diff --git a/.gitignore b/.gitignore index ac443b7..7f501b8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ target src/test +.settings diff --git a/Cargo.toml b/Cargo.toml index 37c417f..8dde448 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,5 @@ glob = "*" [profile.dev] debug = true - [profile.release] opt-level = 3 \ No newline at end of file diff --git a/src/fsutil.rs b/src/fsutil.rs new file mode 100644 index 0000000..7ba8bde --- /dev/null +++ b/src/fsutil.rs @@ -0,0 +1,84 @@ +extern crate glob; + +use std::fs; +use std::fs::metadata; +use self::glob::glob; + +pub fn contains_comments(file: &str, comment: &str) -> bool { + let vector = file.splitn(3, "\"").filter_map( |element| { + if !(element == "") { + Some(element) + } else { + None + } + + }).collect::>(); + + let length = vector.len(); + + if length == 0 || length == 1 { + return false + } + + if length == 2 { + for element in &vector { + if element.contains(comment) { + return true + } + } + return false + } + + if vector[0].contains(comment) { + + return true + } + + if vector[2].contains("\"") { + + return contains_comments(vector[2], comment) + } else if vector[2].contains(comment) { + + return true + } + false +} + +pub fn get_all_files(path: String, ignored_directories: &Vec) -> Vec { + let mut files: Vec = Vec::new(); + + if let Ok(result) = metadata(&path) { + if result.is_dir() { + let dir = fs::read_dir(&path).unwrap(); + 'file: for entry in dir { + let entry = entry.unwrap(); + let file_path = entry.path(); + let file_str = file_path.to_str().unwrap(); + let file_string = file_str.to_owned(); + let path_metadata = metadata(&file_string).unwrap(); + + if path_metadata.is_dir() { + for ignored_directory in ignored_directories { + if file_str.contains(ignored_directory) { + continue 'file; + } + } + 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 { + for path_buf in glob(&path).unwrap() { + let file_path = path_buf.unwrap().as_path().to_str().unwrap().to_owned(); + files.push(file_path); + } + } + + files +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 998aee1..aa7e519 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,24 +1,25 @@ extern crate getopts; -extern crate glob; pub mod language; +pub mod fsutil; use std::env; -use std::fs; use std::io::Read; use std::path::Path; -use std::fs::{File, metadata}; +use std::fs::File; use std::collections::HashMap; -use self::glob::glob; use getopts::Options; use language::Language; +use fsutil::{get_all_files, contains_comments}; fn main() { let args: Vec = env::args().collect(); let mut opts = Options::new(); opts.optflag("h", "help", "Print this help menu"); - opts.optopt("", "exclude-dir", "Example: --exclude-dir=docs", "\tDirectories wanted to be ignored"); + opts.optopt("", "exclude-dir", + "Example: --exclude-dir=docs", + "\tDirectories wanted to be ignored"); let matches = opts.parse(&args[1..]).unwrap(); let mut ignored_directories: Vec = Vec::new(); @@ -34,150 +35,121 @@ fn main() { let exclude_args = matches.opt_str("exclude-dir").unwrap(); let exclude_vec = exclude_args.split(","); - for excluded in exclude_vec { ignored_directories.push(excluded.to_string()); } } - if !matches.free.is_empty() { - println!("----------------------------------------------------------------------------------------------------"); - println!(" {:<15} {:>15} {:>15} {:>15} {:>15} {:>15} ", - "language", "files", "total", "blanks", "comments", "code"); - println!("----------------------------------------------------------------------------------------------------"); - let mut languages: HashMap<&str, Language> = HashMap::new(); - languages.insert("cpp" , Language::new("C++", "//","/*","*/")); - languages.insert("hpp" , Language::new("C++ Header", "//","/*","*/")); - languages.insert("c" , Language::new("C", "//","/*","*/")); - languages.insert("h" , Language::new("C Header", "//","/*","*/")); - languages.insert("css" , Language::new("CSS", "//","/*","*/")); - languages.insert("java" , Language::new("Java", "//","/*","*/")); - languages.insert("js" , Language::new("JavaScript", "//","/*","*/")); - languages.insert("rs" , Language::new("Rust", "//","/*","*/")); - languages.insert("xml" , Language::new("XML", "")); - languages.insert("html" , Language::new("HTML", "")); - languages.insert("py" , Language::new("Python", "#","'''","'''")); - languages.insert("rb" , Language::new("Ruby", "#","=begin","=end")); + if matches.free.is_empty() { + println!("ERROR: "); + println!("You must provide a file, or folder path as an argument."); + return; + } - for path in matches.free { - let files = get_all_files(path, &ignored_directories); - for file in files { - let extension = match Path::new(&file).extension() { - Some(result) => result.to_str().unwrap(), - None => continue, - }; + let row = "----------------------------------------------------------------------------------------------------"; - let mut language = match languages.get_mut(extension) { - Some(result) => result, - None => continue, - }; - language.files.push(file.to_string()); - } + println!("{}", row); + println!(" {:<15} {:>15} {:>15} {:>15} {:>15} {:>15} ", + "language", "files", "total", "blanks", "comments", "code"); + println!("{}", row); + let mut languages: HashMap<&str, Language> = HashMap::new(); + languages.insert("cpp" , Language::new("C++", "//","/*","*/")); + languages.insert("hpp" , Language::new("C++ Header", "//","/*","*/")); + languages.insert("c" , Language::new("C", "//","/*","*/")); + languages.insert("h" , Language::new("C Header", "//","/*","*/")); + languages.insert("css" , Language::new("CSS", "//","/*","*/")); + languages.insert("java" , Language::new("Java", "//","/*","*/")); + languages.insert("js" , Language::new("JavaScript", "//","/*","*/")); + languages.insert("rs" , Language::new("Rust", "//","/*","*/")); + languages.insert("xml" , Language::new("XML", "")); + languages.insert("html" , Language::new("HTML", "")); + languages.insert("py" , Language::new("Python", "#","'''","'''")); + languages.insert("rb" , Language::new("Ruby", "#","=begin","=end")); + languages.insert("php" , Language::new("PHP", "#,//","/*","*/")); + + for path in matches.free { + let files = get_all_files(path, &ignored_directories); + + for file in files { + let extension = match Path::new(&file).extension() { + Some(result) => result.to_str().unwrap(), + None => continue, + }; + + let mut language = match languages.get_mut(extension) { + Some(result) => result, + None => continue, + }; + language.files.push(file.to_string()); } + } - let mut total = Language::new("Total", "", "", ""); + let mut total = Language::new("Total", "", "", ""); - for (_, language) in languages.iter_mut() { + for (_, language) in languages.iter_mut() { - for file in language.files.iter() { - let mut buffer: Vec = Vec::new(); + for file in language.files.iter() { + let mut buffer: Vec = Vec::new(); - let mut file_ref = match File::open(&file) { - Ok(result) => result, - _ => continue, - }; + let mut file_ref = match File::open(&file) { + Ok(result) => result, + _ => continue, + }; - let _ = file_ref.read_to_end(&mut buffer); + let _ = file_ref.read_to_end(&mut buffer); - let contents = match String::from_utf8(buffer) { - Ok(result) => result, - Err(_) => continue, - }; + let contents = match String::from_utf8(buffer) { + Ok(result) => result, + Err(_) => continue, + }; - let mut is_in_comments = false; + let mut is_in_comments = false; - for line in contents.lines() { - let line = line.trim(); - language.lines += 1; + for line in contents.lines() { + let line = line.trim(); + language.lines += 1; - if line.starts_with(language.multi_line) { - language.comments += 1; - is_in_comments = true; - } else if line.contains(language.multi_line) { - language.code += 1; - is_in_comments = true; + if line.starts_with(language.multi_line) { + language.comments += 1; + is_in_comments = true; + } else if contains_comments(line, language.multi_line) { + language.code += 1; + is_in_comments = true; + } + + if is_in_comments { + if line.contains(language.multi_line_end) { + is_in_comments = false; } - - if is_in_comments { - if line.contains(language.multi_line_end) { - is_in_comments = false; - } - language.comments += 1; - continue; - } - - if line.starts_with(language.line_comment) { + language.comments += 1; + continue; + } + let single_comments = language.line_comment.split(","); + for single in single_comments { + if line.starts_with(single) { language.comments += 1; } else if line.trim().is_empty() { language.blanks += 1; } else { language.code += 1; } - }; - } - if !language.is_empty() { - println!("{}", language); - } - total.total += language.files.len(); - total.lines += language.lines; - total.comments += language.comments; - total.blanks += language.blanks; - total.code += language.code; - } - println!("----------------------------------------------------------------------------------------------------"); - println!("{}", total); - println!("----------------------------------------------------------------------------------------------------"); - } -} - - - -fn get_all_files(path: String, ignored_directories: &Vec) -> Vec { - let mut files: Vec = Vec::new(); - - if let Ok(result) = metadata(&path) { - if result.is_dir() { - let dir = fs::read_dir(&path).unwrap(); - 'file: for entry in dir { - let dir_entry = entry.unwrap(); - let file_path = dir_entry.path(); - let file_str = file_path.to_str().unwrap(); - let file_string = file_str.to_string(); - let path_metadata = metadata(&file_string).unwrap(); - - if path_metadata.is_dir() { - for ignored_directory in ignored_directories { - if file_str.contains(ignored_directory) { - continue 'file; - } - } - 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 { - for path_buf in glob(&path).unwrap() { - let file_path = path_buf.unwrap().as_path().to_str().unwrap().to_string(); - files.push(file_path); + + if !language.is_empty() { + println!("{}", language); } + + total.total += language.files.len(); + total.lines += language.lines; + total.comments += language.comments; + total.blanks += language.blanks; + total.code += language.code; } - files + println!("{}", row); + println!("{}", total); + println!("{}", row); } \ No newline at end of file