diff --git a/Cargo.lock b/Cargo.lock index b3abb07..65120ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,6 +5,7 @@ dependencies = [ "clap 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "maplit 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -34,6 +35,15 @@ name = "glob" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "kernel32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "maplit" version = "0.1.3" @@ -49,6 +59,25 @@ name = "vec_map" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "walkdir" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "yaml-rust" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index bc71d32..ff18154 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ # found in the LICENSE file. [package] name = "tokei" -version = "1.3.1" +version = "1.4.0" authors = ["Aaronepower "] repository = "https://github.com/Aaronepower/tokei.git" homepage = "https://aaronepower.github.io/tokei/" @@ -18,6 +18,7 @@ debug = true opt-level = 3 [dependencies] -clap = {version = "2.0.1", features = ["yaml"]} -maplit = "*" -glob = "0.2.10" \ No newline at end of file +clap = {version = "2.1.1", features = ["yaml"]} +glob = "*" +maplit = "0.1.3" +walkdir = "0.1.5" \ No newline at end of file diff --git a/src/fsutil.rs b/src/fsutil.rs index 86bd1dd..5b6d8ac 100644 --- a/src/fsutil.rs +++ b/src/fsutil.rs @@ -2,12 +2,6 @@ // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. -extern crate glob; - -use std::fs; -use std::fs::metadata; -use self::glob::glob; - pub fn contains_comments(file: &str, comment: &str, comment_end: &str) -> bool { let mut in_comments: usize = 0; 'window: for chars in file.chars().collect::>().windows(comment.len()) { @@ -32,60 +26,6 @@ pub fn contains_comments(file: &str, comment: &str, comment_end: &str) -> bool { in_comments != 0 } -pub fn get_all_files(path: String, ignored_directories: &[String]) -> Vec { - let mut files: Vec = Vec::new(); - - if let Ok(result) = metadata(&path) { - if result.is_dir() { - let dir = match fs::read_dir(&path) { - Ok(val) => val, - Err(_) => return Vec::new(), - }; - 'file: for entry in dir { - let entry = unwrap_rs_cont!(entry); - let file_path = entry.path(); - let file_str = unwrap_opt_cont!(file_path.to_str()); - let file_string = file_str.to_owned(); - let path_metadata = unwrap_rs_cont!(metadata(file_str)); - - for ignored_directory in ignored_directories { - if file_str.contains(ignored_directory) { - continue 'file; - } - } - - if path_metadata.is_dir() { - for file in get_all_files(file_string, ignored_directories) { - files.push(file); - } - } else if path_metadata.is_file() { - files.push(file_string); - } - } - } else { - files.push(path); - } - } else { - let glob = glob(&path); - match glob { - Ok(iter) => { - for path_buf in iter { - let file_path = unwrap_opt_cont!(unwrap_rs_cont!(path_buf).as_path().to_str()) - .to_owned(); - files.push(file_path); - } - } - Err(error) => { - panic!("The path provided wasn't valid. PATH:{:?}, error:{:?}", - path, - error); - } - } - } - - files -} - #[allow(dead_code, unused_imports)] mod tests { use super::*; diff --git a/src/language.rs b/src/language.rs index 9bf9cc4..b7fe3d2 100644 --- a/src/language.rs +++ b/src/language.rs @@ -2,8 +2,9 @@ // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. -use std::fmt; use std::cell::RefCell; +use std::fmt; +use std::path::PathBuf; #[derive(Debug, Default)] pub struct Language<'a> { @@ -11,7 +12,7 @@ pub struct Language<'a> { pub line_comment: &'a str, pub multi_line: &'a str, pub multi_line_end: &'a str, - pub files: Vec, + pub files: Vec, pub code: usize, pub comments: usize, pub blanks: usize, diff --git a/src/main.rs b/src/main.rs index b1c5f4d..cd5488a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,8 @@ extern crate clap; #[macro_use] extern crate maplit; +extern crate glob; +extern crate walkdir; #[macro_use] pub mod macros; pub mod language; @@ -13,14 +15,16 @@ pub mod fsutil; use std::cell::RefCell; use std::io::Read; -use std::path::Path; use std::fs::File; +use std::path::Path; use clap::App; +use glob::glob; +use walkdir::{WalkDir, WalkDirIterator}; use language::Language; -use fsutil::{get_all_files, contains_comments}; +use fsutil::contains_comments; const ROW: &'static str = "-----------------------------------------------------------------------\ ---------"; const BLANKS: &'static str = "blanks"; @@ -41,7 +45,7 @@ fn main() { let c_sharp = Language::new_c("C#"); let clojure = Language::new_single("Clojure", ";,#,#_"); let coffee_script = Language::new("CoffeeScript", "#", "###", "###"); - let cold_fusion = Language::new("ColdFusion", ""); + 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"); @@ -68,6 +72,7 @@ fn main() { 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 python = Language::new("Python", "#", "'''", "'''"); let r = Language::new_single("R", "#"); @@ -144,6 +149,7 @@ fn main() { "php" => &php, "pas" => &pascal, "pl" => &perl, + "polly" => &polly, "py" => &python, "r" => &r, "rake" => &ruby, @@ -178,7 +184,7 @@ fn main() { let paths = matches.values_of("input").unwrap(); - let mut ignored_directories: Vec = Vec::new(); + let mut ignored_directories: Vec = vec![String::from(".git")]; if let Some(user_ignored) = matches.values_of("exclude") { for ignored in user_ignored { ignored_directories.push(ignored.to_owned()); @@ -205,13 +211,44 @@ fn main() { println!("{}", ROW); // Get every path from the paths provided. for path in paths { - let files = get_all_files(path.to_owned(), &ignored_directories); - for file in files { - let extension = unwrap_opt_cont!(unwrap_opt_cont!(Path::new(&file).extension()) - .to_str()); - let lowercase: &str = &extension.to_lowercase(); - let language = unwrap_opt_cont!(languages.get_mut(lowercase)); - language.borrow_mut().files.push(file.to_owned()); + 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 = { + let extension = unwrap_opt_cont!(unwrap_opt_cont!(path.extension()) + .to_str()); + let lowercase = extension.to_lowercase(); + unwrap_opt_cont!(languages.get_mut(&*lowercase)) + }; + + language.borrow_mut().files.push(path); + } + } 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 = { + let extension = unwrap_opt_cont!(unwrap_opt_cont!(entry.path().extension()) + .to_str()); + let lowercase = extension.to_lowercase(); + unwrap_opt_cont!(languages.get_mut(&*lowercase)) + }; + + language.borrow_mut().files.push(entry.path().to_owned()); + } } } @@ -225,7 +262,7 @@ fn main() { for file in files { let mut contents = String::new(); let is_fortran = language.borrow().name.contains("FORTRAN"); - 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)); let mut is_in_comments = false; @@ -283,7 +320,7 @@ fn main() { if matches.is_present(FILES) { println!("{}", ROW); for file in &language.borrow().files { - println!("{}", file); + println!("{}", unwrap_opt_cont!(file.to_str())); } println!("{}", ROW); }