mirror of
https://github.com/XAMPPRocky/tokei
synced 2024-10-05 23:39:28 +00:00
VERSION 1.1, added sorting, added support for 26 languages, replaced getopts with clap
This commit is contained in:
parent
ee045d302c
commit
3bbc39f937
30
Cargo.lock
generated
30
Cargo.lock
generated
|
@ -1,17 +1,24 @@
|
||||||
[root]
|
[root]
|
||||||
name = "rusty-cloc"
|
name = "tokei"
|
||||||
version = "0.1.0"
|
version = "1.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getopts 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 1.4.0 (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)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getopts"
|
name = "ansi_term"
|
||||||
version = "0.2.11"
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ansi_term 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"strsim 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"yaml-rust 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -20,15 +27,12 @@ version = "0.2.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "strsim"
|
||||||
version = "0.1.8"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "yaml-rust"
|
||||||
version = "0.3.1"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
|
||||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
14
Cargo.toml
14
Cargo.toml
|
@ -1,14 +1,14 @@
|
||||||
[package]
|
[package]
|
||||||
name = "rusty-cloc"
|
name = "tokei"
|
||||||
version = "0.1.0"
|
version = "1.1.0"
|
||||||
authors = ["Aaronepower <theaaronepower@gmail.com>"]
|
authors = ["Aaronepower <theaaronepower@gmail.com>"]
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
getopts = "0.2"
|
|
||||||
glob = "*"
|
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = {version = "*", features = ["yaml"]}
|
||||||
|
glob = "*"
|
||||||
|
|
68
README.md
68
README.md
|
@ -1,11 +1,67 @@
|
||||||
# rusty-cloc
|
# Tokei
|
||||||
A CLOC(Count Lines Of Code) program, written in Rust.
|
A blazingly fast CLOC(Count Lines Of Code) program, written in Rust.
|
||||||
|
|
||||||
|
|
||||||
# Options
|
# Options
|
||||||
|
```
|
||||||
|
Aaron P. <theaaronepower@gmail.com>
|
||||||
|
A quick CLOC (Count Lines Of Code) tool
|
||||||
|
|
||||||
`--exclude-dir` exclude one, or more directories from the search.
|
USAGE:
|
||||||
###### Example
|
tokei [FLAGS] [OPTIONS] [--] <input>...
|
||||||
`rusty-cloc --exclude-dir=node_modules`
|
|
||||||
|
|
||||||
Will ignore everything within a folder named `node_modules`
|
FLAGS:
|
||||||
|
-h, --help Prints help information
|
||||||
|
-l, --languages prints out supported languages and their extensions
|
||||||
|
-V, --version Prints version information
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
-e, --exclude <exclude>... Will ignore all files and directories containing the word ie --exclude node_modules
|
||||||
|
-s, --sort <sort> Will sort based on a certain column ie --sort=files will sort by file count.
|
||||||
|
|
||||||
|
ARGS:
|
||||||
|
input... The input file(s)/directory(ies)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
# Supported Languages
|
||||||
|
```
|
||||||
|
ActionScript (as)
|
||||||
|
C (c)
|
||||||
|
ColdFusion CFScript (cfc)
|
||||||
|
ColdFusion (cfm)
|
||||||
|
Clojure (clj)
|
||||||
|
CoffeeScript (coffee)
|
||||||
|
C++ (cpp)
|
||||||
|
C# (cs)
|
||||||
|
CSS (css)
|
||||||
|
D (d)
|
||||||
|
Dart (dart)
|
||||||
|
LISP (el)
|
||||||
|
Go (go)
|
||||||
|
C Header (h)
|
||||||
|
C++ Header (hpp)
|
||||||
|
Haskell (hs)
|
||||||
|
HTML (html)
|
||||||
|
Java (java)
|
||||||
|
JavaScript (js)
|
||||||
|
JSON (json)
|
||||||
|
JSX (jsx)
|
||||||
|
Objective-C (m)
|
||||||
|
Objective-C++ (mm)
|
||||||
|
Pascal (pas)
|
||||||
|
PHP (php)
|
||||||
|
Perl (pl)
|
||||||
|
Python (py)
|
||||||
|
R (r)
|
||||||
|
Ruby (rb)
|
||||||
|
Ruby HTML (rhtml)
|
||||||
|
Rust (rs)
|
||||||
|
Sass (sass)
|
||||||
|
BASH (sh)
|
||||||
|
SQL (sql)
|
||||||
|
Swift (swift)
|
||||||
|
TypeScript (ts)
|
||||||
|
XML (xml)
|
||||||
|
YAML (yml)
|
||||||
|
```
|
||||||
|
|
25
cli.yml
Normal file
25
cli.yml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
name: Tokei
|
||||||
|
version: 1.1
|
||||||
|
author: Aaron P. <theaaronepower@gmail.com>
|
||||||
|
about: A quick CLOC (Count Lines Of Code) tool
|
||||||
|
args:
|
||||||
|
- exclude:
|
||||||
|
short: e
|
||||||
|
long: exclude
|
||||||
|
multiple: true
|
||||||
|
help: Will ignore all files and directories containing the word ie --exclude node_modules
|
||||||
|
takes_value: true
|
||||||
|
- sort:
|
||||||
|
short: s
|
||||||
|
long: sort
|
||||||
|
takes_value: true
|
||||||
|
help: Will sort based on a certain column ie --sort=files will sort by file count.
|
||||||
|
- input:
|
||||||
|
index: 1
|
||||||
|
multiple: true
|
||||||
|
required: true
|
||||||
|
help: The input file(s)/directory(ies)
|
||||||
|
- languages:
|
||||||
|
short: l
|
||||||
|
long: languages
|
||||||
|
help: prints out supported languages and their extensions
|
|
@ -41,7 +41,7 @@ pub fn contains_comments(file: &str, comment: &str) -> bool {
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_all_files(path: String, ignored_directories: &Vec<String>) -> Vec<String> {
|
pub fn get_all_files(path: String, ignored_directories: &Vec<String>) -> Vec<String> {
|
||||||
|
@ -49,13 +49,16 @@ pub fn get_all_files(path: String, ignored_directories: &Vec<String>) -> Vec<Str
|
||||||
|
|
||||||
if let Ok(result) = metadata(&path) {
|
if let Ok(result) = metadata(&path) {
|
||||||
if result.is_dir() {
|
if result.is_dir() {
|
||||||
let dir = fs::read_dir(&path).unwrap();
|
let dir = match fs::read_dir(&path) {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(err) => panic!("ERROR: {:?}", err),
|
||||||
|
};
|
||||||
'file: for entry in dir {
|
'file: for entry in dir {
|
||||||
let entry = entry.unwrap();
|
let entry = unwrap_rs_cont!(entry);
|
||||||
let file_path = entry.path();
|
let file_path = entry.path();
|
||||||
let file_str = file_path.to_str().unwrap();
|
let file_str = unwrap_opt_cont!(file_path.to_str());
|
||||||
let file_string = file_str.to_owned();
|
let file_string = file_str.to_owned();
|
||||||
let path_metadata = metadata(&file_string).unwrap();
|
let path_metadata = unwrap_rs_cont!(metadata(file_str));
|
||||||
|
|
||||||
if path_metadata.is_dir() {
|
if path_metadata.is_dir() {
|
||||||
for ignored_directory in ignored_directories {
|
for ignored_directory in ignored_directories {
|
||||||
|
@ -74,11 +77,15 @@ pub fn get_all_files(path: String, ignored_directories: &Vec<String>) -> Vec<Str
|
||||||
files.push(path);
|
files.push(path);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for path_buf in glob(&path).unwrap() {
|
let iter = match glob(&path) {
|
||||||
let file_path = path_buf.unwrap().as_path().to_str().unwrap().to_owned();
|
Ok(value) => value,
|
||||||
|
Err(err) => panic!("{:?}", err)
|
||||||
|
};
|
||||||
|
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);
|
files.push(file_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
files
|
files
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,12 @@ pub struct Language<'a> {
|
||||||
pub multi_line: &'a str,
|
pub multi_line: &'a str,
|
||||||
pub multi_line_end: &'a str,
|
pub multi_line_end: &'a str,
|
||||||
pub files: Vec<String>,
|
pub files: Vec<String>,
|
||||||
pub code: u32,
|
pub code: usize,
|
||||||
pub comments: u32,
|
pub comments: usize,
|
||||||
pub blanks: u32,
|
pub blanks: usize,
|
||||||
pub lines: u32,
|
pub lines: usize,
|
||||||
pub total: usize,
|
pub total: usize,
|
||||||
|
pub size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Language<'a> {
|
impl<'a> Language<'a> {
|
||||||
|
@ -30,6 +31,71 @@ impl<'a> Language<'a> {
|
||||||
blanks: 0,
|
blanks: 0,
|
||||||
lines: 0,
|
lines: 0,
|
||||||
total: 0,
|
total: 0,
|
||||||
|
size: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_c(name: &'a str) -> Language<'a> {
|
||||||
|
Language {
|
||||||
|
name: name,
|
||||||
|
line_comment: "//",
|
||||||
|
multi_line: "/*",
|
||||||
|
multi_line_end: "*/",
|
||||||
|
files: Vec::new(),
|
||||||
|
code: 0,
|
||||||
|
comments: 0,
|
||||||
|
blanks: 0,
|
||||||
|
lines: 0,
|
||||||
|
total: 0,
|
||||||
|
size: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_html(name: &'a str) -> Language<'a> {
|
||||||
|
Language {
|
||||||
|
name: name,
|
||||||
|
line_comment: "<!--",
|
||||||
|
multi_line: "<!--",
|
||||||
|
multi_line_end: "-->",
|
||||||
|
files: Vec::new(),
|
||||||
|
code: 0,
|
||||||
|
comments: 0,
|
||||||
|
blanks: 0,
|
||||||
|
lines: 0,
|
||||||
|
total: 0,
|
||||||
|
size: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_blank(name: &'a str) -> Language<'a> {
|
||||||
|
Language {
|
||||||
|
name: name,
|
||||||
|
line_comment: "",
|
||||||
|
multi_line: "",
|
||||||
|
multi_line_end: "",
|
||||||
|
files: Vec::new(),
|
||||||
|
code: 0,
|
||||||
|
comments: 0,
|
||||||
|
blanks: 0,
|
||||||
|
lines: 0,
|
||||||
|
total: 0,
|
||||||
|
size: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_single(name: &'a str, line_comment: &'a str) -> Language<'a> {
|
||||||
|
Language {
|
||||||
|
name: name,
|
||||||
|
line_comment: line_comment,
|
||||||
|
multi_line: "",
|
||||||
|
multi_line_end: "",
|
||||||
|
files: Vec::new(),
|
||||||
|
code: 0,
|
||||||
|
comments: 0,
|
||||||
|
blanks: 0,
|
||||||
|
lines: 0,
|
||||||
|
total: 0,
|
||||||
|
size: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,13 +106,11 @@ impl<'a> Language<'a> {
|
||||||
|
|
||||||
impl<'a> fmt::Display for Language<'a> {
|
impl<'a> fmt::Display for Language<'a> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let mut total;
|
let total = if self.total == 0 {
|
||||||
|
self.files.len()
|
||||||
if self.total == 0 {
|
|
||||||
total = self.files.len()
|
|
||||||
} else {
|
} else {
|
||||||
total = self.total;
|
self.total
|
||||||
}
|
};
|
||||||
write!(f," {: <15} {: >15} {:>15} {:>15} {:>15} {:>15} ", self.name, total, self.lines, self.blanks, self.comments, self.code)
|
write!(f," {: <15} {: >15} {:>15} {:>15} {:>15} {:>15}", self.name, total, self.lines, self.blanks, self.comments, self.code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
src/macros.rs
Normal file
19
src/macros.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#[inline(always)]
|
||||||
|
macro_rules! unwrap_opt_cont {
|
||||||
|
($option:expr) => {
|
||||||
|
match $option {
|
||||||
|
Some(result) => result,
|
||||||
|
None => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
macro_rules! unwrap_rs_cont {
|
||||||
|
($result:expr) => {
|
||||||
|
match $result {
|
||||||
|
Ok(result) => result,
|
||||||
|
Err(_) => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
227
src/main.rs
227
src/main.rs
|
@ -1,122 +1,140 @@
|
||||||
extern crate getopts;
|
#[macro_use]
|
||||||
|
extern crate clap;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
pub mod macros;
|
||||||
pub mod language;
|
pub mod language;
|
||||||
pub mod fsutil;
|
pub mod fsutil;
|
||||||
|
|
||||||
use std::env;
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::collections::HashMap;
|
use std::collections::BTreeMap;
|
||||||
use getopts::Options;
|
|
||||||
|
use clap::App;
|
||||||
|
|
||||||
use language::Language;
|
use language::Language;
|
||||||
use fsutil::{get_all_files, contains_comments};
|
use fsutil::{get_all_files, contains_comments};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let yaml = load_yaml!("../cli.yml");
|
||||||
let mut opts = Options::new();
|
let matches = App::from_yaml(yaml).get_matches();
|
||||||
|
|
||||||
opts.optflag("h", "help", "Print this help menu");
|
let mut languages: BTreeMap<&str, Language> = BTreeMap::new();
|
||||||
opts.optopt("", "exclude-dir",
|
languages.insert("as" , Language::new_c("ActionScript"));
|
||||||
"Example: --exclude-dir=docs",
|
languages.insert("c" , Language::new_c("C"));
|
||||||
"\tDirectories wanted to be ignored");
|
languages.insert("cs" , Language::new_c("C#"));
|
||||||
|
languages.insert("clj" , Language::new_single("Clojure", ";,#,#_"));
|
||||||
|
languages.insert("coffee" , Language::new("CoffeeScript", "#", "###", "###"));
|
||||||
|
languages.insert("cfm" , Language::new("ColdFusion", "<!---", "<!---", "--->"));
|
||||||
|
languages.insert("cfc" , Language::new_c("ColdFusion CFScript"));
|
||||||
|
languages.insert("cpp" , Language::new_c("C++"));
|
||||||
|
languages.insert("css" , Language::new_c("CSS"));
|
||||||
|
languages.insert("d" , Language::new_c("D"));
|
||||||
|
languages.insert("dart" , Language::new_c("Dart"));
|
||||||
|
languages.insert("go" , Language::new_c("Go"));
|
||||||
|
languages.insert("h" , Language::new_c("C Header"));
|
||||||
|
languages.insert("hs" , Language::new_single("Haskell", "--"));
|
||||||
|
languages.insert("hpp" , Language::new_c("C++ Header"));
|
||||||
|
languages.insert("html" , Language::new_html("HTML"));
|
||||||
|
languages.insert("java" , Language::new_c("Java"));
|
||||||
|
languages.insert("js" , Language::new_c("JavaScript"));
|
||||||
|
languages.insert("json" , Language::new_blank("JSON"));
|
||||||
|
languages.insert("jsx" , Language::new_c("JSX"));
|
||||||
|
languages.insert("el" , Language::new("LISP", ";", "#|", "|#"));
|
||||||
|
languages.insert("m" , Language::new_c("Objective-C"));
|
||||||
|
languages.insert("mm" , Language::new_c("Objective-C++"));
|
||||||
|
languages.insert("php" , Language::new("PHP", "#,//","/*","*/"));
|
||||||
|
languages.insert("pas" , Language::new("Pascal", "//,(*","{","}"));
|
||||||
|
languages.insert("pl" , Language::new("Perl", "#","=","=cut"));
|
||||||
|
languages.insert("py" , Language::new("Python", "#","'''","'''"));
|
||||||
|
languages.insert("rs" , Language::new("Rust", "//,///,//!", "/*", "*/"));
|
||||||
|
languages.insert("r" , Language::new("R", "#","",""));
|
||||||
|
languages.insert("rb" , Language::new("Ruby", "#","=begin","=end"));
|
||||||
|
languages.insert("rhtml" , Language::new_html("Ruby HTML"));
|
||||||
|
languages.insert("sass" , Language::new_c("Sass"));
|
||||||
|
languages.insert("sh" , Language::new_single("BASH", "#"));
|
||||||
|
languages.insert("sql" , Language::new("SQL", "--", "/*", "*/"));
|
||||||
|
languages.insert("swift" , Language::new_c("Swift"));
|
||||||
|
languages.insert("ts" , Language::new_c("TypeScript"));
|
||||||
|
languages.insert("xml" , Language::new_html("XML"));
|
||||||
|
languages.insert("yml" , Language::new_single("YAML", "#"));
|
||||||
|
|
||||||
let matches = opts.parse(&args[1..]).unwrap();
|
if matches.is_present("languages") {
|
||||||
let mut ignored_directories: Vec<String> = Vec::new();
|
for (ext, language) in languages {
|
||||||
ignored_directories.push(".git".to_string());
|
println!("{:<25} ({})", language.name, ext);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if matches.opt_present("h") {
|
|
||||||
let brief = format!("Usage: {} [options] [paths]", args[0].clone());
|
let paths = matches.values_of("input").unwrap();
|
||||||
println!("{}", opts.usage(&brief));
|
|
||||||
return;
|
let mut ignored_directories: Vec<String> = Vec::new();
|
||||||
|
|
||||||
|
if let Some(user_ignored) = matches.values_of("exclude") {
|
||||||
|
for ignored in user_ignored {
|
||||||
|
ignored_directories.push(ignored.to_owned());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches.opt_present("exclude-dir") {
|
let mut sort = String::new();
|
||||||
let exclude_args = matches.opt_str("exclude-dir").unwrap();
|
if let Some(sort_by) = matches.value_of("sort") {
|
||||||
let exclude_vec = exclude_args.split(",");
|
match &*sort_by.to_lowercase() {
|
||||||
|
"files" | "total" | "blanks" | "comments" | "code" => sort.push_str(&*sort_by.to_lowercase()),
|
||||||
|
_ => println!("--sort must be any of the following files, total, blanks, comments, code"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let sort_empty = sort.is_empty();
|
||||||
|
|
||||||
for excluded in exclude_vec {
|
let row = "--------------------------------------------------------------------------------------------------";
|
||||||
ignored_directories.push(excluded.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if matches.free.is_empty() {
|
|
||||||
println!("ERROR: ");
|
|
||||||
println!("You must provide a file, or folder path as an argument.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let row = "----------------------------------------------------------------------------------------------------";
|
|
||||||
|
|
||||||
println!("{}", row);
|
println!("{}", row);
|
||||||
println!(" {:<15} {:>15} {:>15} {:>15} {:>15} {:>15} ",
|
println!(" {:<15} {:>15} {:>15} {:>15} {:>15} {:>15}",
|
||||||
"language", "files", "total", "blanks", "comments", "code");
|
"Language", "Files", "Total", "Blanks", "Comments", "Code");
|
||||||
println!("{}", row);
|
println!("{}", row);
|
||||||
let mut languages: HashMap<&str, Language> = HashMap::new();
|
for path in paths {
|
||||||
languages.insert("cpp" , Language::new("C++", "//","/*","*/"));
|
let files = get_all_files(path.to_owned(), &ignored_directories);
|
||||||
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 {
|
for file in files {
|
||||||
let extension = match Path::new(&file).extension() {
|
let extension = unwrap_opt_cont!(unwrap_opt_cont!(Path::new(&file).extension()).to_str());
|
||||||
Some(result) => result.to_str().unwrap(),
|
|
||||||
None => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut language = match languages.get_mut(extension) {
|
let lowercase: &str = &extension.to_lowercase();
|
||||||
Some(result) => result,
|
|
||||||
None => continue,
|
let mut language = unwrap_opt_cont!(languages.get_mut(lowercase));
|
||||||
};
|
language.files.push(file.to_owned());
|
||||||
language.files.push(file.to_string());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut total = Language::new("Total", "", "", "");
|
let mut total = Language::new_blank("Total");
|
||||||
|
|
||||||
for (_, language) in languages.iter_mut() {
|
for (_, language) in &mut languages {
|
||||||
|
|
||||||
for file in language.files.iter() {
|
for file in language.files.iter() {
|
||||||
let mut buffer: Vec<u8> = Vec::new();
|
|
||||||
|
|
||||||
let mut file_ref = match File::open(&file) {
|
let mut file_ref = unwrap_rs_cont!(File::open(&file));
|
||||||
Ok(result) => result,
|
let mut contents = String::new();
|
||||||
_ => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
let _ = file_ref.read_to_end(&mut buffer);
|
|
||||||
|
|
||||||
let contents = match String::from_utf8(buffer) {
|
|
||||||
Ok(result) => result,
|
|
||||||
Err(_) => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
let _ = unwrap_rs_cont!(file_ref.read_to_string(&mut contents));
|
||||||
|
|
||||||
let mut is_in_comments = false;
|
let mut is_in_comments = false;
|
||||||
|
|
||||||
for line in contents.lines() {
|
'line: for line in contents.lines() {
|
||||||
let line = line.trim();
|
let line = line.trim();
|
||||||
language.lines += 1;
|
language.lines += 1;
|
||||||
|
|
||||||
if line.starts_with(language.multi_line) {
|
if line.trim().is_empty() {
|
||||||
language.comments += 1;
|
language.blanks += 1;
|
||||||
is_in_comments = true;
|
continue;
|
||||||
} else if contains_comments(line, language.multi_line) {
|
}
|
||||||
language.code += 1;
|
if !language.multi_line.is_empty() {
|
||||||
is_in_comments = true;
|
if line.starts_with(language.multi_line) {
|
||||||
}
|
is_in_comments = true;
|
||||||
|
} else if contains_comments(line, language.multi_line) {
|
||||||
|
language.code += 1;
|
||||||
|
is_in_comments = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if is_in_comments {
|
if is_in_comments {
|
||||||
if line.contains(language.multi_line_end) {
|
if line.contains(language.multi_line_end) {
|
||||||
|
@ -129,16 +147,15 @@ fn main() {
|
||||||
for single in single_comments {
|
for single in single_comments {
|
||||||
if line.starts_with(single) {
|
if line.starts_with(single) {
|
||||||
language.comments += 1;
|
language.comments += 1;
|
||||||
} else if line.trim().is_empty() {
|
continue 'line;
|
||||||
language.blanks += 1;
|
}
|
||||||
} else {
|
}
|
||||||
language.code += 1;
|
language.code += 1;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !language.is_empty() {
|
|
||||||
|
if !language.is_empty() && sort_empty {
|
||||||
println!("{}", language);
|
println!("{}", language);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +166,35 @@ fn main() {
|
||||||
total.code += language.code;
|
total.code += language.code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !sort_empty {
|
||||||
|
let mut unsorted_vec:Vec<(&&str, &Language)> = languages.iter().collect();
|
||||||
|
match &*sort {
|
||||||
|
"files" => {
|
||||||
|
unsorted_vec.sort_by(|a, b| b.1.files.len().cmp(&a.1.files.len()))
|
||||||
|
},
|
||||||
|
"total" => {
|
||||||
|
unsorted_vec.sort_by(|a, b| b.1.lines.cmp(&a.1.lines))
|
||||||
|
},
|
||||||
|
"blanks" => {
|
||||||
|
unsorted_vec.sort_by(|a, b| b.1.blanks.cmp(&a.1.blanks))
|
||||||
|
},
|
||||||
|
"comments" => {
|
||||||
|
unsorted_vec.sort_by(|a, b| b.1.comments.cmp(&a.1.comments))
|
||||||
|
},
|
||||||
|
"code" => {
|
||||||
|
unsorted_vec.sort_by(|a, b| b.1.code.cmp(&a.1.code))
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (_, language) in unsorted_vec {
|
||||||
|
if !language.is_empty() {
|
||||||
|
println!("{}", language);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
println!("{}", row);
|
println!("{}", row);
|
||||||
println!("{}", total);
|
println!("{}", total);
|
||||||
println!("{}", row);
|
println!("{}", row);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue