mirror of
https://github.com/XAMPPRocky/tokei
synced 2024-10-30 07:11:48 +00:00
moved functions to fsutil, and switched from RefCell to an Enum based system
This commit is contained in:
parent
db2060e0f2
commit
ebee004a8f
4 changed files with 536 additions and 337 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -1,6 +1,6 @@
|
||||||
[root]
|
[root]
|
||||||
name = "tokei"
|
name = "tokei"
|
||||||
version = "1.5.1"
|
version = "1.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"glob 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"glob 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
226
src/fsutil.rs
226
src/fsutil.rs
|
@ -2,6 +2,21 @@
|
||||||
// Use of this source code is governed by the MIT license that can be
|
// Use of this source code is governed by the MIT license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::io::{self, BufRead, BufReader, Read, Write};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::sync::mpsc::channel;
|
||||||
|
use clap::App;
|
||||||
|
use glob::glob;
|
||||||
|
use walkdir::{WalkDir, WalkDirIterator};
|
||||||
|
|
||||||
|
use language::{Language, LanguageName};
|
||||||
|
use language::LanguageName::*;
|
||||||
|
|
||||||
pub fn contains_comments(file: &str, comment: &str, comment_end: &str) -> bool {
|
pub fn contains_comments(file: &str, comment: &str, comment_end: &str) -> bool {
|
||||||
let mut in_comments: usize = 0;
|
let mut in_comments: usize = 0;
|
||||||
'window: for chars in file.chars().collect::<Vec<char>>().windows(comment.len()) {
|
'window: for chars in file.chars().collect::<Vec<char>>().windows(comment.len()) {
|
||||||
|
@ -26,6 +41,197 @@ pub fn contains_comments(file: &str, comment: &str, comment_end: &str) -> bool {
|
||||||
in_comments != 0
|
in_comments != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_all_files<'a, I: Iterator<Item = &'a str>>(paths: I,
|
||||||
|
languages: &mut BTreeMap<LanguageName,
|
||||||
|
Language>,
|
||||||
|
ignored_directories: Vec<&str>) {
|
||||||
|
for path in paths {
|
||||||
|
if let Err(_) = Path::new(path).metadata() {
|
||||||
|
if let Ok(paths) = glob(path) {
|
||||||
|
for path in paths {
|
||||||
|
let path = unwrap_rs_cont!(path);
|
||||||
|
let mut language = if unwrap_opt_cont!(path.to_str()).contains("Makefile") {
|
||||||
|
languages.get_mut(&Makefile).unwrap()
|
||||||
|
} else {
|
||||||
|
unwrap_opt_cont!(languages.get_mut(&unwrap_opt_cont!(get_language(&path))))
|
||||||
|
};
|
||||||
|
|
||||||
|
language.files.push(path.to_owned());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let walker = WalkDir::new(path).into_iter().filter_entry(|entry| {
|
||||||
|
for ig in ignored_directories.to_owned() {
|
||||||
|
if entry.path().to_str().unwrap().contains(&*ig) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
});
|
||||||
|
|
||||||
|
for entry in walker {
|
||||||
|
let entry = unwrap_rs_cont!(entry);
|
||||||
|
|
||||||
|
let mut language = if unwrap_opt_cont!(entry.path().to_str())
|
||||||
|
.contains("Makefile") {
|
||||||
|
languages.get_mut(&Makefile).unwrap()
|
||||||
|
} else {
|
||||||
|
unwrap_opt_cont!(languages.get_mut(&unwrap_opt_cont!(get_language(entry.path()))))
|
||||||
|
};
|
||||||
|
|
||||||
|
language.files.push(entry.path().to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_extension<P: AsRef<Path>>(path: P) -> Option<String> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
let extension = match path.extension() {
|
||||||
|
Some(extension_os) => {
|
||||||
|
match extension_os.to_str() {
|
||||||
|
Some(ext) => ext,
|
||||||
|
None => return None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
match get_filetype_from_shebang(path) {
|
||||||
|
Some(ext) => ext,
|
||||||
|
None => return None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(extension.to_lowercase())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_filetype_from_shebang<P: AsRef<Path>>(file: P) -> Option<&'static str> {
|
||||||
|
let file = match File::open(file) {
|
||||||
|
Ok(file) => file,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
let mut buf = BufReader::new(file);
|
||||||
|
let mut line = String::new();
|
||||||
|
let _ = buf.read_line(&mut line);
|
||||||
|
|
||||||
|
let mut words = line.split_whitespace();
|
||||||
|
match words.next() {
|
||||||
|
Some("#!/bin/sh") => Some("sh"),
|
||||||
|
Some("#!/bin/csh") => Some("csh"),
|
||||||
|
Some("#!/usr/bin/perl") => Some("pl"),
|
||||||
|
Some("#!/usr/bin/env") => {
|
||||||
|
match words.next() {
|
||||||
|
Some("python") | Some("python2") | Some("python3") => Some("py"),
|
||||||
|
Some("sh") => Some("sh"),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_language<P: AsRef<Path>>(entry: P) -> Option<LanguageName> {
|
||||||
|
if let Some(extension) = get_extension(entry) {
|
||||||
|
match &*extension {
|
||||||
|
"as" => Some(ActionScript),
|
||||||
|
"s" => Some(Assembly),
|
||||||
|
"bat" => Some(Batch),
|
||||||
|
"btm" => Some(Batch),
|
||||||
|
"cmd" => Some(Batch),
|
||||||
|
"bash" => Some(Bash),
|
||||||
|
"sh" => Some(Bash),
|
||||||
|
"c" => Some(C),
|
||||||
|
"csh" => Some(CShell),
|
||||||
|
"ec" => Some(C),
|
||||||
|
"pgc" => Some(C),
|
||||||
|
"cs" => Some(CSharp),
|
||||||
|
"clj" => Some(Clojure),
|
||||||
|
"coffee" => Some(CoffeeScript),
|
||||||
|
"cfm" => Some(ColdFusion),
|
||||||
|
"cfc" => Some(ColdFusionScript),
|
||||||
|
"cc" => Some(Cpp),
|
||||||
|
"cpp" => Some(Cpp),
|
||||||
|
"cxx" => Some(Cpp),
|
||||||
|
"pcc" => Some(Cpp),
|
||||||
|
"c++" => Some(Cpp),
|
||||||
|
"css" => Some(Css),
|
||||||
|
"d" => Some(D),
|
||||||
|
"dart" => Some(Dart),
|
||||||
|
"dts" => Some(DeviceTree),
|
||||||
|
"dtsi" => Some(DeviceTree),
|
||||||
|
"el" => Some(Lisp),
|
||||||
|
"lisp" => Some(Lisp),
|
||||||
|
"lsp" => Some(Lisp),
|
||||||
|
"lua" => Some(Lua),
|
||||||
|
"sc" => Some(Lisp),
|
||||||
|
"f" => Some(FortranLegacy),
|
||||||
|
"f77" => Some(FortranLegacy),
|
||||||
|
"for" => Some(FortranLegacy),
|
||||||
|
"ftn" => Some(FortranLegacy),
|
||||||
|
"pfo" => Some(FortranLegacy),
|
||||||
|
"f90" => Some(FortranModern),
|
||||||
|
"f95" => Some(FortranModern),
|
||||||
|
"f03" => Some(FortranModern),
|
||||||
|
"f08" => Some(FortranModern),
|
||||||
|
"go" => Some(Go),
|
||||||
|
"h" => Some(CHeader),
|
||||||
|
"hs" => Some(Haskell),
|
||||||
|
"hpp" => Some(CppHeader),
|
||||||
|
"hh" => Some(CppHeader),
|
||||||
|
"html" => Some(Html),
|
||||||
|
"hxx" => Some(CppHeader),
|
||||||
|
"jai" => Some(Jai),
|
||||||
|
"java" => Some(Java),
|
||||||
|
"js" => Some(JavaScript),
|
||||||
|
"jl" => Some(Julia),
|
||||||
|
"json" => Some(Json),
|
||||||
|
"jsx" => Some(Jsx),
|
||||||
|
"lds" => Some(LinkerScript),
|
||||||
|
"less" => Some(Less),
|
||||||
|
"m" => Some(ObjectiveC),
|
||||||
|
"md" => Some(Markdown),
|
||||||
|
"markdown" => Some(Markdown),
|
||||||
|
"ml" => Some(OCaml),
|
||||||
|
"mli" => Some(OCaml),
|
||||||
|
"mm" => Some(ObjectiveCpp),
|
||||||
|
"makefile" => Some(Makefile),
|
||||||
|
"mustache" => Some(Mustache),
|
||||||
|
"php" => Some(Php),
|
||||||
|
"pas" => Some(Pascal),
|
||||||
|
"pl" => Some(Perl),
|
||||||
|
"text" => Some(Text),
|
||||||
|
"txt" => Some(Text),
|
||||||
|
"polly" => Some(Polly),
|
||||||
|
"proto" => Some(Protobuf),
|
||||||
|
"py" => Some(Python),
|
||||||
|
"r" => Some(R),
|
||||||
|
"rake" => Some(Ruby),
|
||||||
|
"rb" => Some(Ruby),
|
||||||
|
"rhtml" => Some(RubyHtml),
|
||||||
|
"rs" => Some(Rust),
|
||||||
|
"sass" => Some(Sass),
|
||||||
|
"scss" => Some(Sass),
|
||||||
|
"scala" => Some(Scala),
|
||||||
|
"sml" => Some(Sml),
|
||||||
|
"sql" => Some(Sql),
|
||||||
|
"swift" => Some(Swift),
|
||||||
|
"tex" => Some(Tex),
|
||||||
|
"sty" => Some(Tex),
|
||||||
|
"toml" => Some(Toml),
|
||||||
|
"ts" => Some(TypeScript),
|
||||||
|
"vim" => Some(VimScript),
|
||||||
|
"xml" => Some(Xml),
|
||||||
|
"yaml" => Some(Yaml),
|
||||||
|
"yml" => Some(Yaml),
|
||||||
|
"zsh" => Some(Zsh),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code, unused_imports)]
|
#[allow(dead_code, unused_imports)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -48,4 +254,24 @@ mod tests {
|
||||||
fn comment_start_in_line() {
|
fn comment_start_in_line() {
|
||||||
assert!(contains_comments("Hello /* World", "/*", "*/"));
|
assert!(contains_comments("Hello /* World", "/*", "*/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn comment_start_in_quotes_ocaml() {
|
||||||
|
assert!(contains_comments("Hello \"(*\" World", "(*", "*)"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn both_comments_in_quotes_ocaml() {
|
||||||
|
assert!(!contains_comments("Hello \"(**)\" World", "(*", "*)"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn both_comments_in_line_ocaml() {
|
||||||
|
assert!(!contains_comments("Hello (**) World", "(*", "*)"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn comment_start_in_line_ocaml() {
|
||||||
|
assert!(contains_comments("Hello (* World", "(*", "*)"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
236
src/language.rs
236
src/language.rs
|
@ -7,90 +7,80 @@ use std::fmt;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::ops::AddAssign;
|
use std::ops::AddAssign;
|
||||||
use stats::Stats;
|
use stats::Stats;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default, Clone, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
pub struct Language<'a> {
|
pub struct Language {
|
||||||
pub name: &'a str,
|
pub line_comment: &'static str,
|
||||||
pub line_comment: &'a str,
|
pub multi_line: &'static str,
|
||||||
pub multi_line: &'a str,
|
pub multi_line_end: &'static str,
|
||||||
pub multi_line_end: &'a str,
|
|
||||||
pub files: Vec<PathBuf>,
|
pub files: Vec<PathBuf>,
|
||||||
pub code: usize,
|
pub code: usize,
|
||||||
pub comments: usize,
|
pub comments: usize,
|
||||||
pub blanks: usize,
|
pub blanks: usize,
|
||||||
pub lines: usize,
|
pub lines: usize,
|
||||||
pub total: usize,
|
pub total: usize,
|
||||||
pub printed: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Language {
|
||||||
|
pub fn new(line_comment: &'static str,
|
||||||
|
multi_line: &'static str,
|
||||||
|
multi_line_end: &'static str)
|
||||||
|
-> Self {
|
||||||
|
|
||||||
impl<'a> Language<'a> {
|
Language {
|
||||||
pub fn new(name: &'a str,
|
|
||||||
line_comment: &'a str,
|
|
||||||
multi_line: &'a str,
|
|
||||||
multi_line_end: &'a str)
|
|
||||||
-> RefCell<Self> {
|
|
||||||
|
|
||||||
RefCell::new(Language {
|
|
||||||
name: name,
|
|
||||||
line_comment: line_comment,
|
line_comment: line_comment,
|
||||||
multi_line: multi_line,
|
multi_line: multi_line,
|
||||||
multi_line_end: multi_line_end,
|
multi_line_end: multi_line_end,
|
||||||
..Self::default()
|
..Self::default()
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_raw(name: &'a str) -> Self {
|
pub fn new_c() -> Self {
|
||||||
Language { name: name, ..Self::default() }
|
Language {
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_c(name: &'a str) -> RefCell<Self> {
|
|
||||||
RefCell::new(Language {
|
|
||||||
name: name,
|
|
||||||
line_comment: "//",
|
line_comment: "//",
|
||||||
multi_line: "/*",
|
multi_line: "/*",
|
||||||
multi_line_end: "*/",
|
multi_line_end: "*/",
|
||||||
..Self::default()
|
..Self::default()
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_html(name: &'a str) -> RefCell<Self> {
|
pub fn new_html() -> Self {
|
||||||
RefCell::new(Language {
|
Language {
|
||||||
name: name,
|
|
||||||
line_comment: "<!--",
|
line_comment: "<!--",
|
||||||
multi_line: "<!--",
|
multi_line: "<!--",
|
||||||
multi_line_end: "-->",
|
multi_line_end: "-->",
|
||||||
..Self::default()
|
..Self::default()
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_blank(name: &'a str) -> RefCell<Self> {
|
pub fn new_blank() -> Self {
|
||||||
RefCell::new(Language { name: name, ..Self::default() })
|
Language { ..Self::default() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_single(name: &'a str, line_comment: &'a str) -> RefCell<Self> {
|
pub fn new_single(line_comment: &'static str) -> Self {
|
||||||
RefCell::new(Language {
|
Language { line_comment: line_comment, ..Self::default() }
|
||||||
name: name,
|
|
||||||
line_comment: line_comment,
|
|
||||||
..Self::default()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_multi(name: &'a str, multi_line: &'a str, multi_line_end: &'a str) -> RefCell<Self> {
|
pub fn new_multi(multi_line: &'static str, multi_line_end: &'static str) -> Self {
|
||||||
RefCell::new(Language {
|
Language {
|
||||||
name: name,
|
|
||||||
multi_line: multi_line,
|
multi_line: multi_line,
|
||||||
multi_line_end: multi_line_end,
|
multi_line_end: multi_line_end,
|
||||||
..Self::default()
|
..Self::default()
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.code == 0 && self.comments == 0 && self.blanks == 0 && self.lines == 0
|
self.code == 0 && self.comments == 0 && self.blanks == 0 && self.lines == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_blank(&self) -> bool {
|
||||||
|
self.line_comment == "" && self.multi_line == ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Display for Language<'a> {
|
impl fmt::Display for Language {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let total = if self.total == 0 {
|
let total = if self.total == 0 {
|
||||||
self.files.len()
|
self.files.len()
|
||||||
|
@ -99,7 +89,7 @@ impl<'a> fmt::Display for Language<'a> {
|
||||||
};
|
};
|
||||||
write!(f,
|
write!(f,
|
||||||
" {: <18} {: >6} {:>12} {:>12} {:>12} {:>12}",
|
" {: <18} {: >6} {:>12} {:>12} {:>12} {:>12}",
|
||||||
self.name,
|
"CHANGE",
|
||||||
total,
|
total,
|
||||||
self.lines,
|
self.lines,
|
||||||
self.blanks,
|
self.blanks,
|
||||||
|
@ -107,8 +97,9 @@ impl<'a> fmt::Display for Language<'a> {
|
||||||
self.code)
|
self.code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adding languages to the raw total.
|
// Adding languages to the raw total.
|
||||||
impl<'a, 'b> AddAssign<&'b Language<'a>> for Language<'a> {
|
impl<'a> AddAssign<&'a Language> for Language {
|
||||||
fn add_assign(&mut self, rhs: &Self) {
|
fn add_assign(&mut self, rhs: &Self) {
|
||||||
self.total += rhs.files.len();
|
self.total += rhs.files.len();
|
||||||
self.lines += rhs.lines;
|
self.lines += rhs.lines;
|
||||||
|
@ -118,8 +109,19 @@ impl<'a, 'b> AddAssign<&'b Language<'a>> for Language<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adding languages to the raw total.
|
||||||
|
impl<'a> AddAssign<&'a mut Language> for Language {
|
||||||
|
fn add_assign(&mut self, rhs: &mut Self) {
|
||||||
|
self.total += rhs.files.len();
|
||||||
|
self.lines += rhs.lines;
|
||||||
|
self.comments += rhs.comments;
|
||||||
|
self.blanks += rhs.blanks;
|
||||||
|
self.code += rhs.code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Adding a file to the language.
|
// Adding a file to the language.
|
||||||
impl<'a> AddAssign<Stats> for Language<'a> {
|
impl AddAssign<Stats> for Language {
|
||||||
fn add_assign(&mut self, rhs: Stats) {
|
fn add_assign(&mut self, rhs: Stats) {
|
||||||
self.lines += rhs.lines;
|
self.lines += rhs.lines;
|
||||||
self.code += rhs.code;
|
self.code += rhs.code;
|
||||||
|
@ -127,3 +129,147 @@ impl<'a> AddAssign<Stats> for Language<'a> {
|
||||||
self.blanks += rhs.blanks;
|
self.blanks += rhs.blanks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
|
pub enum LanguageName {
|
||||||
|
ActionScript,
|
||||||
|
Assembly,
|
||||||
|
Bash,
|
||||||
|
Batch,
|
||||||
|
C,
|
||||||
|
CHeader,
|
||||||
|
CSharp,
|
||||||
|
CShell,
|
||||||
|
Clojure,
|
||||||
|
CoffeeScript,
|
||||||
|
ColdFusion,
|
||||||
|
ColdFusionScript,
|
||||||
|
Cpp,
|
||||||
|
CppHeader,
|
||||||
|
Css,
|
||||||
|
D,
|
||||||
|
Dart,
|
||||||
|
DeviceTree,
|
||||||
|
Lisp,
|
||||||
|
FortranLegacy,
|
||||||
|
FortranModern,
|
||||||
|
Go,
|
||||||
|
Haskell,
|
||||||
|
Html,
|
||||||
|
Jai,
|
||||||
|
Java,
|
||||||
|
JavaScript,
|
||||||
|
Julia,
|
||||||
|
Json,
|
||||||
|
Jsx,
|
||||||
|
Less,
|
||||||
|
LinkerScript,
|
||||||
|
Lua,
|
||||||
|
Makefile,
|
||||||
|
Markdown,
|
||||||
|
Mustache,
|
||||||
|
ObjectiveC,
|
||||||
|
ObjectiveCpp,
|
||||||
|
OCaml,
|
||||||
|
Php,
|
||||||
|
Pascal,
|
||||||
|
Polly,
|
||||||
|
Perl,
|
||||||
|
Protobuf,
|
||||||
|
Python,
|
||||||
|
R,
|
||||||
|
Ruby,
|
||||||
|
RubyHtml,
|
||||||
|
Rust,
|
||||||
|
Sass,
|
||||||
|
Scala,
|
||||||
|
Sml,
|
||||||
|
Sql,
|
||||||
|
Swift,
|
||||||
|
Tex,
|
||||||
|
Text,
|
||||||
|
Toml,
|
||||||
|
TypeScript,
|
||||||
|
VimScript,
|
||||||
|
Xml,
|
||||||
|
Yaml,
|
||||||
|
Zsh,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LanguageName {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
use self::LanguageName::*;
|
||||||
|
|
||||||
|
match *self {
|
||||||
|
ActionScript => "ActionScript",
|
||||||
|
Assembly => "Assembly",
|
||||||
|
Bash => "BASH",
|
||||||
|
Batch => "Batch",
|
||||||
|
C => "C",
|
||||||
|
CHeader => "C Header",
|
||||||
|
CSharp => "C#",
|
||||||
|
CShell => "C Shell",
|
||||||
|
Clojure => "Clojure",
|
||||||
|
CoffeeScript => "CoffeeScript",
|
||||||
|
ColdFusion => "ColdFusion",
|
||||||
|
ColdFusionScript => "ColdFusion CFScript",
|
||||||
|
Cpp => "C++",
|
||||||
|
CppHeader => "C++ Header",
|
||||||
|
Css => "CSS",
|
||||||
|
D => "D",
|
||||||
|
Dart => "Dart",
|
||||||
|
DeviceTree => "Device Tree",
|
||||||
|
Lisp => "LISP",
|
||||||
|
FortranLegacy => "FORTRAN Legacy",
|
||||||
|
FortranModern => "FORTRAN Modern",
|
||||||
|
Go => "Go",
|
||||||
|
Haskell => "Haskell",
|
||||||
|
Html => "HTML",
|
||||||
|
Jai => "JAI",
|
||||||
|
Java => "Java",
|
||||||
|
JavaScript => "JavaScript",
|
||||||
|
Julia => "Julia",
|
||||||
|
Json => "JSON",
|
||||||
|
Jsx => "JSX",
|
||||||
|
Less => "LESS",
|
||||||
|
LinkerScript => "LD Script",
|
||||||
|
Lua => "Lua",
|
||||||
|
Makefile => "Makefile",
|
||||||
|
Markdown => "Markdown",
|
||||||
|
Mustache => "Mustache",
|
||||||
|
ObjectiveC => "Objective C",
|
||||||
|
ObjectiveCpp => "Objective C++",
|
||||||
|
OCaml => "OCaml",
|
||||||
|
Php => "PHP",
|
||||||
|
Pascal => "Pascal",
|
||||||
|
Polly => "Polly",
|
||||||
|
Perl => "Perl",
|
||||||
|
Protobuf => "Protocol Buffers",
|
||||||
|
Python => "Python",
|
||||||
|
R => "R",
|
||||||
|
Ruby => "Ruby",
|
||||||
|
RubyHtml => "Ruby HTML",
|
||||||
|
Rust => "Rust",
|
||||||
|
Sass => "Sass",
|
||||||
|
Scala => "Scala",
|
||||||
|
Sml => "Standard ML",
|
||||||
|
Sql => "SQL",
|
||||||
|
Swift => "Swift",
|
||||||
|
Tex => "TeX",
|
||||||
|
Text => "Plain Text",
|
||||||
|
Toml => "TOML",
|
||||||
|
TypeScript => "TypeScript",
|
||||||
|
VimScript => "Vim Script",
|
||||||
|
Xml => "XML",
|
||||||
|
Yaml => "YAML",
|
||||||
|
Zsh => "Zsh",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for LanguageName {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
409
src/main.rs
409
src/main.rs
|
@ -16,17 +16,21 @@ pub mod stats;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::io::{BufRead, BufReader, Read};
|
use std::io::{self, BufRead, BufReader, Read, Write};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::sync::mpsc::channel;
|
||||||
|
|
||||||
use clap::App;
|
use clap::App;
|
||||||
use glob::glob;
|
use glob::glob;
|
||||||
use walkdir::{WalkDir, WalkDirIterator};
|
use walkdir::{WalkDir, WalkDirIterator};
|
||||||
|
|
||||||
use language::Language;
|
use fsutil::*;
|
||||||
|
use language::{Language, LanguageName};
|
||||||
|
use language::LanguageName::*;
|
||||||
|
|
||||||
use fsutil::contains_comments;
|
|
||||||
const ROW: &'static str = "-----------------------------------------------------------------------\
|
const ROW: &'static str = "-----------------------------------------------------------------------\
|
||||||
--------";
|
--------";
|
||||||
const BLANKS: &'static str = "blanks";
|
const BLANKS: &'static str = "blanks";
|
||||||
|
@ -39,170 +43,78 @@ fn main() {
|
||||||
let yaml = load_yaml!("../cli.yml");
|
let yaml = load_yaml!("../cli.yml");
|
||||||
let matches = App::from_yaml(yaml).get_matches();
|
let matches = App::from_yaml(yaml).get_matches();
|
||||||
|
|
||||||
let action_script = Language::new_c("ActionScript");
|
let files_option = matches.is_present(FILES);
|
||||||
let asm = Language::new_single("Assembly", ";");
|
let language_option = matches.is_present("languages");
|
||||||
let bash = Language::new_single("BASH", "#");
|
|
||||||
let batch = Language::new_single("Batch", "REM");
|
|
||||||
let c = Language::new_c("C");
|
|
||||||
let c_header = Language::new_c("C Header");
|
|
||||||
let c_sharp = Language::new_c("C#");
|
|
||||||
let c_shell = Language::new_single("C Shell", "#");
|
|
||||||
let clojure = Language::new_single("Clojure", ";,#,#_");
|
|
||||||
let coffee_script = Language::new("CoffeeScript", "#", "###", "###");
|
|
||||||
let cold_fusion = Language::new_multi("ColdFusion", "<!---", "--->");
|
|
||||||
let cf_script = Language::new_c("ColdFusion CFScript");
|
|
||||||
let cpp = Language::new_c("C++");
|
|
||||||
let cpp_header = Language::new_c("C++ Header");
|
|
||||||
let css = Language::new_c("CSS");
|
|
||||||
let d = Language::new_c("D");
|
|
||||||
let dart = Language::new_c("Dart");
|
|
||||||
let device_tree = Language::new_c("Device Tree");
|
|
||||||
let lisp = Language::new("LISP", ";", "#|", "|#");
|
|
||||||
let fortran_legacy = Language::new_single("FORTRAN Legacy", "c,C,!,*");
|
|
||||||
let fortran_modern = Language::new_single("FORTRAN Modern", "!");
|
|
||||||
let go = Language::new_c("Go");
|
|
||||||
let haskell = Language::new_single("Haskell", "--");
|
|
||||||
let html = Language::new_html("HTML");
|
|
||||||
let jai = Language::new_c("JAI");
|
|
||||||
let java = Language::new_c("Java");
|
|
||||||
let java_script = Language::new_c("JavaScript");
|
|
||||||
let julia = Language::new("Julia", "#", "#=", "=#");
|
|
||||||
let json = Language::new_blank("JSON");
|
|
||||||
let jsx = Language::new_c("JSX");
|
|
||||||
let less = Language::new_c("LESS");
|
|
||||||
let linker_script = Language::new_c("LD Script");
|
|
||||||
let lua = Language::new("Lua", "--", "--[[", "]]");
|
|
||||||
let makefile = Language::new_single("Makefile", "#");
|
|
||||||
let markdown = Language::new_blank("Markdown");
|
|
||||||
let mustache = Language::new_multi("Mustache", "{{!", "}}");
|
|
||||||
let objective_c = Language::new_c("Objective C");
|
|
||||||
let objective_cpp = Language::new_c("Objective C++");
|
|
||||||
let ocaml = Language::new_multi("OCaml", "(*", "*)");
|
|
||||||
let php = Language::new("PHP", "#,//", "/*", "*/");
|
|
||||||
let pascal = Language::new("Pascal", "//,(*", "{", "}");
|
|
||||||
let polly = Language::new_html("Polly");
|
|
||||||
let perl = Language::new("Perl", "#", "=", "=cut");
|
|
||||||
let protobuf = Language::new_single("Protocol Buffers", "//");
|
|
||||||
let python = Language::new("Python", "#", "'''", "'''");
|
|
||||||
let r = Language::new_single("R", "#");
|
|
||||||
let ruby = Language::new("Ruby", "#", "=begin", "=end");
|
|
||||||
let ruby_html = Language::new_html("Ruby HTML");
|
|
||||||
let rust = Language::new("Rust", "//,///,//!", "/*", "*/");
|
|
||||||
let sass = Language::new_c("Sass");
|
|
||||||
let sml = Language::new_multi("Standard ML", "(*", "*)");
|
|
||||||
let sql = Language::new("SQL", "--", "/*", "*/");
|
|
||||||
let swift = Language::new_c("Swift");
|
|
||||||
let tex = Language::new_single("TeX", "%");
|
|
||||||
let text = Language::new_blank("Plain Text");
|
|
||||||
let toml = Language::new_single("TOML", "#");
|
|
||||||
let type_script = Language::new_c("TypeScript");
|
|
||||||
let vim_script = Language::new_single("Vim script", "\"");
|
|
||||||
let xml = Language::new_html("XML");
|
|
||||||
let yaml = Language::new_single("YAML", "#");
|
|
||||||
let zsh = Language::new_single("Zsh", "#");
|
|
||||||
|
|
||||||
// Languages are placed inside a BTreeMap, in order to print alphabetically by default
|
// Languages are placed inside a BTreeMap, in order to print alphabetically by default
|
||||||
let languages = btreemap! {
|
let mut languages = btreemap! {
|
||||||
"as" => &action_script,
|
ActionScript => Language::new_c(),
|
||||||
"s" => &asm,
|
Assembly => Language::new_single(";"),
|
||||||
"bat" => &batch,
|
Bash => Language::new_single("#"),
|
||||||
"btm" => &batch,
|
Batch => Language::new_single("REM"),
|
||||||
"cmd" => &batch,
|
C => Language::new_c(),
|
||||||
"bash" => &bash,
|
CHeader => Language::new_c(),
|
||||||
"sh" => &bash,
|
CSharp => Language::new_c(),
|
||||||
"c" => &c,
|
CShell => Language::new_single("#"),
|
||||||
"csh" => &c_shell,
|
Clojure => Language::new_single(";,#,#_"),
|
||||||
"ec" => &c,
|
CoffeeScript => Language::new("#", "###", "###"),
|
||||||
"pgc" => &c,
|
ColdFusion => Language::new_multi("<!---", "--->"),
|
||||||
"cs" => &c_sharp,
|
ColdFusionScript => Language::new_c(),
|
||||||
"clj" => &clojure,
|
Cpp => Language::new_c(),
|
||||||
"coffee" => &coffee_script,
|
CppHeader => Language::new_c(),
|
||||||
"cfm" => &cold_fusion,
|
Css => Language::new_c(),
|
||||||
"cfc" => &cf_script,
|
D => Language::new_c(),
|
||||||
"cc" => &cpp,
|
Dart => Language::new_c(),
|
||||||
"cpp" => &cpp,
|
DeviceTree => Language::new_c(),
|
||||||
"cxx" => &cpp,
|
Lisp => Language::new(";", "#|", "|#"),
|
||||||
"pcc" => &cpp,
|
FortranLegacy => Language::new_single("c,C,!,*"),
|
||||||
"c++" => &cpp,
|
FortranModern => Language::new_single("!"),
|
||||||
"css" => &css,
|
Go => Language::new_c(),
|
||||||
"d" => &d,
|
Haskell => Language::new_single("--"),
|
||||||
"dart" => &dart,
|
Html => Language::new_html(),
|
||||||
"dts" => &device_tree,
|
Jai => Language::new_c(),
|
||||||
"dtsi" => &device_tree,
|
Java => Language::new_c(),
|
||||||
"el" => &lisp,
|
JavaScript => Language::new_c(),
|
||||||
"lisp" => &lisp,
|
Julia => Language::new("#", "#=", "=#"),
|
||||||
"lsp" => &lisp,
|
Json => Language::new_blank(),
|
||||||
"lua" => &lua,
|
Jsx => Language::new_c(),
|
||||||
"sc" => &lisp,
|
Less => Language::new_c(),
|
||||||
"f" => &fortran_legacy,
|
LinkerScript => Language::new_c(),
|
||||||
"f77" => &fortran_legacy,
|
Lua => Language::new("--", "--[[", "]]"),
|
||||||
"for" => &fortran_legacy,
|
Makefile => Language::new_single("#"),
|
||||||
"ftn" => &fortran_legacy,
|
Markdown => Language::new_blank(),
|
||||||
"pfo" => &fortran_legacy,
|
Mustache => Language::new_multi("{{!", "}}"),
|
||||||
"f90" => &fortran_modern,
|
ObjectiveC => Language::new_c(),
|
||||||
"f95" => &fortran_modern,
|
ObjectiveCpp => Language::new_c(),
|
||||||
"f03" => &fortran_modern,
|
OCaml => Language::new_multi("(*", "*)"),
|
||||||
"f08" => &fortran_modern,
|
Php => Language::new("#,//", "/*", "*/"),
|
||||||
"go" => &go,
|
Pascal => Language::new("//,(*", "{", "}"),
|
||||||
"h" => &c_header,
|
Polly => Language::new_html(),
|
||||||
"hs" => &haskell,
|
Perl => Language::new("#", "=", "=cut"),
|
||||||
"hpp" => &cpp_header,
|
Protobuf => Language::new_single("//"),
|
||||||
"hh" => &cpp_header,
|
Python => Language::new("#", "'''", "'''"),
|
||||||
"html" => &html,
|
R => Language::new_single("#"),
|
||||||
"hxx" => &cpp_header,
|
Ruby => Language::new("#", "=begin", "=end"),
|
||||||
"jai" => &jai,
|
RubyHtml => Language::new_html(),
|
||||||
"java" => &java,
|
Rust => Language::new("//,///,//!", "/*", "*/"),
|
||||||
"js" => &java_script,
|
Sass => Language::new_c(),
|
||||||
"jl" => &julia,
|
Sml => Language::new_multi("(*", "*)"),
|
||||||
"json" => &json,
|
Sql => Language::new("--", "/*", "*/"),
|
||||||
"jsx" => &jsx,
|
Swift => Language::new_c(),
|
||||||
"lds" => &linker_script,
|
Tex => Language::new_single("%"),
|
||||||
"less" => &less,
|
Text => Language::new_blank(),
|
||||||
"m" => &objective_c,
|
Toml => Language::new_single("#"),
|
||||||
"md" => &markdown,
|
TypeScript => Language::new_c(),
|
||||||
"markdown" => &markdown,
|
VimScript => Language::new_single("\""),
|
||||||
"ml" => &ocaml,
|
Xml => Language::new_html(),
|
||||||
"mli" => &ocaml,
|
Yaml => Language::new_single("#"),
|
||||||
"mm" => &objective_cpp,
|
Zsh => Language::new_single("#"),
|
||||||
"makefile" => &makefile,
|
|
||||||
"mustache" => &mustache,
|
|
||||||
"php" => &php,
|
|
||||||
"pas" => &pascal,
|
|
||||||
"pl" => &perl,
|
|
||||||
"text" => &text,
|
|
||||||
"txt" => &text,
|
|
||||||
"polly" => &polly,
|
|
||||||
"proto" => &protobuf,
|
|
||||||
"py" => &python,
|
|
||||||
"r" => &r,
|
|
||||||
"rake" => &ruby,
|
|
||||||
"rb" => &ruby,
|
|
||||||
"rhtml" => &ruby_html,
|
|
||||||
"rs" => &rust,
|
|
||||||
"sass" => &sass,
|
|
||||||
"scss" => &sass,
|
|
||||||
"sml" => &sml,
|
|
||||||
"sql" => &sql,
|
|
||||||
"swift" => &swift,
|
|
||||||
"tex" => &tex,
|
|
||||||
"sty" => &tex,
|
|
||||||
"toml" => &toml,
|
|
||||||
"ts" => &type_script,
|
|
||||||
"vim" => &vim_script,
|
|
||||||
"xml" => &xml,
|
|
||||||
"yaml" => &yaml,
|
|
||||||
"yml" => &yaml,
|
|
||||||
"zsh" => &zsh,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Print every supported language.
|
// Print every supported language.
|
||||||
if matches.is_present("languages") {
|
if language_option {
|
||||||
for language in languages.values() {
|
for key in languages.keys() {
|
||||||
let mut language = language.borrow_mut();
|
println!("{:<25}", key);
|
||||||
if !language.printed {
|
|
||||||
println!("{:<25}", language.name);
|
|
||||||
language.printed = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -210,10 +122,10 @@ fn main() {
|
||||||
let paths = matches.values_of("input").unwrap();
|
let paths = matches.values_of("input").unwrap();
|
||||||
|
|
||||||
let ignored_directories = {
|
let ignored_directories = {
|
||||||
let mut ignored_directories = vec![String::from(".git")];
|
let mut ignored_directories = vec![".git"];
|
||||||
if let Some(user_ignored) = matches.values_of("exclude") {
|
if let Some(user_ignored) = matches.values_of("exclude") {
|
||||||
for ignored in user_ignored {
|
for ignored in user_ignored {
|
||||||
ignored_directories.push(ignored.to_owned());
|
ignored_directories.push(ignored);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ignored_directories
|
ignored_directories
|
||||||
|
@ -238,25 +150,35 @@ fn main() {
|
||||||
"Code");
|
"Code");
|
||||||
println!("{}", ROW);
|
println!("{}", ROW);
|
||||||
|
|
||||||
get_all_files(paths, &languages, ignored_directories);
|
get_all_files(paths, &mut languages, ignored_directories);
|
||||||
|
|
||||||
let mut total = Language::new_raw("Total");
|
let mut total = Language::new_blank();
|
||||||
for language_ref in languages.values() {
|
for (name, language) in &mut languages {
|
||||||
let mut language = language_ref.borrow_mut();
|
|
||||||
|
|
||||||
if language.printed {
|
if language.files.len() == 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let is_blank_lang = if language.line_comment == "" && language.multi_line == "" {
|
|
||||||
true
|
let (tx, rx) = channel();
|
||||||
} else {
|
let child = thread::spawn(move || {
|
||||||
false
|
loop {
|
||||||
};
|
if let Ok(_) = rx.try_recv() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// print!("\x1B[?25l;");
|
||||||
|
print!(" Counting {} files. \r", name);
|
||||||
|
thread::sleep(Duration::from_millis(4));
|
||||||
|
print!(" Counting {} files..\r", name);
|
||||||
|
thread::sleep(Duration::from_millis(4));
|
||||||
|
print!(" Counting {} files...\r", name);
|
||||||
|
thread::sleep(Duration::from_millis(4));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let files = language.files.clone();
|
let files = language.files.clone();
|
||||||
for file in files {
|
for file in files {
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
let is_fortran = language.name.contains("FORTRAN");
|
let is_fortran = *name == FortranModern || *name == FortranLegacy;
|
||||||
let mut stats = stats::Stats::new(unwrap_opt_cont!(file.to_str()));
|
let mut stats = stats::Stats::new(unwrap_opt_cont!(file.to_str()));
|
||||||
let _ = unwrap_rs_cont!(unwrap_rs_cont!(File::open(file))
|
let _ = unwrap_rs_cont!(unwrap_rs_cont!(File::open(file))
|
||||||
.read_to_string(&mut contents));
|
.read_to_string(&mut contents));
|
||||||
|
@ -265,7 +187,7 @@ fn main() {
|
||||||
let lines = contents.lines();
|
let lines = contents.lines();
|
||||||
|
|
||||||
|
|
||||||
if is_blank_lang {
|
if language.is_blank() {
|
||||||
stats.code += lines.count();
|
stats.code += lines.count();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -314,149 +236,54 @@ fn main() {
|
||||||
stats.code += 1;
|
stats.code += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches.is_present(FILES) {
|
if files_option {
|
||||||
println!("{}", stats);
|
println!("{}", stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
*language += stats;
|
*language += stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _ = tx.send(());
|
||||||
|
let _ = child.join();
|
||||||
|
print!(" \r");
|
||||||
if !language.is_empty() {
|
if !language.is_empty() {
|
||||||
language.printed = true;
|
|
||||||
if let None = sort {
|
if let None = sort {
|
||||||
if matches.is_present(FILES) {
|
if files_option {
|
||||||
println!("{}", ROW);
|
println!("{}", ROW);
|
||||||
println!("{}", *language);
|
println!("{}", language);
|
||||||
println!("{}", ROW);
|
println!("{}", ROW);
|
||||||
} else {
|
} else {
|
||||||
println!("{}", *language);
|
println!("{}", language);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
total += &*language;
|
|
||||||
|
total += language;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(sort_category) = sort {
|
if let Some(sort_category) = sort {
|
||||||
let mut unsorted_vec: Vec<(&&str, &&RefCell<Language>)> = languages.iter().collect();
|
let mut sorted: Vec<&Language> = languages.values().collect();
|
||||||
match &*sort_category {
|
match &*sort_category {
|
||||||
BLANKS => unsorted_vec.sort_by(|a, b| b.1.borrow().blanks.cmp(&a.1.borrow().blanks)),
|
BLANKS => sorted.sort_by(|a, b| b.blanks.cmp(&a.blanks)),
|
||||||
COMMENTS => {
|
COMMENTS => sorted.sort_by(|a, b| b.comments.cmp(&a.comments)),
|
||||||
unsorted_vec.sort_by(|a, b| b.1.borrow().comments.cmp(&a.1.borrow().comments))
|
CODE => sorted.sort_by(|a, b| b.code.cmp(&a.code)),
|
||||||
}
|
FILES => sorted.sort_by(|a, b| b.files.len().cmp(&a.files.len())),
|
||||||
CODE => unsorted_vec.sort_by(|a, b| b.1.borrow().code.cmp(&a.1.borrow().code)),
|
TOTAL => sorted.sort_by(|a, b| b.lines.cmp(&a.lines)),
|
||||||
FILES => {
|
|
||||||
unsorted_vec.sort_by(|a, b| b.1.borrow().files.len().cmp(&a.1.borrow().files.len()))
|
|
||||||
}
|
|
||||||
TOTAL => unsorted_vec.sort_by(|a, b| b.1.borrow().lines.cmp(&a.1.borrow().lines)),
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
for (_, language) in unsorted_vec {
|
for language in sorted {
|
||||||
|
if !language.is_empty() {
|
||||||
if !language.borrow().is_empty() && language.borrow().printed {
|
println!("{}", *language);
|
||||||
language.borrow_mut().printed = false;
|
|
||||||
println!("{}", *language.borrow());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !matches.is_present(FILES) {
|
if !files_option {
|
||||||
println!("{}", ROW);
|
println!("{}", ROW);
|
||||||
}
|
}
|
||||||
println!("{}", total);
|
println!("{}", total);
|
||||||
println!("{}", ROW);
|
println!("{}", ROW);
|
||||||
}
|
println!("\x1B[?25h");
|
||||||
|
|
||||||
|
|
||||||
fn get_all_files<'a, I: Iterator<Item = &'a str>>(paths: I,
|
|
||||||
languages: &BTreeMap<&str, &RefCell<Language>>,
|
|
||||||
ignored_directories: Vec<String>) {
|
|
||||||
for path in paths {
|
|
||||||
if let Err(_) = Path::new(path).metadata() {
|
|
||||||
if let Ok(paths) = glob(path) {
|
|
||||||
for path in paths {
|
|
||||||
let path = unwrap_rs_cont!(path);
|
|
||||||
let language = if unwrap_opt_cont!(path.to_str()).contains("Makefile") {
|
|
||||||
languages.get("makefile").unwrap()
|
|
||||||
} else {
|
|
||||||
let extension = unwrap_opt_cont!(get_extension(&path));
|
|
||||||
unwrap_opt_cont!(languages.get(&*extension))
|
|
||||||
};
|
|
||||||
|
|
||||||
language.borrow_mut().files.push(path.to_owned());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let walker = WalkDir::new(path).into_iter().filter_entry(|entry| {
|
|
||||||
for ig in ignored_directories.to_owned() {
|
|
||||||
if entry.path().to_str().unwrap().contains(&*ig) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
});
|
|
||||||
|
|
||||||
for entry in walker {
|
|
||||||
let entry = unwrap_rs_cont!(entry);
|
|
||||||
|
|
||||||
let language = if unwrap_opt_cont!(entry.path().to_str()).contains("Makefile") {
|
|
||||||
languages.get("makefile").unwrap()
|
|
||||||
} else {
|
|
||||||
let extension = unwrap_opt_cont!(get_extension(entry.path()));
|
|
||||||
unwrap_opt_cont!(languages.get(&*extension))
|
|
||||||
};
|
|
||||||
|
|
||||||
language.borrow_mut().files.push(entry.path().to_owned());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn get_filetype_from_shebang<P: AsRef<Path>>(file: P) -> Option<&'static str> {
|
|
||||||
let file = match File::open(file) {
|
|
||||||
Ok(file) => file,
|
|
||||||
_ => return None,
|
|
||||||
};
|
|
||||||
let mut buf = BufReader::new(file);
|
|
||||||
let mut line = String::new();
|
|
||||||
let _ = buf.read_line(&mut line);
|
|
||||||
|
|
||||||
let mut words = line.split_whitespace();
|
|
||||||
match words.next() {
|
|
||||||
Some("#!/bin/sh") => Some("sh"),
|
|
||||||
Some("#!/bin/csh") => Some("csh"),
|
|
||||||
Some("#!/usr/bin/perl") => Some("pl"),
|
|
||||||
Some("#!/usr/bin/env") => {
|
|
||||||
match words.next() {
|
|
||||||
Some("python") | Some("python2") | Some("python3") => Some("py"),
|
|
||||||
Some("sh") => Some("sh"),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_extension<P: AsRef<Path>>(path: P) -> Option<String> {
|
|
||||||
let path = path.as_ref();
|
|
||||||
let extension = match path.extension() {
|
|
||||||
Some(extension_os) => {
|
|
||||||
let extension = match extension_os.to_str() {
|
|
||||||
Some(ext) => ext,
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
extension.to_lowercase()
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
match get_filetype_from_shebang(path) {
|
|
||||||
Some(ext) => String::from(ext).to_lowercase(),
|
|
||||||
None => return None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Some(extension)
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue