mirror of https://github.com/XAMPPRocky/tokei
version 2.0
This commit is contained in:
parent
ebee004a8f
commit
0287ab0946
24
CHANGELOG.md
24
CHANGELOG.md
|
|
@ -1,3 +1,27 @@
|
|||
# 2.0.0
|
||||
|
||||
Major rewrite, now parallelized.
|
||||
Can now support sorting files.
|
||||
Added a progress message for when it is counting files.
|
||||
Fixed #29
|
||||
|
||||
Added languages:
|
||||
- Coq
|
||||
- Erlang
|
||||
- Kotlin
|
||||
- Idris
|
||||
- Nim
|
||||
- Oz
|
||||
- Prolog
|
||||
- Qcl
|
||||
- Scala
|
||||
- Unreal Script
|
||||
- Wolfram
|
||||
|
||||
# 1.6.0
|
||||
|
||||
Added file counting.
|
||||
|
||||
# 1.5.0
|
||||
|
||||
Added Shebang support.
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@
|
|||
name = "tokei"
|
||||
version = "1.6.0"
|
||||
dependencies = [
|
||||
"clap 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.5.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)",
|
||||
"rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
|
@ -15,19 +16,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.1.2"
|
||||
version = "2.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vec_map 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"yaml-rust 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"yaml-rust 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deque"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -44,19 +55,55 @@ dependencies = [
|
|||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "maplit"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.4.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
|
@ -80,6 +127,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.3.0"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ repository = "https://github.com/Aaronepower/tokei.git"
|
|||
homepage = "https://aaronepower.github.io/tokei/"
|
||||
license = "MIT/Apache-2.0"
|
||||
readme = "README.md"
|
||||
description = "Count your code, quickly."
|
||||
description = "Count code, quickly."
|
||||
|
||||
[profile.dev]
|
||||
debug = true
|
||||
|
|
@ -18,7 +18,8 @@ debug = true
|
|||
opt-level = 3
|
||||
|
||||
[dependencies]
|
||||
clap = {version = "2.1.1", features = ["yaml"]}
|
||||
clap = {version = "2.5.1", features = ["yaml"]}
|
||||
glob = "0.2.10"
|
||||
maplit = "0.1.3"
|
||||
walkdir = "0.1.5"
|
||||
rayon = "0.3.1"
|
||||
2
cli.yml
2
cli.yml
|
|
@ -3,7 +3,7 @@
|
|||
# found in the LICENSE file.
|
||||
bin_name: Tokei
|
||||
name: Tokei
|
||||
version: 1.3.0
|
||||
version: 2.0.0
|
||||
author: Aaron P. <theaaronepower@gmail.com>
|
||||
about: A quick CLOC (Count Lines Of Code) tool
|
||||
args:
|
||||
|
|
|
|||
137
src/fsutil.rs
137
src/fsutil.rs
|
|
@ -2,15 +2,10 @@
|
|||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::{self, BufRead, BufReader, Read, Write};
|
||||
use std::io::{BufRead, BufReader, Read};
|
||||
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};
|
||||
|
||||
|
|
@ -19,23 +14,23 @@ use language::LanguageName::*;
|
|||
|
||||
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::<Vec<char>>().windows(comment.len()) {
|
||||
let section = {
|
||||
let mut section = String::new();
|
||||
for chars in file.chars().collect::<Vec<char>>().windows(comment.len()) {
|
||||
let window = {
|
||||
let mut window = String::new();
|
||||
for ch in chars {
|
||||
section.push(*ch);
|
||||
window.push(*ch);
|
||||
}
|
||||
section
|
||||
window
|
||||
};
|
||||
|
||||
if section == comment {
|
||||
if window == comment {
|
||||
in_comments += 1;
|
||||
continue 'window;
|
||||
} else if section == comment_end {
|
||||
continue;
|
||||
} else if window == comment_end {
|
||||
if in_comments != 0 {
|
||||
in_comments -= 1;
|
||||
}
|
||||
continue 'window;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
in_comments != 0
|
||||
|
|
@ -49,11 +44,11 @@ pub fn get_all_files<'a, I: Iterator<Item = &'a str>>(paths: I,
|
|||
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") {
|
||||
let path = rs_or_cont!(path);
|
||||
let mut language = if opt_or_cont!(path.to_str()).contains("Makefile") {
|
||||
languages.get_mut(&Makefile).unwrap()
|
||||
} else {
|
||||
unwrap_opt_cont!(languages.get_mut(&unwrap_opt_cont!(get_language(&path))))
|
||||
opt_or_cont!(languages.get_mut(&opt_or_cont!(get_language(&path))))
|
||||
};
|
||||
|
||||
language.files.push(path.to_owned());
|
||||
|
|
@ -72,13 +67,12 @@ pub fn get_all_files<'a, I: Iterator<Item = &'a str>>(paths: I,
|
|||
});
|
||||
|
||||
for entry in walker {
|
||||
let entry = unwrap_rs_cont!(entry);
|
||||
let entry = rs_or_cont!(entry);
|
||||
|
||||
let mut language = if unwrap_opt_cont!(entry.path().to_str())
|
||||
.contains("Makefile") {
|
||||
let mut language = if opt_or_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()))))
|
||||
opt_or_cont!(languages.get_mut(&opt_or_cont!(get_language(entry.path()))))
|
||||
};
|
||||
|
||||
language.files.push(entry.path().to_owned());
|
||||
|
|
@ -135,73 +129,82 @@ 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),
|
||||
"bash" => Some(Bash),
|
||||
"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),
|
||||
"cfc" => Some(ColdFusionScript),
|
||||
"cfm" => Some(ColdFusion),
|
||||
"clj" => Some(Clojure),
|
||||
"cmd" => Some(Batch),
|
||||
"coffee" => Some(CoffeeScript),
|
||||
"cs" => Some(CSharp),
|
||||
"csh" => Some(CShell),
|
||||
"css" => Some(Css),
|
||||
"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),
|
||||
"ec" => Some(C),
|
||||
"el" => Some(Lisp),
|
||||
"erl" => Some(Erlang),
|
||||
"f" => Some(FortranLegacy),
|
||||
"for" => Some(FortranLegacy),
|
||||
"ftn" => Some(FortranLegacy),
|
||||
"f03" => Some(FortranModern),
|
||||
"f08" => Some(FortranModern),
|
||||
"f77" => Some(FortranLegacy),
|
||||
"f90" => Some(FortranModern),
|
||||
"f95" => Some(FortranModern),
|
||||
"go" => Some(Go),
|
||||
"h" => Some(CHeader),
|
||||
"hh" => Some(CppHeader),
|
||||
"hpp" => Some(CppHeader),
|
||||
"hrl" => Some(Erlang),
|
||||
"hs" => Some(Haskell),
|
||||
"html" => Some(Html),
|
||||
"hxx" => Some(CppHeader),
|
||||
"idr" => Some(Idris),
|
||||
"jai" => Some(Jai),
|
||||
"java" => Some(Java),
|
||||
"jl" => Some(Julia),
|
||||
"js" => Some(JavaScript),
|
||||
"json" => Some(Json),
|
||||
"jsx" => Some(Jsx),
|
||||
"kt" => Some(Kotlin),
|
||||
"kts" => Some(Kotlin),
|
||||
"lds" => Some(LinkerScript),
|
||||
"less" => Some(Less),
|
||||
"lidr" => Some(Idris),
|
||||
"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),
|
||||
"md" => Some(Markdown),
|
||||
"ml" => Some(OCaml),
|
||||
"mli" => Some(OCaml),
|
||||
"mm" => Some(ObjectiveCpp),
|
||||
"makefile" => Some(Makefile),
|
||||
"mustache" => Some(Mustache),
|
||||
"php" => Some(Php),
|
||||
"nim" => Some(Nim),
|
||||
"nb" => Some(Wolfram),
|
||||
"oz" => Some(Oz),
|
||||
"p" => Some(Prolog),
|
||||
"pas" => Some(Pascal),
|
||||
"pfo" => Some(FortranLegacy),
|
||||
"pcc" => Some(Cpp),
|
||||
"php" => Some(Php),
|
||||
"pl" => Some(Perl),
|
||||
"pro" => Some(Prolog),
|
||||
"qcl" => Some(Qcl),
|
||||
"text" => Some(Text),
|
||||
"txt" => Some(Text),
|
||||
"pgc" => Some(C),
|
||||
"polly" => Some(Polly),
|
||||
"proto" => Some(Protobuf),
|
||||
"py" => Some(Python),
|
||||
|
|
@ -210,9 +213,12 @@ pub fn get_language<P: AsRef<Path>>(entry: P) -> Option<LanguageName> {
|
|||
"rb" => Some(Ruby),
|
||||
"rhtml" => Some(RubyHtml),
|
||||
"rs" => Some(Rust),
|
||||
"s" => Some(Assembly),
|
||||
"sass" => Some(Sass),
|
||||
"sc" => Some(Lisp),
|
||||
"scss" => Some(Sass),
|
||||
"scala" => Some(Scala),
|
||||
"sh" => Some(Bash),
|
||||
"sml" => Some(Sml),
|
||||
"sql" => Some(Sql),
|
||||
"swift" => Some(Swift),
|
||||
|
|
@ -220,7 +226,12 @@ pub fn get_language<P: AsRef<Path>>(entry: P) -> Option<LanguageName> {
|
|||
"sty" => Some(Tex),
|
||||
"toml" => Some(Toml),
|
||||
"ts" => Some(TypeScript),
|
||||
"uc" => Some(UnrealScript),
|
||||
"uci" => Some(UnrealScript),
|
||||
"upkg" => Some(UnrealScript),
|
||||
"v" => Some(Coq),
|
||||
"vim" => Some(VimScript),
|
||||
"wl" => Some(Wolfram),
|
||||
"xml" => Some(Xml),
|
||||
"yaml" => Some(Yaml),
|
||||
"yml" => Some(Yaml),
|
||||
|
|
|
|||
124
src/language.rs
124
src/language.rs
|
|
@ -2,24 +2,24 @@
|
|||
// Use of this source code is governed by the MIT/APACHE2.0 license that can be
|
||||
// found in the LICENCE-{APACHE - MIT} file.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
use std::path::PathBuf;
|
||||
use std::ops::AddAssign;
|
||||
use stats::Stats;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Default, Clone, Eq, Ord, PartialEq, PartialOrd)]
|
||||
use consts::*;
|
||||
use stats::Stats;
|
||||
|
||||
#[derive(Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
|
||||
pub struct Language {
|
||||
pub blanks: usize,
|
||||
pub code: usize,
|
||||
pub comments: usize,
|
||||
pub files: Vec<PathBuf>,
|
||||
pub stats: Vec<Stats>,
|
||||
pub lines: usize,
|
||||
pub line_comment: &'static str,
|
||||
pub multi_line: &'static str,
|
||||
pub multi_line_end: &'static str,
|
||||
pub files: Vec<PathBuf>,
|
||||
pub code: usize,
|
||||
pub comments: usize,
|
||||
pub blanks: usize,
|
||||
pub lines: usize,
|
||||
pub total: usize,
|
||||
}
|
||||
|
||||
|
|
@ -59,8 +59,12 @@ impl Language {
|
|||
Language { ..Self::default() }
|
||||
}
|
||||
|
||||
pub fn new_single(line_comment: &'static str) -> Self {
|
||||
Language { line_comment: line_comment, ..Self::default() }
|
||||
pub fn new_func() -> Self {
|
||||
Language {
|
||||
multi_line: "(*",
|
||||
multi_line_end: "*)",
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_multi(multi_line: &'static str, multi_line_end: &'static str) -> Self {
|
||||
|
|
@ -71,6 +75,18 @@ impl Language {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new_pro() -> Self {
|
||||
Language {
|
||||
line_comment: "%",
|
||||
multi_line: "/*",
|
||||
multi_line_end: "*/",
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_single(line_comment: &'static str) -> Self {
|
||||
Language { line_comment: line_comment, ..Self::default() }
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.code == 0 && self.comments == 0 && self.blanks == 0 && self.lines == 0
|
||||
}
|
||||
|
|
@ -78,30 +94,33 @@ impl Language {
|
|||
pub fn is_blank(&self) -> bool {
|
||||
self.line_comment == "" && self.multi_line == ""
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Language {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let total = if self.total == 0 {
|
||||
self.files.len()
|
||||
} else {
|
||||
self.total
|
||||
};
|
||||
write!(f,
|
||||
" {: <18} {: >6} {:>12} {:>12} {:>12} {:>12}",
|
||||
"CHANGE",
|
||||
total,
|
||||
self.lines,
|
||||
self.blanks,
|
||||
self.comments,
|
||||
self.code)
|
||||
pub fn sort_by(&mut self, category: &str) {
|
||||
match category {
|
||||
BLANKS => self.stats.sort_by(|a, b| b.blanks.cmp(&a.blanks)),
|
||||
COMMENTS => self.stats.sort_by(|a, b| b.comments.cmp(&a.comments)),
|
||||
CODE => self.stats.sort_by(|a, b| b.code.cmp(&a.code)),
|
||||
TOTAL => self.stats.sort_by(|a, b| b.lines.cmp(&a.lines)),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print(&self, name: LanguageName) {
|
||||
println!(" {: <18} {: >6} {:>12} {:>12} {:>12} {:>12}",
|
||||
name.name(),
|
||||
self.total,
|
||||
self.lines,
|
||||
self.blanks,
|
||||
self.comments,
|
||||
self.code)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Adding languages to the raw total.
|
||||
impl<'a> AddAssign<&'a Language> for Language {
|
||||
fn add_assign(&mut self, rhs: &Self) {
|
||||
self.total += rhs.files.len();
|
||||
self.total += rhs.total;
|
||||
self.lines += rhs.lines;
|
||||
self.comments += rhs.comments;
|
||||
self.blanks += rhs.blanks;
|
||||
|
|
@ -112,7 +131,7 @@ impl<'a> AddAssign<&'a Language> for Language {
|
|||
// 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.total += rhs.total;
|
||||
self.lines += rhs.lines;
|
||||
self.comments += rhs.comments;
|
||||
self.blanks += rhs.blanks;
|
||||
|
|
@ -127,6 +146,7 @@ impl AddAssign<Stats> for Language {
|
|||
self.code += rhs.code;
|
||||
self.comments += rhs.comments;
|
||||
self.blanks += rhs.blanks;
|
||||
self.stats.push(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -139,45 +159,53 @@ pub enum LanguageName {
|
|||
Batch,
|
||||
C,
|
||||
CHeader,
|
||||
CSharp,
|
||||
CShell,
|
||||
Clojure,
|
||||
CoffeeScript,
|
||||
ColdFusion,
|
||||
ColdFusionScript,
|
||||
Coq,
|
||||
Cpp,
|
||||
CppHeader,
|
||||
CSharp,
|
||||
CShell,
|
||||
Css,
|
||||
D,
|
||||
Dart,
|
||||
DeviceTree,
|
||||
Lisp,
|
||||
Erlang,
|
||||
FortranLegacy,
|
||||
FortranModern,
|
||||
Go,
|
||||
Haskell,
|
||||
Html,
|
||||
Idris,
|
||||
Jai,
|
||||
Java,
|
||||
JavaScript,
|
||||
Julia,
|
||||
Json,
|
||||
Jsx,
|
||||
Kotlin,
|
||||
Less,
|
||||
LinkerScript,
|
||||
Lisp,
|
||||
Lua,
|
||||
Makefile,
|
||||
Markdown,
|
||||
Mustache,
|
||||
Nim,
|
||||
ObjectiveC,
|
||||
ObjectiveCpp,
|
||||
OCaml,
|
||||
Php,
|
||||
Oz,
|
||||
Pascal,
|
||||
Polly,
|
||||
Perl,
|
||||
Polly,
|
||||
Php,
|
||||
Protobuf,
|
||||
Prolog,
|
||||
Python,
|
||||
Qcl,
|
||||
R,
|
||||
Ruby,
|
||||
RubyHtml,
|
||||
|
|
@ -192,9 +220,12 @@ pub enum LanguageName {
|
|||
Toml,
|
||||
TypeScript,
|
||||
VimScript,
|
||||
UnrealScript,
|
||||
Wolfram,
|
||||
Xml,
|
||||
Yaml,
|
||||
Zsh,
|
||||
__Total,
|
||||
}
|
||||
|
||||
impl LanguageName {
|
||||
|
|
@ -208,45 +239,53 @@ impl LanguageName {
|
|||
Batch => "Batch",
|
||||
C => "C",
|
||||
CHeader => "C Header",
|
||||
CSharp => "C#",
|
||||
CShell => "C Shell",
|
||||
Clojure => "Clojure",
|
||||
CoffeeScript => "CoffeeScript",
|
||||
ColdFusion => "ColdFusion",
|
||||
ColdFusionScript => "ColdFusion CFScript",
|
||||
Coq => "Coq",
|
||||
Cpp => "C++",
|
||||
CppHeader => "C++ Header",
|
||||
CSharp => "C#",
|
||||
CShell => "C Shell",
|
||||
Css => "CSS",
|
||||
D => "D",
|
||||
Dart => "Dart",
|
||||
DeviceTree => "Device Tree",
|
||||
Lisp => "LISP",
|
||||
Erlang => "Erlang",
|
||||
FortranLegacy => "FORTRAN Legacy",
|
||||
FortranModern => "FORTRAN Modern",
|
||||
Go => "Go",
|
||||
Haskell => "Haskell",
|
||||
Html => "HTML",
|
||||
Idris => "Idris",
|
||||
Jai => "JAI",
|
||||
Java => "Java",
|
||||
JavaScript => "JavaScript",
|
||||
Julia => "Julia",
|
||||
Json => "JSON",
|
||||
Jsx => "JSX",
|
||||
Julia => "Julia",
|
||||
Kotlin => "Kotlin",
|
||||
Less => "LESS",
|
||||
LinkerScript => "LD Script",
|
||||
Lisp => "LISP",
|
||||
Lua => "Lua",
|
||||
Makefile => "Makefile",
|
||||
Markdown => "Markdown",
|
||||
Mustache => "Mustache",
|
||||
Nim => "Nim",
|
||||
ObjectiveC => "Objective C",
|
||||
ObjectiveCpp => "Objective C++",
|
||||
OCaml => "OCaml",
|
||||
Php => "PHP",
|
||||
Oz => "Oz",
|
||||
Pascal => "Pascal",
|
||||
Polly => "Polly",
|
||||
Perl => "Perl",
|
||||
Polly => "Polly",
|
||||
Php => "PHP",
|
||||
Protobuf => "Protocol Buffers",
|
||||
Prolog => "Prolog",
|
||||
Python => "Python",
|
||||
Qcl => "QCL",
|
||||
R => "R",
|
||||
Ruby => "Ruby",
|
||||
RubyHtml => "Ruby HTML",
|
||||
|
|
@ -260,10 +299,13 @@ impl LanguageName {
|
|||
Text => "Plain Text",
|
||||
Toml => "TOML",
|
||||
TypeScript => "TypeScript",
|
||||
UnrealScript => "Unreal Script",
|
||||
VimScript => "Vim Script",
|
||||
Wolfram => "Wolfram",
|
||||
Xml => "XML",
|
||||
Yaml => "YAML",
|
||||
Zsh => "Zsh",
|
||||
__Total => "Total",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
macro_rules! unwrap_opt_cont {
|
||||
macro_rules! opt_or_cont {
|
||||
($option:expr) => {
|
||||
match $option {
|
||||
Some(result) => result,
|
||||
|
|
@ -11,7 +11,7 @@ macro_rules! unwrap_opt_cont {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! unwrap_rs_cont {
|
||||
macro_rules! rs_or_cont {
|
||||
($result:expr) => {
|
||||
match $result {
|
||||
Ok(result) => result,
|
||||
|
|
@ -19,3 +19,9 @@ macro_rules! unwrap_rs_cont {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
macro_rules! debug {
|
||||
($fmt:expr) => (if cfg!(debug_assertions) {println!($fmt)});
|
||||
($fmt:expr, $($arg:tt)*) => (if cfg!(debug_assertions) {println!($fmt, $($arg)*)});
|
||||
}
|
||||
|
|
|
|||
285
src/main.rs
285
src/main.rs
|
|
@ -8,36 +8,28 @@ extern crate clap;
|
|||
extern crate maplit;
|
||||
extern crate glob;
|
||||
extern crate walkdir;
|
||||
extern crate rayon;
|
||||
#[macro_use]
|
||||
pub mod macros;
|
||||
pub mod language;
|
||||
pub mod fsutil;
|
||||
pub mod stats;
|
||||
mod macros;
|
||||
mod consts;
|
||||
mod fsutil;
|
||||
mod language;
|
||||
mod stats;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::{self, BufRead, BufReader, Read, Write};
|
||||
use std::io::{BufRead, Read};
|
||||
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 rayon::prelude::*;
|
||||
|
||||
use consts::*;
|
||||
use fsutil::*;
|
||||
use language::{Language, LanguageName};
|
||||
use language::LanguageName::*;
|
||||
|
||||
const ROW: &'static str = "-----------------------------------------------------------------------\
|
||||
--------";
|
||||
const BLANKS: &'static str = "blanks";
|
||||
const COMMENTS: &'static str = "comments";
|
||||
const CODE: &'static str = "code";
|
||||
const FILES: &'static str = "files";
|
||||
const TOTAL: &'static str = "total";
|
||||
use stats::Stats;
|
||||
|
||||
fn main() {
|
||||
let yaml = load_yaml!("../cli.yml");
|
||||
|
|
@ -54,58 +46,68 @@ fn main() {
|
|||
Batch => Language::new_single("REM"),
|
||||
C => Language::new_c(),
|
||||
CHeader => Language::new_c(),
|
||||
CSharp => Language::new_c(),
|
||||
CShell => Language::new_single("#"),
|
||||
Clojure => Language::new_single(";,#,#_"),
|
||||
CoffeeScript => Language::new("#", "###", "###"),
|
||||
ColdFusion => Language::new_multi("<!---", "--->"),
|
||||
ColdFusionScript => Language::new_c(),
|
||||
Coq => Language::new_func(),
|
||||
Cpp => Language::new_c(),
|
||||
CppHeader => Language::new_c(),
|
||||
CSharp => Language::new_c(),
|
||||
CShell => Language::new_single("#"),
|
||||
Css => Language::new_c(),
|
||||
D => Language::new_c(),
|
||||
Dart => Language::new_c(),
|
||||
DeviceTree => Language::new_c(),
|
||||
Lisp => Language::new(";", "#|", "|#"),
|
||||
Erlang => Language::new_single("%"),
|
||||
FortranLegacy => Language::new_single("c,C,!,*"),
|
||||
FortranModern => Language::new_single("!"),
|
||||
Go => Language::new_c(),
|
||||
Haskell => Language::new_single("--"),
|
||||
Html => Language::new_html(),
|
||||
Idris => Language::new("--", "{-", "-}"),
|
||||
Jai => Language::new_c(),
|
||||
Java => Language::new_c(),
|
||||
JavaScript => Language::new_c(),
|
||||
Julia => Language::new("#", "#=", "=#"),
|
||||
Json => Language::new_blank(),
|
||||
Jsx => Language::new_c(),
|
||||
Julia => Language::new("#", "#=", "=#"),
|
||||
Kotlin => Language::new_c(),
|
||||
Less => Language::new_c(),
|
||||
LinkerScript => Language::new_c(),
|
||||
Lisp => Language::new(";", "#|", "|#"),
|
||||
Lua => Language::new("--", "--[[", "]]"),
|
||||
Makefile => Language::new_single("#"),
|
||||
Markdown => Language::new_blank(),
|
||||
Mustache => Language::new_multi("{{!", "}}"),
|
||||
Nim => Language::new_single("#"),
|
||||
ObjectiveC => Language::new_c(),
|
||||
ObjectiveCpp => Language::new_c(),
|
||||
OCaml => Language::new_multi("(*", "*)"),
|
||||
Php => Language::new("#,//", "/*", "*/"),
|
||||
OCaml => Language::new_func(),
|
||||
Oz => Language::new_pro(),
|
||||
Pascal => Language::new("//,(*", "{", "}"),
|
||||
Polly => Language::new_html(),
|
||||
Perl => Language::new("#", "=", "=cut"),
|
||||
Php => Language::new("#,//", "/*", "*/"),
|
||||
Polly => Language::new_html(),
|
||||
Prolog => Language::new_pro(),
|
||||
Protobuf => Language::new_single("//"),
|
||||
Python => Language::new("#", "'''", "'''"),
|
||||
Qcl => Language::new_c(),
|
||||
R => Language::new_single("#"),
|
||||
Ruby => Language::new("#", "=begin", "=end"),
|
||||
RubyHtml => Language::new_html(),
|
||||
Rust => Language::new("//,///,//!", "/*", "*/"),
|
||||
Sass => Language::new_c(),
|
||||
Sml => Language::new_multi("(*", "*)"),
|
||||
Sml => Language::new_func(),
|
||||
Sql => Language::new("--", "/*", "*/"),
|
||||
Swift => Language::new_c(),
|
||||
Tex => Language::new_single("%"),
|
||||
Text => Language::new_blank(),
|
||||
Toml => Language::new_single("#"),
|
||||
TypeScript => Language::new_c(),
|
||||
UnrealScript => Language::new_c(),
|
||||
VimScript => Language::new_single("\""),
|
||||
Wolfram => Language::new_func(),
|
||||
Xml => Language::new_html(),
|
||||
Yaml => Language::new_single("#"),
|
||||
Zsh => Language::new_single("#"),
|
||||
|
|
@ -153,129 +155,154 @@ fn main() {
|
|||
get_all_files(paths, &mut languages, ignored_directories);
|
||||
|
||||
let mut total = Language::new_blank();
|
||||
for (name, language) in &mut languages {
|
||||
|
||||
if language.files.len() == 0 {
|
||||
continue;
|
||||
let mut languages: Vec<(LanguageName, Language)> = languages.into_iter().collect();
|
||||
|
||||
let (tx, rx) = channel();
|
||||
let child = thread::spawn(move || {
|
||||
loop {
|
||||
if let Ok(_) = rx.try_recv() {
|
||||
break;
|
||||
}
|
||||
print!("\x1B[?25l");
|
||||
print!(" Counting files. \r");
|
||||
thread::sleep(Duration::from_millis(4));
|
||||
print!(" Counting files..\r");
|
||||
thread::sleep(Duration::from_millis(4));
|
||||
print!(" Counting files...\r");
|
||||
thread::sleep(Duration::from_millis(4));
|
||||
}
|
||||
});
|
||||
|
||||
let (tx, rx) = channel();
|
||||
let child = thread::spawn(move || {
|
||||
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();
|
||||
for file in files {
|
||||
let mut contents = String::new();
|
||||
let is_fortran = *name == FortranModern || *name == FortranLegacy;
|
||||
let mut stats = stats::Stats::new(unwrap_opt_cont!(file.to_str()));
|
||||
let _ = unwrap_rs_cont!(unwrap_rs_cont!(File::open(file))
|
||||
.read_to_string(&mut contents));
|
||||
|
||||
let mut is_in_comments = false;
|
||||
let lines = contents.lines();
|
||||
languages.par_iter_mut()
|
||||
.for_each(|&mut (name, ref mut language)| {
|
||||
if language.files.len() == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if language.is_blank() {
|
||||
stats.code += lines.count();
|
||||
continue;
|
||||
}
|
||||
language.total = language.files.len();
|
||||
let files: Vec<_> = language.files.drain(..).collect();
|
||||
for file in files {
|
||||
let mut contents = String::new();
|
||||
let is_fortran = name == FortranModern || name == FortranLegacy;
|
||||
let mut stats = Stats::new(opt_or_cont!(file.to_str()));
|
||||
let _ = rs_or_cont!(rs_or_cont!(File::open(file))
|
||||
.read_to_string(&mut contents));
|
||||
|
||||
'line: for line in lines {
|
||||
let line = if is_fortran {
|
||||
line
|
||||
} else {
|
||||
line.trim()
|
||||
};
|
||||
stats.lines += 1;
|
||||
|
||||
if line.trim().is_empty() {
|
||||
stats.blanks += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if !language.multi_line.is_empty() {
|
||||
let multi_line = language.multi_line;
|
||||
let multi_line_end = language.multi_line_end;
|
||||
if line.starts_with(multi_line) {
|
||||
is_in_comments = true;
|
||||
} else if contains_comments(line, multi_line, multi_line_end) {
|
||||
stats.code += 1;
|
||||
is_in_comments = true;
|
||||
}
|
||||
}
|
||||
let mut is_in_comments = false;
|
||||
let lines = contents.lines();
|
||||
|
||||
|
||||
if is_in_comments {
|
||||
if line.contains(language.multi_line_end) {
|
||||
is_in_comments = false;
|
||||
}
|
||||
stats.comments += 1;
|
||||
continue;
|
||||
}
|
||||
if language.is_blank() {
|
||||
stats.code += lines.count();
|
||||
continue;
|
||||
}
|
||||
|
||||
let single_comments = language.line_comment.split(',');
|
||||
'line: for line in lines {
|
||||
let line = if is_fortran {
|
||||
line
|
||||
} else {
|
||||
line.trim()
|
||||
};
|
||||
stats.lines += 1;
|
||||
|
||||
for single in single_comments {
|
||||
if line.starts_with(single) {
|
||||
stats.comments += 1;
|
||||
continue 'line;
|
||||
}
|
||||
}
|
||||
stats.code += 1;
|
||||
}
|
||||
if line.trim().is_empty() {
|
||||
stats.blanks += 1;
|
||||
continue 'line;
|
||||
}
|
||||
|
||||
if files_option {
|
||||
println!("{}", stats);
|
||||
}
|
||||
|
||||
*language += stats;
|
||||
}
|
||||
|
||||
let _ = tx.send(());
|
||||
let _ = child.join();
|
||||
print!(" \r");
|
||||
if !language.is_empty() {
|
||||
if let None = sort {
|
||||
if files_option {
|
||||
println!("{}", ROW);
|
||||
println!("{}", language);
|
||||
println!("{}", ROW);
|
||||
} else {
|
||||
println!("{}", language);
|
||||
}
|
||||
}
|
||||
}
|
||||
if !language.multi_line.is_empty() {
|
||||
let multi_line = language.multi_line;
|
||||
let multi_line_end = language.multi_line_end;
|
||||
if line.starts_with(multi_line) {
|
||||
is_in_comments = true;
|
||||
} else if contains_comments(line, multi_line, multi_line_end) {
|
||||
is_in_comments = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if is_in_comments {
|
||||
if line.contains(language.multi_line_end) {
|
||||
is_in_comments = false;
|
||||
}
|
||||
stats.comments += 1;
|
||||
continue 'line;
|
||||
}
|
||||
|
||||
if !language.line_comment.is_empty() {
|
||||
for single in language.line_comment.split(',') {
|
||||
if line.starts_with(single) {
|
||||
stats.comments += 1;
|
||||
continue 'line;
|
||||
}
|
||||
}
|
||||
}
|
||||
stats.code += 1;
|
||||
}
|
||||
|
||||
*language += stats;
|
||||
}
|
||||
|
||||
print!(" \r");
|
||||
if !language.is_empty() {
|
||||
if let None = sort {
|
||||
if files_option {
|
||||
language.print(name);
|
||||
println!("{}", ROW);
|
||||
|
||||
for stat in &language.stats {
|
||||
println!("{}", stat);
|
||||
}
|
||||
println!("{}", ROW);
|
||||
} else {
|
||||
language.print(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
let _ = tx.send(());
|
||||
let _ = child.join();
|
||||
|
||||
for &(_, ref language) in &languages {
|
||||
total += language;
|
||||
}
|
||||
|
||||
if let Some(sort_category) = sort {
|
||||
let mut sorted: Vec<&Language> = languages.values().collect();
|
||||
|
||||
for &mut (_, ref mut language) in &mut languages {
|
||||
match &*sort_category {
|
||||
BLANKS => language.sort_by(BLANKS),
|
||||
COMMENTS => language.sort_by(COMMENTS),
|
||||
CODE => language.sort_by(CODE),
|
||||
FILES => {}
|
||||
TOTAL => language.sort_by(TOTAL),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
match &*sort_category {
|
||||
BLANKS => sorted.sort_by(|a, b| b.blanks.cmp(&a.blanks)),
|
||||
COMMENTS => sorted.sort_by(|a, b| b.comments.cmp(&a.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())),
|
||||
TOTAL => sorted.sort_by(|a, b| b.lines.cmp(&a.lines)),
|
||||
BLANKS => languages.sort_by(|a, b| b.1.blanks.cmp(&a.1.blanks)),
|
||||
COMMENTS => languages.sort_by(|a, b| b.1.comments.cmp(&a.1.comments)),
|
||||
CODE => languages.sort_by(|a, b| b.1.code.cmp(&a.1.code)),
|
||||
FILES => languages.sort_by(|a, b| b.1.files.len().cmp(&a.1.files.len())),
|
||||
TOTAL => languages.sort_by(|a, b| b.1.lines.cmp(&a.1.lines)),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
for language in sorted {
|
||||
for (name, language) in languages {
|
||||
if !language.is_empty() {
|
||||
println!("{}", *language);
|
||||
if !files_option {
|
||||
language.print(name);
|
||||
} else {
|
||||
language.print(name);
|
||||
println!("{}", ROW);
|
||||
for file in &language.stats {
|
||||
println!("{}", file);
|
||||
}
|
||||
println!("{}", ROW);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -283,7 +310,7 @@ fn main() {
|
|||
if !files_option {
|
||||
println!("{}", ROW);
|
||||
}
|
||||
println!("{}", total);
|
||||
total.print(__Total);
|
||||
println!("{}", ROW);
|
||||
println!("\x1B[?25h");
|
||||
print!("\x1B[?25h\r");
|
||||
}
|
||||
|
|
|
|||
10
src/stats.rs
10
src/stats.rs
|
|
@ -1,6 +1,6 @@
|
|||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Default, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||
pub struct Stats {
|
||||
pub name: String,
|
||||
pub code: usize,
|
||||
|
|
@ -12,13 +12,7 @@ pub struct Stats {
|
|||
|
||||
impl Stats {
|
||||
pub fn new<S: Into<String>>(name: S) -> Self {
|
||||
Stats {
|
||||
name: name.into(),
|
||||
code: 0,
|
||||
blanks: 0,
|
||||
lines: 0,
|
||||
comments: 0,
|
||||
}
|
||||
Stats { name: name.into(), ..Self::default() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue