mirror of
https://github.com/XAMPPRocky/tokei
synced 2024-10-01 05:23:37 +00:00
2.1.0 IO
This commit is contained in:
parent
bc83358d82
commit
350cb5f30f
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -6,6 +6,7 @@ dependencies = [
|
|||
"glob 0.2.11 (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)",
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_cbor 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_codegen 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
|
@ -10,7 +10,7 @@ homepage = "https://aaronepower.github.io/tokei/"
|
|||
license = "MIT/Apache-2.0"
|
||||
readme = "README.md"
|
||||
description = "Count code, quickly."
|
||||
build = "src/build.rs"
|
||||
build = "build.rs"
|
||||
|
||||
# For building serde in stable.
|
||||
[build-dependencies]
|
||||
|
@ -33,6 +33,7 @@ clap = {version = "2.5.1", features = ["yaml"]}
|
|||
glob = "0.2.11"
|
||||
maplit = "0.1.3"
|
||||
rayon = "0.3.1"
|
||||
rustc-serialize = "*"
|
||||
serde = "*"
|
||||
serde_cbor = "*"
|
||||
serde_json = "*"
|
||||
|
|
54
cli.yml
54
cli.yml
|
@ -1,49 +1,49 @@
|
|||
# Copyright (c) 2015 Aaron Power
|
||||
# Use of this source code is governed by the APACHE2.0/MIT license that can be
|
||||
# found in the LICENCE-{APACHE/MIT} file.
|
||||
about: Count Code, Quickly.
|
||||
author: Aaron P. <theaaronepower@gmail.com>
|
||||
bin_name: Tokei
|
||||
name: Tokei
|
||||
version: 2.0.0
|
||||
author: Aaron P. <theaaronepower@gmail.com>
|
||||
about: Count Code, Quickly.
|
||||
args:
|
||||
- exclude:
|
||||
short: e
|
||||
long: exclude
|
||||
help: Ignore all files & directories containing the word
|
||||
long: exclude
|
||||
short: e
|
||||
takes_value: true
|
||||
- sort:
|
||||
short: s
|
||||
long: sort
|
||||
- files:
|
||||
help: Will print out statistics on individual files.
|
||||
long: files
|
||||
short: f
|
||||
takes_value: false
|
||||
- file_input:
|
||||
help: "Gives statistics from a previous tokei run."
|
||||
long: input
|
||||
short: i
|
||||
takes_value: true
|
||||
possible_values: [files, total, blanks, code, commments]
|
||||
help: Will sort based on column
|
||||
- input:
|
||||
conflicts_with:
|
||||
- languages
|
||||
help: The input file(s)/directory(ies)
|
||||
index: 1
|
||||
multiple: true
|
||||
required: true
|
||||
help: The input file(s)/directory(ies)
|
||||
conflicts_with:
|
||||
- languages
|
||||
- files:
|
||||
short: f
|
||||
long: files
|
||||
takes_value: false
|
||||
help: Will print out statistics on individual files.
|
||||
- languages:
|
||||
short: l
|
||||
long: languages
|
||||
conflicts_with:
|
||||
- input
|
||||
help: Prints out supported languages and their extensions
|
||||
- file_input:
|
||||
short: i
|
||||
long: input
|
||||
takes_value: true
|
||||
help: "Gives statistics from a previous tokei run."
|
||||
long: languages
|
||||
short: l
|
||||
- output:
|
||||
short: o
|
||||
long: output
|
||||
takes_value: true
|
||||
help: Outputs Tokei in a specific format.
|
||||
long: output
|
||||
possible_values: [cbor, json, yaml]
|
||||
short: o
|
||||
takes_value: true
|
||||
- sort:
|
||||
help: Will sort based on column
|
||||
long: sort
|
||||
possible_values: [files, total, blanks, code, commments]
|
||||
short: s
|
||||
takes_value: true
|
|
@ -1,4 +1,4 @@
|
|||
pub const CLEAR: &'static str = " \r";
|
||||
pub const CLEAR: &'static str = " \r";
|
||||
pub const ROW: &'static str = "-------------------------------------------------------------------------------";
|
||||
pub const BLANKS: &'static str = "blanks";
|
||||
pub const COMMENTS: &'static str = "comments";
|
||||
|
|
146
src/fsutil.rs
146
src/fsutil.rs
|
@ -1,6 +1,6 @@
|
|||
// Copyright (c) 2015 Aaron Power
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
// Use of this source code is governed by the APACHE2.0/MIT licence that can be
|
||||
// found in the LICENCE-{APACHE/MIT} file.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::{BufRead, BufReader};
|
||||
|
@ -8,6 +8,7 @@ use std::fs::File;
|
|||
use std::path::Path;
|
||||
|
||||
use glob::glob;
|
||||
use rustc_serialize::hex::FromHex;
|
||||
use serde_cbor;
|
||||
use serde_json;
|
||||
use serde_yaml;
|
||||
|
@ -17,9 +18,14 @@ use language::Language;
|
|||
use language_name::LanguageName;
|
||||
use language_name::LanguageName::*;
|
||||
|
||||
pub fn contains_comments(file: &str, comment: &str, comment_end: &str) -> bool {
|
||||
/// This is used to catch lines like "let x = 5; /* Comment */"
|
||||
pub fn has_trailing_comments(line: &str,
|
||||
nested: bool,
|
||||
comment: &'static str,
|
||||
comment_end: &'static str)
|
||||
-> bool {
|
||||
let mut in_comments: usize = 0;
|
||||
for chars in file.chars().collect::<Vec<char>>().windows(comment.len()) {
|
||||
for chars in line.chars().collect::<Vec<char>>().windows(comment.len()) {
|
||||
let window = {
|
||||
let mut window = String::new();
|
||||
for ch in chars {
|
||||
|
@ -29,11 +35,17 @@ pub fn contains_comments(file: &str, comment: &str, comment_end: &str) -> bool {
|
|||
};
|
||||
|
||||
if window == comment {
|
||||
in_comments += 1;
|
||||
if nested {
|
||||
in_comments += 1;
|
||||
} else {
|
||||
in_comments = 1;
|
||||
}
|
||||
continue;
|
||||
} else if window == comment_end {
|
||||
if in_comments != 0 {
|
||||
if nested && in_comments != 0 {
|
||||
in_comments -= 1;
|
||||
} else {
|
||||
in_comments = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -42,10 +54,12 @@ pub fn contains_comments(file: &str, comment: &str, comment_end: &str) -> bool {
|
|||
}
|
||||
|
||||
pub fn get_all_files<'a, I: Iterator<Item = &'a str>>(paths: I,
|
||||
ignored_directories: Vec<&str>,
|
||||
languages: &mut BTreeMap<LanguageName,
|
||||
Language>,
|
||||
ignored_directories: Vec<&str>) {
|
||||
Language>) {
|
||||
for path in paths {
|
||||
// A small metadata check to check if the file actually exists, this is used over calling
|
||||
// File::open because we're going to be passing the path to either glob() or WalkDir::new()
|
||||
if let Err(_) = Path::new(path).metadata() {
|
||||
if let Ok(paths) = glob(path) {
|
||||
for path in paths {
|
||||
|
@ -53,13 +67,11 @@ pub fn get_all_files<'a, I: Iterator<Item = &'a str>>(paths: I,
|
|||
let mut language = if opt_or_cont!(path.to_str()).contains("Makefile") {
|
||||
languages.get_mut(&Makefile).unwrap()
|
||||
} else {
|
||||
opt_or_cont!(languages.get_mut(&opt_or_cont!(get_language(&path))))
|
||||
opt_or_cont!(languages.get_mut(&opt_or_cont!(LanguageName::from_extension(&path))))
|
||||
};
|
||||
|
||||
language.files.push(path.to_owned());
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
} else {
|
||||
let walker = WalkDir::new(path).into_iter().filter_entry(|entry| {
|
||||
|
@ -77,7 +89,7 @@ pub fn get_all_files<'a, I: Iterator<Item = &'a str>>(paths: I,
|
|||
let mut language = if opt_or_cont!(entry.path().to_str()).contains("Makefile") {
|
||||
languages.get_mut(&Makefile).unwrap()
|
||||
} else {
|
||||
opt_or_cont!(languages.get_mut(&opt_or_cont!(get_language(entry.path()))))
|
||||
opt_or_cont!(languages.get_mut(&opt_or_cont!(LanguageName::from_extension(entry.path()))))
|
||||
};
|
||||
|
||||
language.files.push(entry.path().to_owned());
|
||||
|
@ -88,23 +100,25 @@ pub fn get_all_files<'a, I: Iterator<Item = &'a str>>(paths: I,
|
|||
|
||||
pub fn get_extension<P: AsRef<Path>>(path: P) -> Option<String> {
|
||||
let path = path.as_ref();
|
||||
let extension = match path.extension() {
|
||||
match path.extension() {
|
||||
Some(extension_os) => {
|
||||
match extension_os.to_str() {
|
||||
Some(ext) => ext,
|
||||
None => return None,
|
||||
Some(extension) => Some(extension.to_lowercase()),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
None => {
|
||||
match get_filetype_from_shebang(path) {
|
||||
Some(ext) => ext,
|
||||
None => return None,
|
||||
// Using String::from here because all file extensions from
|
||||
// get_filetype_from_shebang are guaranteed to be lowercase.
|
||||
Some(extension) => Some(String::from(extension)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
};
|
||||
Some(extension.to_lowercase())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/// This is for getting the file type from the first line of a file
|
||||
pub fn get_filetype_from_shebang<P: AsRef<Path>>(file: P) -> Option<&'static str> {
|
||||
let file = match File::open(file) {
|
||||
Ok(file) => file,
|
||||
|
@ -130,96 +144,16 @@ pub fn get_filetype_from_shebang<P: AsRef<Path>>(file: P) -> Option<&'static str
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_language<P: AsRef<Path>>(entry: P) -> Option<LanguageName> {
|
||||
if let Some(extension) = get_extension(entry) {
|
||||
match &*extension {
|
||||
"as" => Some(ActionScript),
|
||||
"bash" | "sh" => Some(Bash),
|
||||
"bat" | "btm" | "cmd" => Some(Batch),
|
||||
"c" | "ec" | "pgc" => Some(C),
|
||||
"cc" | "cpp" | "cxx" | "c++" | "pcc" => Some(Cpp),
|
||||
"cfc" => Some(ColdFusionScript),
|
||||
"cfm" => Some(ColdFusion),
|
||||
"clj" => Some(Clojure),
|
||||
"coffee" => Some(CoffeeScript),
|
||||
"cs" => Some(CSharp),
|
||||
"csh" => Some(CShell),
|
||||
"css" => Some(Css),
|
||||
"d" => Some(D),
|
||||
"dart" => Some(Dart),
|
||||
"dts" | "dtsi" => Some(DeviceTree),
|
||||
"el" | "lisp" | "lsp" | "sc" => Some(Lisp),
|
||||
"erl" | "hrl" => Some(Erlang),
|
||||
"f" | "for" | "ftn" | "f77" | "pfo" => Some(FortranLegacy),
|
||||
"f03" | "f08" | "f90" | "f95" => Some(FortranModern),
|
||||
"go" => Some(Go),
|
||||
"h" => Some(CHeader),
|
||||
"hh" | "hpp" | "hxx" => Some(CppHeader),
|
||||
"hs" => Some(Haskell),
|
||||
"html" => Some(Html),
|
||||
"idr" | "lidr" => Some(Idris),
|
||||
"jai" => Some(Jai),
|
||||
"java" => Some(Java),
|
||||
"jl" => Some(Julia),
|
||||
"js" => Some(JavaScript),
|
||||
"json" => Some(Json),
|
||||
"jsx" => Some(Jsx),
|
||||
"kt" | "kts" => Some(Kotlin),
|
||||
"lds" => Some(LinkerScript),
|
||||
"less" => Some(Less),
|
||||
"lua" => Some(Lua),
|
||||
"m" => Some(ObjectiveC),
|
||||
"markdown" | "md" => Some(Markdown),
|
||||
"ml" | "mli" => Some(OCaml),
|
||||
"mm" => Some(ObjectiveCpp),
|
||||
"makefile" => Some(Makefile),
|
||||
"mustache" => Some(Mustache),
|
||||
"nim" => Some(Nim),
|
||||
"nb" | "wl" => Some(Wolfram),
|
||||
"oz" => Some(Oz),
|
||||
"p" | "pro" => Some(Prolog),
|
||||
"pas" => Some(Pascal),
|
||||
"php" => Some(Php),
|
||||
"pl" => Some(Perl),
|
||||
"qcl" => Some(Qcl),
|
||||
"text" | "txt" => Some(Text),
|
||||
"polly" => Some(Polly),
|
||||
"proto" => Some(Protobuf),
|
||||
"py" => Some(Python),
|
||||
"r" => Some(R),
|
||||
"rake" | "rb" => Some(Ruby),
|
||||
"rhtml" => Some(RubyHtml),
|
||||
"rs" => Some(Rust),
|
||||
"s" => Some(Assembly),
|
||||
"sass" | "scss" => Some(Sass),
|
||||
"scala" => Some(Scala),
|
||||
"sml" => Some(Sml),
|
||||
"sql" => Some(Sql),
|
||||
"swift" => Some(Swift),
|
||||
"tex" | "sty" => Some(Tex),
|
||||
"toml" => Some(Toml),
|
||||
"ts" => Some(TypeScript),
|
||||
"uc" | "uci" | "upkg" => Some(UnrealScript),
|
||||
"v" => Some(Coq),
|
||||
"vim" => Some(VimScript),
|
||||
"xml" => Some(Xml),
|
||||
"yaml" | "yml" => Some(Yaml),
|
||||
"zsh" => Some(Zsh),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_input(contents: &[u8]) -> Option<BTreeMap<LanguageName, Language>> {
|
||||
/// This originally too a &[u8], but the u8 didn't directly correspond with the hexadecimal u8, so
|
||||
/// it had to be changed to a String, and add the rustc_serialize dependency.
|
||||
pub fn convert_input(contents: String) -> Option<BTreeMap<String, Language>> {
|
||||
if contents.is_empty() {
|
||||
None
|
||||
} else if let Ok(result) = serde_json::from_slice(contents) {
|
||||
} else if let Ok(result) = serde_json::from_str(&*contents) {
|
||||
Some(result)
|
||||
} else if let Ok(result) = serde_yaml::from_slice(contents) {
|
||||
} else if let Ok(result) = serde_yaml::from_str(&*contents) {
|
||||
Some(result)
|
||||
} else if let Ok(result) = serde_cbor::from_slice(contents) {
|
||||
} else if let Ok(result) = serde_cbor::from_slice(&*contents.from_hex().unwrap()) {
|
||||
Some(result)
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
// Copyright (c) 2015 Aaron Power
|
||||
// Use of this source code is governed by the MIT/APACHE2.0 license that can be
|
||||
// found in the LICENCE-{APACHE - MIT} file.
|
||||
|
||||
/**
|
||||
Hello world
|
||||
/**
|
||||
Hi
|
||||
*/
|
||||
Hello */
|
||||
use std::path::PathBuf;
|
||||
use std::ops::AddAssign;
|
||||
|
||||
|
@ -14,49 +19,46 @@ pub struct Language {
|
|||
pub blanks: usize,
|
||||
pub code: usize,
|
||||
pub comments: usize,
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
#[serde(skip_deserializing, skip_serializing)]
|
||||
pub files: Vec<PathBuf>,
|
||||
pub stats: Vec<Stats>,
|
||||
pub lines: usize,
|
||||
#[serde(skip_deserializing,skip_serializing, rename(serialize="lineComment"))]
|
||||
pub line_comment: &'static str,
|
||||
#[serde(skip_deserializing,skip_serializing, rename(serialize="multiLine"))]
|
||||
pub multi_line: &'static str,
|
||||
#[serde(skip_deserializing,skip_serializing, rename(serialize="multiLineEnd"))]
|
||||
pub multi_line_end: &'static str,
|
||||
#[serde(skip_deserializing, skip_serializing)]
|
||||
pub line_comment: Vec<&'static str>,
|
||||
#[serde(skip_deserializing, skip_serializing)]
|
||||
pub multi_line: Vec<(&'static str, &'static str)>,
|
||||
#[serde(skip_deserializing, skip_serializing)]
|
||||
pub nested: bool,
|
||||
pub total_files: usize,
|
||||
}
|
||||
|
||||
impl Language {
|
||||
pub fn new(line_comment: &'static str,
|
||||
multi_line: &'static str,
|
||||
multi_line_end: &'static str)
|
||||
pub fn new(line_comment: Vec<&'static str>,
|
||||
multi_line: Vec<(&'static str, &'static str)>)
|
||||
-> Self {
|
||||
|
||||
Language {
|
||||
line_comment: line_comment,
|
||||
multi_line: multi_line,
|
||||
multi_line_end: multi_line_end,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nested(mut self) -> Self {
|
||||
self.nested = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn new_c() -> Self {
|
||||
Language {
|
||||
line_comment: "//",
|
||||
multi_line: "/*",
|
||||
multi_line_end: "*/",
|
||||
line_comment: vec!["//"],
|
||||
multi_line: vec![("/*", "*/")],
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_html() -> Self {
|
||||
Language {
|
||||
line_comment: "<!--",
|
||||
multi_line: "<!--",
|
||||
multi_line_end: "-->",
|
||||
..Self::default()
|
||||
}
|
||||
Language { multi_line: vec![("<!--", "-->")], ..Self::default() }
|
||||
}
|
||||
|
||||
pub fn new_blank() -> Self {
|
||||
|
@ -64,43 +66,35 @@ impl Language {
|
|||
}
|
||||
|
||||
pub fn new_func() -> Self {
|
||||
Language {
|
||||
multi_line: "(*",
|
||||
multi_line_end: "*)",
|
||||
..Self::default()
|
||||
}
|
||||
Language { multi_line: vec![("(*", "*)")], ..Self::default() }
|
||||
}
|
||||
|
||||
pub fn new_hash() -> Self {
|
||||
Self::new_single("#")
|
||||
Self::new_single(vec!["#"])
|
||||
}
|
||||
|
||||
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 new_multi(multi_line: Vec<(&'static str, &'static str)>) -> Self {
|
||||
Language { multi_line: multi_line, ..Self::default() }
|
||||
}
|
||||
|
||||
pub fn new_pro() -> Self {
|
||||
Language {
|
||||
line_comment: "%",
|
||||
multi_line: "/*",
|
||||
multi_line_end: "*/",
|
||||
line_comment: vec!["%"],
|
||||
multi_line: vec![("/*", "*/")],
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_single(line_comment: &'static str) -> Self {
|
||||
pub fn new_single(line_comment: Vec<&'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
|
||||
}
|
||||
|
||||
pub fn is_blank(&self) -> bool {
|
||||
self.line_comment == "" && self.multi_line == ""
|
||||
self.line_comment.is_empty() && self.multi_line.is_empty()
|
||||
}
|
||||
|
||||
pub fn sort_by(&mut self, category: &str) {
|
||||
|
@ -154,7 +148,6 @@ impl<'a> AddAssign<&'a mut Language> for Language {
|
|||
}
|
||||
}
|
||||
|
||||
// Adding a file to the language.
|
||||
impl AddAssign<Stats> for Language {
|
||||
fn add_assign(&mut self, rhs: Stats) {
|
||||
self.lines += rhs.lines;
|
||||
|
@ -164,13 +157,3 @@ impl AddAssign<Stats> for Language {
|
|||
self.stats.push(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
// impl AddAssign<BTreeMap<LanguageName, Language>> for BTreeMap<LanguageName, Language> {
|
||||
// fn add_assign(&mut self, rhs: BTreeMap<LanguageName, Language>) {
|
||||
// for (name, rhs_language) in rhs {
|
||||
// if let Some(language) = self.get_mut(name) {
|
||||
// language += rhs_language;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
use std::fmt;
|
||||
use std::path::Path;
|
||||
|
||||
use fsutil::*;
|
||||
use self::LanguageName::*;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
|
||||
pub enum LanguageName {
|
||||
|
@ -28,6 +32,7 @@ pub enum LanguageName {
|
|||
Haskell,
|
||||
Html,
|
||||
Idris,
|
||||
Isabelle,
|
||||
Jai,
|
||||
Java,
|
||||
JavaScript,
|
||||
|
@ -79,8 +84,6 @@ pub enum LanguageName {
|
|||
|
||||
impl LanguageName {
|
||||
pub fn name(&self) -> &'static str {
|
||||
use self::LanguageName::*;
|
||||
|
||||
match *self {
|
||||
ActionScript => "ActionScript",
|
||||
Assembly => "Assembly",
|
||||
|
@ -108,6 +111,7 @@ impl LanguageName {
|
|||
Haskell => "Haskell",
|
||||
Html => "HTML",
|
||||
Idris => "Idris",
|
||||
Isabelle => "Isabelle",
|
||||
Jai => "JAI",
|
||||
Java => "Java",
|
||||
JavaScript => "JavaScript",
|
||||
|
@ -157,6 +161,169 @@ impl LanguageName {
|
|||
__Total => "Total",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_extension<P: AsRef<Path>>(entry: P) -> Option<Self> {
|
||||
if let Some(extension) = get_extension(entry) {
|
||||
match &*extension {
|
||||
"as" => Some(ActionScript),
|
||||
"bash" | "sh" => Some(Bash),
|
||||
"bat" | "btm" | "cmd" => Some(Batch),
|
||||
"c" | "ec" | "pgc" => Some(C),
|
||||
"cc" | "cpp" | "cxx" | "c++" | "pcc" => Some(Cpp),
|
||||
"cfc" => Some(ColdFusionScript),
|
||||
"cfm" => Some(ColdFusion),
|
||||
"clj" => Some(Clojure),
|
||||
"coffee" => Some(CoffeeScript),
|
||||
"cs" => Some(CSharp),
|
||||
"csh" => Some(CShell),
|
||||
"css" => Some(Css),
|
||||
"d" => Some(D),
|
||||
"dart" => Some(Dart),
|
||||
"dts" | "dtsi" => Some(DeviceTree),
|
||||
"el" | "lisp" | "lsp" => Some(Lisp),
|
||||
"erl" | "hrl" => Some(Erlang),
|
||||
"f" | "for" | "ftn" | "f77" | "pfo" => Some(FortranLegacy),
|
||||
"f03" | "f08" | "f90" | "f95" => Some(FortranModern),
|
||||
"go" => Some(Go),
|
||||
"h" => Some(CHeader),
|
||||
"hh" | "hpp" | "hxx" => Some(CppHeader),
|
||||
"hs" => Some(Haskell),
|
||||
"html" => Some(Html),
|
||||
"idr" | "lidr" => Some(Idris),
|
||||
"jai" => Some(Jai),
|
||||
"java" => Some(Java),
|
||||
"jl" => Some(Julia),
|
||||
"js" => Some(JavaScript),
|
||||
"json" => Some(Json),
|
||||
"jsx" => Some(Jsx),
|
||||
"kt" | "kts" => Some(Kotlin),
|
||||
"lds" => Some(LinkerScript),
|
||||
"less" => Some(Less),
|
||||
"lua" => Some(Lua),
|
||||
"m" => Some(ObjectiveC),
|
||||
"markdown" | "md" => Some(Markdown),
|
||||
"ml" | "mli" => Some(OCaml),
|
||||
"mm" => Some(ObjectiveCpp),
|
||||
"makefile" => Some(Makefile),
|
||||
"mustache" => Some(Mustache),
|
||||
"nim" => Some(Nim),
|
||||
"nb" | "wl" => Some(Wolfram),
|
||||
"oz" => Some(Oz),
|
||||
"p" | "pro" => Some(Prolog),
|
||||
"pas" => Some(Pascal),
|
||||
"php" => Some(Php),
|
||||
"pl" => Some(Perl),
|
||||
"qcl" => Some(Qcl),
|
||||
"text" | "txt" => Some(Text),
|
||||
"polly" => Some(Polly),
|
||||
"proto" => Some(Protobuf),
|
||||
"py" => Some(Python),
|
||||
"r" => Some(R),
|
||||
"rake" | "rb" => Some(Ruby),
|
||||
"rhtml" => Some(RubyHtml),
|
||||
"rs" | "in" => Some(Rust),
|
||||
"s" => Some(Assembly),
|
||||
"sass" | "scss" => Some(Sass),
|
||||
"sc" | "scala" => Some(Scala),
|
||||
"sml" => Some(Sml),
|
||||
"sql" => Some(Sql),
|
||||
"swift" => Some(Swift),
|
||||
"tex" | "sty" => Some(Tex),
|
||||
"toml" => Some(Toml),
|
||||
"ts" => Some(TypeScript),
|
||||
"thy" => Some(Isabelle),
|
||||
"uc" | "uci" | "upkg" => Some(UnrealScript),
|
||||
"v" => Some(Coq),
|
||||
"vim" => Some(VimScript),
|
||||
"xml" => Some(Xml),
|
||||
"yaml" | "yml" => Some(Yaml),
|
||||
"zsh" => Some(Zsh),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for LanguageName {
|
||||
fn from(from: String) -> Self {
|
||||
match &*from {
|
||||
"ActionScript" => ActionScript,
|
||||
"Assembly" => Assembly,
|
||||
"Bash" => Bash,
|
||||
"Batch" => Batch,
|
||||
"C" => C,
|
||||
"CHeader" => CHeader,
|
||||
"Clojure" => Clojure,
|
||||
"CoffeeScript" => CoffeeScript,
|
||||
"ColdFusion" => ColdFusion,
|
||||
"ColdFusionScript" => ColdFusionScript,
|
||||
"Coq" => Coq,
|
||||
"Cpp" => Cpp,
|
||||
"CppHeader" => CppHeader,
|
||||
"CSharp" => CSharp,
|
||||
"CShell" => CShell,
|
||||
"Css" => Css,
|
||||
"D" => D,
|
||||
"Dart" => Dart,
|
||||
"DeviceTree" => DeviceTree,
|
||||
"Erlang" => Erlang,
|
||||
"FortranLegacy" => FortranLegacy,
|
||||
"FortranModern" => FortranModern,
|
||||
"Go" => Go,
|
||||
"Haskell" => Haskell,
|
||||
"Html" => Html,
|
||||
"Idris" => Idris,
|
||||
"Jai" => Jai,
|
||||
"Java" => Java,
|
||||
"JavaScript" => JavaScript,
|
||||
"Julia" => Julia,
|
||||
"Json" => Json,
|
||||
"Jsx" => Jsx,
|
||||
"Kotlin" => Kotlin,
|
||||
"Less" => Less,
|
||||
"LinkerScript" => LinkerScript,
|
||||
"Lisp" => Lisp,
|
||||
"Lua" => Lua,
|
||||
"Makefile" => Makefile,
|
||||
"Markdown" => Markdown,
|
||||
"Mustache" => Mustache,
|
||||
"Nim" => Nim,
|
||||
"ObjectiveC" => ObjectiveC,
|
||||
"ObjectiveCpp" => ObjectiveCpp,
|
||||
"OCaml" => OCaml,
|
||||
"Oz" => Oz,
|
||||
"Pascal" => Pascal,
|
||||
"Perl" => Perl,
|
||||
"Polly" => Polly,
|
||||
"Php" => Php,
|
||||
"Protobuf" => Protobuf,
|
||||
"Prolog" => Prolog,
|
||||
"Python" => Python,
|
||||
"Qcl" => Qcl,
|
||||
"R" => R,
|
||||
"Ruby" => Ruby,
|
||||
"RubyHtml" => RubyHtml,
|
||||
"Rust" => Rust,
|
||||
"Sass" => Sass,
|
||||
"Scala" => Scala,
|
||||
"Sml" => Sml,
|
||||
"Sql" => Sql,
|
||||
"Swift" => Swift,
|
||||
"Tex" => Tex,
|
||||
"Text" => Text,
|
||||
"Toml" => Toml,
|
||||
"TypeScript" => TypeScript,
|
||||
"VimScript" => VimScript,
|
||||
"UnrealScript" => UnrealScript,
|
||||
"Wolfram" => Wolfram,
|
||||
"Xml" => Xml,
|
||||
"Yaml" => Yaml,
|
||||
"Zsh" => Zsh,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for LanguageName {
|
||||
|
|
|
@ -4,6 +4,7 @@ extern crate glob;
|
|||
#[macro_use]
|
||||
extern crate maplit;
|
||||
extern crate rayon;
|
||||
extern crate rustc_serialize;
|
||||
extern crate serde;
|
||||
extern crate serde_cbor;
|
||||
extern crate serde_json;
|
||||
|
|
140
src/main.rs.in
140
src/main.rs.in
|
@ -10,6 +10,7 @@ mod language;
|
|||
mod language_name;
|
||||
mod stats;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::thread;
|
||||
|
@ -22,13 +23,15 @@ use rayon::prelude::*;
|
|||
use consts::*;
|
||||
use fsutil::*;
|
||||
use language::Language;
|
||||
use language_name::LanguageName;
|
||||
use language_name::LanguageName::*;
|
||||
use stats::Stats;
|
||||
|
||||
fn main() {
|
||||
// Get options at the beginning, so the program doesn't have to make any extra calls to get the
|
||||
// information, and there isn't any magic strings.
|
||||
let yaml = load_yaml!("../cli.yml");
|
||||
let matches = App::from_yaml(yaml).get_matches();
|
||||
|
||||
let files_option = matches.is_present(FILES);
|
||||
let input_option = matches.value_of("file_input");
|
||||
let output_option = matches.value_of("output");
|
||||
|
@ -49,14 +52,14 @@ fn main() {
|
|||
// by default.
|
||||
let mut languages = btreemap! {
|
||||
ActionScript => Language::new_c(),
|
||||
Assembly => Language::new_single(";"),
|
||||
Assembly => Language::new_single(vec![";"]),
|
||||
Bash => Language::new_hash(),
|
||||
Batch => Language::new_single("REM"),
|
||||
Batch => Language::new_single(vec!["REM"]),
|
||||
C => Language::new_c(),
|
||||
CHeader => Language::new_c(),
|
||||
Clojure => Language::new_single(";,#,#_"),
|
||||
CoffeeScript => Language::new("#", "###", "###"),
|
||||
ColdFusion => Language::new_multi("<!---", "--->"),
|
||||
Clojure => Language::new_single(vec![";","#"]),
|
||||
CoffeeScript => Language::new(vec!["#"], vec![("###", "###")]),
|
||||
ColdFusion => Language::new_multi(vec![("<!---", "--->")]),
|
||||
ColdFusionScript => Language::new_c(),
|
||||
Coq => Language::new_func(),
|
||||
Cpp => Language::new_c(),
|
||||
|
@ -67,61 +70,62 @@ fn main() {
|
|||
D => Language::new_c(),
|
||||
Dart => Language::new_c(),
|
||||
DeviceTree => Language::new_c(),
|
||||
Erlang => Language::new_single("%"),
|
||||
FortranLegacy => Language::new_single("c,C,!,*"),
|
||||
FortranModern => Language::new_single("!"),
|
||||
Erlang => Language::new_single(vec!["%"]),
|
||||
FortranLegacy => Language::new_single(vec!["c","C","!","*"]),
|
||||
FortranModern => Language::new_single(vec!["!"]),
|
||||
Go => Language::new_c(),
|
||||
Haskell => Language::new_single("--"),
|
||||
Haskell => Language::new_single(vec!["--"]),
|
||||
Html => Language::new_html(),
|
||||
Idris => Language::new("--", "{-", "-}"),
|
||||
Idris => Language::new(vec!["--"], vec![("{-", "-}")]),
|
||||
Isabelle => Language::new(vec!["--"], vec![("{*","*}"), ("(*","*)"), ("‹","›"), ("\\<open>", "\\<close>")]),
|
||||
Jai => Language::new_c(),
|
||||
Java => Language::new_c(),
|
||||
JavaScript => Language::new_c(),
|
||||
Json => Language::new_blank(),
|
||||
Jsx => Language::new_c(),
|
||||
Julia => Language::new("#", "#=", "=#"),
|
||||
Julia => Language::new(vec!["#"], vec![("#=", "=#")]),
|
||||
Kotlin => Language::new_c(),
|
||||
Less => Language::new_c(),
|
||||
LinkerScript => Language::new_c(),
|
||||
Lisp => Language::new(";", "#|", "|#"),
|
||||
Lua => Language::new("--", "--[[", "]]"),
|
||||
Lisp => Language::new(vec![";"], vec![("#|", "|#")]),
|
||||
Lua => Language::new(vec!["--"], vec![("--[[", "]]")]),
|
||||
Makefile => Language::new_hash(),
|
||||
Markdown => Language::new_blank(),
|
||||
Mustache => Language::new_multi("{{!", "}}"),
|
||||
Mustache => Language::new_multi(vec![("{{!", "}}")]),
|
||||
Nim => Language::new_hash(),
|
||||
ObjectiveC => Language::new_c(),
|
||||
ObjectiveCpp => Language::new_c(),
|
||||
OCaml => Language::new_func(),
|
||||
Oz => Language::new_pro(),
|
||||
Pascal => Language::new("//,(*", "{", "}"),
|
||||
Perl => Language::new("#", "=", "=cut"),
|
||||
Php => Language::new("#,//", "/*", "*/"),
|
||||
Pascal => Language::new(vec!["//","(*"], vec![("{", "}")]),
|
||||
Perl => Language::new(vec!["#"], vec![("=", "=cut")]),
|
||||
Php => Language::new(vec!["#","//"], vec![("/*", "*/")]),
|
||||
Polly => Language::new_html(),
|
||||
Prolog => Language::new_pro(),
|
||||
Protobuf => Language::new_single("//"),
|
||||
Python => Language::new("#", "'''", "'''"),
|
||||
Protobuf => Language::new_single(vec!["//"]),
|
||||
Python => Language::new(vec!["#"], vec![("'''", "'''")]),
|
||||
Qcl => Language::new_c(),
|
||||
R => Language::new_hash(),
|
||||
Ruby => Language::new("#", "=begin", "=end"),
|
||||
Ruby => Language::new(vec!["#"], vec![("=begin", "=end")]),
|
||||
RubyHtml => Language::new_html(),
|
||||
Rust => Language::new("//,///,//!", "/*", "*/"),
|
||||
Rust => Language::new_c().nested(),
|
||||
Sass => Language::new_c(),
|
||||
Scala => Language::new_c(),
|
||||
Sml => Language::new_func(),
|
||||
Sql => Language::new("--", "/*", "*/"),
|
||||
Sql => Language::new(vec!["--"], vec![("/*", "*/")]),
|
||||
Swift => Language::new_c(),
|
||||
Tex => Language::new_single("%"),
|
||||
Tex => Language::new_single(vec!["%"]),
|
||||
Text => Language::new_blank(),
|
||||
Toml => Language::new_hash(),
|
||||
TypeScript => Language::new_c(),
|
||||
UnrealScript => Language::new_c(),
|
||||
VimScript => Language::new_single("\""),
|
||||
VimScript => Language::new_single(vec!["\""]),
|
||||
Wolfram => Language::new_func(),
|
||||
Xml => Language::new_html(),
|
||||
Yaml => Language::new_hash(),
|
||||
Zsh => Language::new_hash(),
|
||||
};
|
||||
|
||||
// Print every supported language.
|
||||
if language_option {
|
||||
for key in languages.keys() {
|
||||
println!("{:<25}", key);
|
||||
|
@ -130,38 +134,38 @@ fn main() {
|
|||
}
|
||||
|
||||
if let Some(input) = input_option {
|
||||
let res = match File::open(input) {
|
||||
let deserded_map = match File::open(input) {
|
||||
Ok(mut file) => {
|
||||
let contents = {
|
||||
let mut contents = Vec::new();
|
||||
file.read_to_end(&mut contents).unwrap();
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
contents
|
||||
};
|
||||
|
||||
convert_input(&contents)
|
||||
convert_input(contents)
|
||||
}
|
||||
Err(_) => {
|
||||
|
||||
if input == "stdin" {
|
||||
let mut stdin = std::io::stdin();
|
||||
let mut buffer = Vec::new();
|
||||
let mut buffer = String::new();
|
||||
|
||||
let _ = stdin.read_to_string(&mut buffer);
|
||||
convert_input(&buffer)
|
||||
convert_input(buffer)
|
||||
} else {
|
||||
convert_input(&input.to_bytes())
|
||||
convert_input(String::from(input))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(res) = res {
|
||||
for (name, res_language) in res {
|
||||
if let Some(language) = languages.get_mut(&name) {
|
||||
*language += res_language;
|
||||
if let Some(deserded_map) = deserded_map {
|
||||
for (name, input_language) in deserded_map {
|
||||
if let Some(language) = languages.get_mut(&LanguageName::from(name)) {
|
||||
*language += input_language;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("Input provided wasn't a path, or valid CBOR, JSON, or YAML.");
|
||||
println!("Input provided wasn't a path, or valid CBOR, JSON, or YAML.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,7 +181,7 @@ fn main() {
|
|||
println!("{}", ROW);
|
||||
}
|
||||
|
||||
get_all_files(paths, &mut languages, ignored_directories);
|
||||
get_all_files(paths, ignored_directories, &mut languages);
|
||||
|
||||
let mut total = Language::new_blank();
|
||||
|
||||
|
@ -215,6 +219,8 @@ fn main() {
|
|||
for file in files {
|
||||
let mut contents = String::new();
|
||||
let mut is_in_comments = false;
|
||||
let mut comment_start = "";
|
||||
let mut depth: usize = 0;
|
||||
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));
|
||||
|
@ -240,30 +246,39 @@ fn main() {
|
|||
continue;
|
||||
}
|
||||
|
||||
if !language.multi_line.is_empty() {
|
||||
let multi_line = language.multi_line;
|
||||
let multi_line_end = language.multi_line_end;
|
||||
for &(multi_line, multi_line_end) in &language.multi_line {
|
||||
if line.starts_with(multi_line) ||
|
||||
contains_comments(line, multi_line, multi_line_end) {
|
||||
has_trailing_comments(line, language.nested, multi_line, multi_line_end) {
|
||||
comment_start = multi_line;
|
||||
is_in_comments = true;
|
||||
if language.nested {
|
||||
depth += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if is_in_comments {
|
||||
if line.contains(language.multi_line_end) {
|
||||
is_in_comments = false;
|
||||
for &(multi_line, multi_line_end) in &language.multi_line {
|
||||
if multi_line == comment_start && line.contains(multi_line_end) {
|
||||
if language.nested {
|
||||
depth -= 1;
|
||||
if depth == 0 {
|
||||
is_in_comments = false;
|
||||
}
|
||||
} else {
|
||||
is_in_comments = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
stats.comments += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if !language.line_comment.is_empty() {
|
||||
for single in language.line_comment.split(',') {
|
||||
if line.starts_with(single) {
|
||||
stats.comments += 1;
|
||||
continue 'line;
|
||||
}
|
||||
for single in &language.line_comment {
|
||||
if line.starts_with(single) {
|
||||
stats.comments += 1;
|
||||
continue 'line;
|
||||
}
|
||||
}
|
||||
stats.code += 1;
|
||||
|
@ -272,7 +287,9 @@ fn main() {
|
|||
*language += stats;
|
||||
}
|
||||
|
||||
print!("{}", CLEAR);
|
||||
if output_option == None {
|
||||
print!("{}", CLEAR);
|
||||
}
|
||||
if !language.is_empty() {
|
||||
if sort_option == None && output_option == None {
|
||||
if files_option {
|
||||
|
@ -302,17 +319,24 @@ fn main() {
|
|||
|
||||
if let Some(format) = output_option {
|
||||
|
||||
let mut lang_map = BTreeMap::new();
|
||||
|
||||
for (key, value) in languages {
|
||||
if !value.is_empty() {
|
||||
lang_map.insert(format!("{:?}", key), value);
|
||||
}
|
||||
}
|
||||
|
||||
match &*format {
|
||||
"cbor" => {
|
||||
let cbor: Vec<_> = serde_cbor::to_vec(&languages).unwrap();
|
||||
let cbor: Vec<_> = serde_cbor::to_vec(&lang_map).unwrap();
|
||||
|
||||
for byte in cbor {
|
||||
print!("{:02x}", byte);
|
||||
}
|
||||
println!("");
|
||||
}
|
||||
"json" => println!("{}", serde_json::to_string(&languages).unwrap()),
|
||||
"yaml" => println!("{}", serde_yaml::to_string(&languages).unwrap()),
|
||||
"json" => print!("{}", serde_json::to_string(&lang_map).unwrap()),
|
||||
"yaml" => print!("{}", serde_yaml::to_string(&lang_map).unwrap()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else if let Some(sort_category) = sort_option {
|
||||
|
@ -359,6 +383,6 @@ fn main() {
|
|||
}
|
||||
total.print(__Total);
|
||||
println!("{}", ROW);
|
||||
print!("\x1B[?25h\r");
|
||||
}
|
||||
print!("\x1B[?25h\r");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue