mirror of
https://github.com/XAMPPRocky/tokei
synced 2024-10-05 23:39:28 +00:00
moved functions to fsutil, and switched from RefCell to an Enum based system
This commit is contained in:
parent
db2060e0f2
commit
ebee004a8f
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -1,6 +1,6 @@
|
|||
[root]
|
||||
name = "tokei"
|
||||
version = "1.5.1"
|
||||
version = "1.6.0"
|
||||
dependencies = [
|
||||
"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)",
|
||||
|
|
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
|
||||
// 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 {
|
||||
let mut in_comments: usize = 0;
|
||||
'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
|
||||
}
|
||||
|
||||
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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -48,4 +254,24 @@ mod tests {
|
|||
fn comment_start_in_line() {
|
||||
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::ops::AddAssign;
|
||||
use stats::Stats;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Language<'a> {
|
||||
pub name: &'a str,
|
||||
pub line_comment: &'a str,
|
||||
pub multi_line: &'a str,
|
||||
pub multi_line_end: &'a str,
|
||||
#[derive(Debug, Default, Clone, Eq, Ord, PartialEq, PartialOrd)]
|
||||
pub struct Language {
|
||||
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,
|
||||
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> {
|
||||
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,
|
||||
Language {
|
||||
line_comment: line_comment,
|
||||
multi_line: multi_line,
|
||||
multi_line_end: multi_line_end,
|
||||
..Self::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_raw(name: &'a str) -> Self {
|
||||
Language { name: name, ..Self::default() }
|
||||
}
|
||||
|
||||
pub fn new_c(name: &'a str) -> RefCell<Self> {
|
||||
RefCell::new(Language {
|
||||
name: name,
|
||||
pub fn new_c() -> Self {
|
||||
Language {
|
||||
line_comment: "//",
|
||||
multi_line: "/*",
|
||||
multi_line_end: "*/",
|
||||
..Self::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_html(name: &'a str) -> RefCell<Self> {
|
||||
RefCell::new(Language {
|
||||
name: name,
|
||||
pub fn new_html() -> Self {
|
||||
Language {
|
||||
line_comment: "<!--",
|
||||
multi_line: "<!--",
|
||||
multi_line_end: "-->",
|
||||
..Self::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_blank(name: &'a str) -> RefCell<Self> {
|
||||
RefCell::new(Language { name: name, ..Self::default() })
|
||||
pub fn new_blank() -> Self {
|
||||
Language { ..Self::default() }
|
||||
}
|
||||
|
||||
pub fn new_single(name: &'a str, line_comment: &'a str) -> RefCell<Self> {
|
||||
RefCell::new(Language {
|
||||
name: name,
|
||||
line_comment: line_comment,
|
||||
..Self::default()
|
||||
})
|
||||
pub fn new_single(line_comment: &'static str) -> Self {
|
||||
Language { line_comment: line_comment, ..Self::default() }
|
||||
}
|
||||
|
||||
pub fn new_multi(name: &'a str, multi_line: &'a str, multi_line_end: &'a str) -> RefCell<Self> {
|
||||
RefCell::new(Language {
|
||||
name: name,
|
||||
pub fn new_multi(multi_line: &'static str, multi_line_end: &'static str) -> Self {
|
||||
Language {
|
||||
multi_line: multi_line,
|
||||
multi_line_end: multi_line_end,
|
||||
..Self::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
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 {
|
||||
let total = if self.total == 0 {
|
||||
self.files.len()
|
||||
|
@ -99,7 +89,7 @@ impl<'a> fmt::Display for Language<'a> {
|
|||
};
|
||||
write!(f,
|
||||
" {: <18} {: >6} {:>12} {:>12} {:>12} {:>12}",
|
||||
self.name,
|
||||
"CHANGE",
|
||||
total,
|
||||
self.lines,
|
||||
self.blanks,
|
||||
|
@ -107,8 +97,9 @@ impl<'a> fmt::Display for Language<'a> {
|
|||
self.code)
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
self.total += rhs.files.len();
|
||||
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.
|
||||
impl<'a> AddAssign<Stats> for Language<'a> {
|
||||
impl AddAssign<Stats> for Language {
|
||||
fn add_assign(&mut self, rhs: Stats) {
|
||||
self.lines += rhs.lines;
|
||||
self.code += rhs.code;
|
||||
|
@ -127,3 +129,147 @@ impl<'a> AddAssign<Stats> for Language<'a> {
|
|||
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::collections::BTreeMap;
|
||||
use std::io::{BufRead, BufReader, Read};
|
||||
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;
|
||||
use fsutil::*;
|
||||
use language::{Language, LanguageName};
|
||||
use language::LanguageName::*;
|
||||
|
||||
use fsutil::contains_comments;
|
||||
const ROW: &'static str = "-----------------------------------------------------------------------\
|
||||
--------";
|
||||
const BLANKS: &'static str = "blanks";
|
||||
|
@ -39,170 +43,78 @@ fn main() {
|
|||
let yaml = load_yaml!("../cli.yml");
|
||||
let matches = App::from_yaml(yaml).get_matches();
|
||||
|
||||
let action_script = Language::new_c("ActionScript");
|
||||
let asm = Language::new_single("Assembly", ";");
|
||||
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", "#");
|
||||
let files_option = matches.is_present(FILES);
|
||||
let language_option = matches.is_present("languages");
|
||||
|
||||
// Languages are placed inside a BTreeMap, in order to print alphabetically by default
|
||||
let languages = btreemap! {
|
||||
"as" => &action_script,
|
||||
"s" => &asm,
|
||||
"bat" => &batch,
|
||||
"btm" => &batch,
|
||||
"cmd" => &batch,
|
||||
"bash" => &bash,
|
||||
"sh" => &bash,
|
||||
"c" => &c,
|
||||
"csh" => &c_shell,
|
||||
"ec" => &c,
|
||||
"pgc" => &c,
|
||||
"cs" => &c_sharp,
|
||||
"clj" => &clojure,
|
||||
"coffee" => &coffee_script,
|
||||
"cfm" => &cold_fusion,
|
||||
"cfc" => &cf_script,
|
||||
"cc" => &cpp,
|
||||
"cpp" => &cpp,
|
||||
"cxx" => &cpp,
|
||||
"pcc" => &cpp,
|
||||
"c++" => &cpp,
|
||||
"css" => &css,
|
||||
"d" => &d,
|
||||
"dart" => &dart,
|
||||
"dts" => &device_tree,
|
||||
"dtsi" => &device_tree,
|
||||
"el" => &lisp,
|
||||
"lisp" => &lisp,
|
||||
"lsp" => &lisp,
|
||||
"lua" => &lua,
|
||||
"sc" => &lisp,
|
||||
"f" => &fortran_legacy,
|
||||
"f77" => &fortran_legacy,
|
||||
"for" => &fortran_legacy,
|
||||
"ftn" => &fortran_legacy,
|
||||
"pfo" => &fortran_legacy,
|
||||
"f90" => &fortran_modern,
|
||||
"f95" => &fortran_modern,
|
||||
"f03" => &fortran_modern,
|
||||
"f08" => &fortran_modern,
|
||||
"go" => &go,
|
||||
"h" => &c_header,
|
||||
"hs" => &haskell,
|
||||
"hpp" => &cpp_header,
|
||||
"hh" => &cpp_header,
|
||||
"html" => &html,
|
||||
"hxx" => &cpp_header,
|
||||
"jai" => &jai,
|
||||
"java" => &java,
|
||||
"js" => &java_script,
|
||||
"jl" => &julia,
|
||||
"json" => &json,
|
||||
"jsx" => &jsx,
|
||||
"lds" => &linker_script,
|
||||
"less" => &less,
|
||||
"m" => &objective_c,
|
||||
"md" => &markdown,
|
||||
"markdown" => &markdown,
|
||||
"ml" => &ocaml,
|
||||
"mli" => &ocaml,
|
||||
"mm" => &objective_cpp,
|
||||
"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,
|
||||
let mut languages = btreemap! {
|
||||
ActionScript => Language::new_c(),
|
||||
Assembly => Language::new_single(";"),
|
||||
Bash => Language::new_single("#"),
|
||||
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(),
|
||||
Cpp => Language::new_c(),
|
||||
CppHeader => Language::new_c(),
|
||||
Css => Language::new_c(),
|
||||
D => Language::new_c(),
|
||||
Dart => Language::new_c(),
|
||||
DeviceTree => Language::new_c(),
|
||||
Lisp => Language::new(";", "#|", "|#"),
|
||||
FortranLegacy => Language::new_single("c,C,!,*"),
|
||||
FortranModern => Language::new_single("!"),
|
||||
Go => Language::new_c(),
|
||||
Haskell => Language::new_single("--"),
|
||||
Html => Language::new_html(),
|
||||
Jai => Language::new_c(),
|
||||
Java => Language::new_c(),
|
||||
JavaScript => Language::new_c(),
|
||||
Julia => Language::new("#", "#=", "=#"),
|
||||
Json => Language::new_blank(),
|
||||
Jsx => Language::new_c(),
|
||||
Less => Language::new_c(),
|
||||
LinkerScript => Language::new_c(),
|
||||
Lua => Language::new("--", "--[[", "]]"),
|
||||
Makefile => Language::new_single("#"),
|
||||
Markdown => Language::new_blank(),
|
||||
Mustache => Language::new_multi("{{!", "}}"),
|
||||
ObjectiveC => Language::new_c(),
|
||||
ObjectiveCpp => Language::new_c(),
|
||||
OCaml => Language::new_multi("(*", "*)"),
|
||||
Php => Language::new("#,//", "/*", "*/"),
|
||||
Pascal => Language::new("//,(*", "{", "}"),
|
||||
Polly => Language::new_html(),
|
||||
Perl => Language::new("#", "=", "=cut"),
|
||||
Protobuf => Language::new_single("//"),
|
||||
Python => Language::new("#", "'''", "'''"),
|
||||
R => Language::new_single("#"),
|
||||
Ruby => Language::new("#", "=begin", "=end"),
|
||||
RubyHtml => Language::new_html(),
|
||||
Rust => Language::new("//,///,//!", "/*", "*/"),
|
||||
Sass => Language::new_c(),
|
||||
Sml => Language::new_multi("(*", "*)"),
|
||||
Sql => Language::new("--", "/*", "*/"),
|
||||
Swift => Language::new_c(),
|
||||
Tex => Language::new_single("%"),
|
||||
Text => Language::new_blank(),
|
||||
Toml => Language::new_single("#"),
|
||||
TypeScript => Language::new_c(),
|
||||
VimScript => Language::new_single("\""),
|
||||
Xml => Language::new_html(),
|
||||
Yaml => Language::new_single("#"),
|
||||
Zsh => Language::new_single("#"),
|
||||
};
|
||||
|
||||
// Print every supported language.
|
||||
if matches.is_present("languages") {
|
||||
for language in languages.values() {
|
||||
let mut language = language.borrow_mut();
|
||||
if !language.printed {
|
||||
println!("{:<25}", language.name);
|
||||
language.printed = true;
|
||||
}
|
||||
if language_option {
|
||||
for key in languages.keys() {
|
||||
println!("{:<25}", key);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -210,10 +122,10 @@ fn main() {
|
|||
let paths = matches.values_of("input").unwrap();
|
||||
|
||||
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") {
|
||||
for ignored in user_ignored {
|
||||
ignored_directories.push(ignored.to_owned());
|
||||
ignored_directories.push(ignored);
|
||||
}
|
||||
}
|
||||
ignored_directories
|
||||
|
@ -238,25 +150,35 @@ fn main() {
|
|||
"Code");
|
||||
println!("{}", ROW);
|
||||
|
||||
get_all_files(paths, &languages, ignored_directories);
|
||||
get_all_files(paths, &mut languages, ignored_directories);
|
||||
|
||||
let mut total = Language::new_raw("Total");
|
||||
for language_ref in languages.values() {
|
||||
let mut language = language_ref.borrow_mut();
|
||||
let mut total = Language::new_blank();
|
||||
for (name, language) in &mut languages {
|
||||
|
||||
if language.printed {
|
||||
if language.files.len() == 0 {
|
||||
continue;
|
||||
}
|
||||
let is_blank_lang = if language.line_comment == "" && language.multi_line == "" {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
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 = language.name.contains("FORTRAN");
|
||||
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));
|
||||
|
@ -265,7 +187,7 @@ fn main() {
|
|||
let lines = contents.lines();
|
||||
|
||||
|
||||
if is_blank_lang {
|
||||
if language.is_blank() {
|
||||
stats.code += lines.count();
|
||||
continue;
|
||||
}
|
||||
|
@ -314,149 +236,54 @@ fn main() {
|
|||
stats.code += 1;
|
||||
}
|
||||
|
||||
if matches.is_present(FILES) {
|
||||
if files_option {
|
||||
println!("{}", stats);
|
||||
}
|
||||
|
||||
*language += stats;
|
||||
}
|
||||
|
||||
let _ = tx.send(());
|
||||
let _ = child.join();
|
||||
print!(" \r");
|
||||
if !language.is_empty() {
|
||||
language.printed = true;
|
||||
if let None = sort {
|
||||
if matches.is_present(FILES) {
|
||||
if files_option {
|
||||
println!("{}", ROW);
|
||||
println!("{}", *language);
|
||||
println!("{}", language);
|
||||
println!("{}", ROW);
|
||||
} else {
|
||||
println!("{}", *language);
|
||||
println!("{}", language);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
total += &*language;
|
||||
|
||||
total += language;
|
||||
}
|
||||
|
||||
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 {
|
||||
BLANKS => unsorted_vec.sort_by(|a, b| b.1.borrow().blanks.cmp(&a.1.borrow().blanks)),
|
||||
COMMENTS => {
|
||||
unsorted_vec.sort_by(|a, b| b.1.borrow().comments.cmp(&a.1.borrow().comments))
|
||||
}
|
||||
CODE => unsorted_vec.sort_by(|a, b| b.1.borrow().code.cmp(&a.1.borrow().code)),
|
||||
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)),
|
||||
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)),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
for (_, language) in unsorted_vec {
|
||||
|
||||
if !language.borrow().is_empty() && language.borrow().printed {
|
||||
language.borrow_mut().printed = false;
|
||||
println!("{}", *language.borrow());
|
||||
for language in sorted {
|
||||
if !language.is_empty() {
|
||||
println!("{}", *language);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !matches.is_present(FILES) {
|
||||
if !files_option {
|
||||
println!("{}", ROW);
|
||||
}
|
||||
println!("{}", total);
|
||||
println!("{}", ROW);
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
println!("\x1B[?25h");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue