ICE error

This commit is contained in:
Aaronepower 2016-05-20 12:44:24 +01:00
parent 77c52b4aea
commit bc83358d82
11 changed files with 808 additions and 552 deletions

158
Cargo.lock generated
View File

@ -6,6 +6,12 @@ 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)",
"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)",
"serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_yaml 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -14,11 +20,24 @@ name = "ansi_term"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "aster"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"syntex_syntax 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.5.1"
@ -60,11 +79,48 @@ name = "libc"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "log"
version = "0.3.6"
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"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-iter"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "num_cpus"
version = "0.2.12"
@ -73,6 +129,24 @@ dependencies = [
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quasi"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"syntex_syntax 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quasi_codegen"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aster 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex_syntax 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.3.14"
@ -91,16 +165,100 @@ dependencies = [
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-serialize"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_cbor"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_codegen"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aster 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
"quasi 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"quasi_codegen 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex_syntax 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_yaml"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 0.7.5 (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 = "strsim"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syntex"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"syntex_syntax 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syntex_syntax"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"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)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "term"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.5 (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 = "unicode-xid"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.6.0"

View File

@ -10,16 +10,31 @@ homepage = "https://aaronepower.github.io/tokei/"
license = "MIT/Apache-2.0"
readme = "README.md"
description = "Count code, quickly."
build = "src/build.rs"
[profile.dev]
debug = true
[profile.release]
opt-level = 3
# For building serde in stable.
[build-dependencies]
serde_codegen = "*"
syntex = "*"
# Dependencies, and why they are used.
# - Clap: For CLI argument parsing.
# - Glob: When a user passes in a ./*.rs path.
# - Maplit: Cleaner initialization of the language map.
# - Rayon: Parallelization of language analysation.
# - Rustc-serialize: Converting String to hex, for CBOR.
# - Serde: Converting Language struct to other formats.
# - Serde_cbor: To CBOR. http://cbor.io/
# - Serde_json: To JSON. http://json.org/
# - Serde_yaml: To YAML. http://yaml.org/
# - Walkdir: Handling recursively reading directories across Windows, OSX, and UNIX.
[dependencies]
clap = {version = "2.5.1", features = ["yaml"]}
glob = "0.2.11"
maplit = "0.1.3"
walkdir = "0.1.5"
rayon = "0.3.1"
serde = "*"
serde_cbor = "*"
serde_json = "*"
serde_yaml = "*"
walkdir = "0.1.5"

View File

@ -40,10 +40,10 @@ args:
short: i
long: input
takes_value: true
help: "Gives statistics for Tokei to start with Accepted formats: JSON"
help: "Gives statistics from a previous tokei run."
- output:
short: o
long: output
takes_value: true
help: Outputs Tokei in a specific format.
possible_values: [csv, json, xml, yml]
possible_values: [cbor, json, yaml]

17
src/build.rs Normal file
View File

@ -0,0 +1,17 @@
extern crate syntex;
extern crate serde_codegen;
use std::env;
use std::path::Path;
pub fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let src = Path::new("src/main.rs.in");
let dst = Path::new(&out_dir).join("main.rs");
let mut registry = syntex::Registry::new();
serde_codegen::register(&mut registry);
registry.expand("", &src, &dst).unwrap();
}

View File

@ -1,3 +1,4 @@
pub const CLEAR: &'static str = " \r";
pub const ROW: &'static str = "-------------------------------------------------------------------------------";
pub const BLANKS: &'static str = "blanks";
pub const COMMENTS: &'static str = "comments";

View File

@ -6,11 +6,16 @@ use std::collections::BTreeMap;
use std::io::{BufRead, BufReader};
use std::fs::File;
use std::path::Path;
use glob::glob;
use serde_cbor;
use serde_json;
use serde_yaml;
use walkdir::{WalkDir, WalkDirIterator};
use language::{Language, LanguageName};
use language::LanguageName::*;
use language::Language;
use language_name::LanguageName;
use language_name::LanguageName::*;
pub fn contains_comments(file: &str, comment: &str, comment_end: &str) -> bool {
let mut in_comments: usize = 0;
@ -129,112 +134,76 @@ pub fn get_language<P: AsRef<Path>>(entry: P) -> Option<LanguageName> {
if let Some(extension) = get_extension(entry) {
match &*extension {
"as" => Some(ActionScript),
"bash" => Some(Bash),
"bat" => Some(Batch),
"btm" => Some(Batch),
"c" => Some(C),
"cc" => Some(Cpp),
"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),
"cmd" => Some(Batch),
"coffee" => Some(CoffeeScript),
"cs" => Some(CSharp),
"csh" => Some(CShell),
"css" => Some(Css),
"cpp" => Some(Cpp),
"cxx" => Some(Cpp),
"c++" => Some(Cpp),
"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),
"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" => Some(CppHeader),
"hpp" => Some(CppHeader),
"hrl" => Some(Erlang),
"hh" | "hpp" | "hxx" => Some(CppHeader),
"hs" => Some(Haskell),
"html" => Some(Html),
"hxx" => Some(CppHeader),
"idr" => Some(Idris),
"idr" | "lidr" => 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),
"kt" | "kts" => Some(Kotlin),
"lds" => Some(LinkerScript),
"less" => Some(Less),
"lidr" => Some(Idris),
"lisp" => Some(Lisp),
"lsp" => Some(Lisp),
"lua" => Some(Lua),
"m" => Some(ObjectiveC),
"markdown" => Some(Markdown),
"md" => Some(Markdown),
"ml" => Some(OCaml),
"mli" => Some(OCaml),
"markdown" | "md" => Some(Markdown),
"ml" | "mli" => Some(OCaml),
"mm" => Some(ObjectiveCpp),
"makefile" => Some(Makefile),
"mustache" => Some(Mustache),
"nim" => Some(Nim),
"nb" => Some(Wolfram),
"nb" | "wl" => Some(Wolfram),
"oz" => Some(Oz),
"p" => Some(Prolog),
"p" | "pro" => 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),
"text" | "txt" => Some(Text),
"polly" => Some(Polly),
"proto" => Some(Protobuf),
"py" => Some(Python),
"r" => Some(R),
"rake" => Some(Ruby),
"rb" => Some(Ruby),
"rake" | "rb" => Some(Ruby),
"rhtml" => Some(RubyHtml),
"rs" => Some(Rust),
"s" => Some(Assembly),
"sass" => Some(Sass),
"sc" => Some(Lisp),
"scss" => Some(Sass),
"sass" | "scss" => Some(Sass),
"scala" => Some(Scala),
"sh" => Some(Bash),
"sml" => Some(Sml),
"sql" => Some(Sql),
"swift" => Some(Swift),
"tex" => Some(Tex),
"sty" => Some(Tex),
"tex" | "sty" => Some(Tex),
"toml" => Some(Toml),
"ts" => Some(TypeScript),
"uc" => Some(UnrealScript),
"uci" => Some(UnrealScript),
"upkg" => Some(UnrealScript),
"uc" | "uci" | "upkg" => Some(UnrealScript),
"v" => Some(Coq),
"vim" => Some(VimScript),
"wl" => Some(Wolfram),
"xml" => Some(Xml),
"yaml" => Some(Yaml),
"yml" => Some(Yaml),
"yaml" | "yml" => Some(Yaml),
"zsh" => Some(Zsh),
_ => None,
}
@ -243,6 +212,20 @@ pub fn get_language<P: AsRef<Path>>(entry: P) -> Option<LanguageName> {
}
}
pub fn convert_input(contents: &[u8]) -> Option<BTreeMap<LanguageName, Language>> {
if contents.is_empty() {
None
} else if let Ok(result) = serde_json::from_slice(contents) {
Some(result)
} else if let Ok(result) = serde_yaml::from_slice(contents) {
Some(result)
} else if let Ok(result) = serde_cbor::from_slice(contents) {
Some(result)
} else {
None
}
}
#[allow(dead_code, unused_imports)]
mod tests {
use super::*;

View File

@ -2,23 +2,27 @@
// 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::fmt;
use std::path::PathBuf;
use std::ops::AddAssign;
use consts::*;
use language_name::LanguageName;
use stats::Stats;
#[derive(Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
#[derive(Debug, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Language {
pub blanks: usize,
pub code: usize,
pub comments: usize,
#[serde(skip_serializing, skip_deserializing)]
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,
pub total_files: usize,
}
@ -56,7 +60,7 @@ impl Language {
}
pub fn new_blank() -> Self {
Language { ..Self::default() }
Self::default()
}
pub fn new_func() -> Self {
@ -120,10 +124,18 @@ impl Language {
}
}
// Adding languages to the raw total_files.
impl<'a> AddAssign<&'a Language> for Language {
fn add_assign(&mut self, rhs: &Self) {
impl AddAssign for Language {
fn add_assign(&mut self, rhs: Self) {
self.total_files += rhs.total_files;
self.lines += rhs.lines;
self.comments += rhs.comments;
self.blanks += rhs.blanks;
self.code += rhs.code;
}
}
impl<'a> AddAssign<&'a Language> for Language {
fn add_assign(&mut self, rhs: &'a Self) {
self.total_files += rhs.total_files;
self.lines += rhs.lines;
self.comments += rhs.comments;
@ -132,7 +144,6 @@ impl<'a> AddAssign<&'a Language> for Language {
}
}
// Adding languages to the raw total_files.
impl<'a> AddAssign<&'a mut Language> for Language {
fn add_assign(&mut self, rhs: &mut Self) {
self.total_files += rhs.total_files;
@ -154,168 +165,12 @@ impl AddAssign<Stats> for Language {
}
}
#[derive(Debug, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
pub enum LanguageName {
ActionScript,
Assembly,
Bash,
Batch,
C,
CHeader,
Clojure,
CoffeeScript,
ColdFusion,
ColdFusionScript,
Coq,
Cpp,
CppHeader,
CSharp,
CShell,
Css,
D,
Dart,
DeviceTree,
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,
Oz,
Pascal,
Perl,
Polly,
Php,
Protobuf,
Prolog,
Python,
Qcl,
R,
Ruby,
RubyHtml,
Rust,
Sass,
Scala,
Sml,
Sql,
Swift,
Tex,
Text,
Toml,
TypeScript,
VimScript,
UnrealScript,
Wolfram,
Xml,
Yaml,
Zsh,
__Total,
}
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",
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",
Erlang => "Erlang",
FortranLegacy => "FORTRAN Legacy",
FortranModern => "FORTRAN Modern",
Go => "Go",
Haskell => "Haskell",
Html => "HTML",
Idris => "Idris",
Jai => "JAI",
Java => "Java",
JavaScript => "JavaScript",
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",
Oz => "Oz",
Pascal => "Pascal",
Perl => "Perl",
Polly => "Polly",
Php => "PHP",
Protobuf => "Protocol Buffers",
Prolog => "Prolog",
Python => "Python",
Qcl => "QCL",
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",
UnrealScript => "Unreal Script",
VimScript => "Vim Script",
Wolfram => "Wolfram",
Xml => "XML",
Yaml => "YAML",
Zsh => "Zsh",
__Total => "Total",
}
}
}
impl fmt::Display for LanguageName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name())
}
}
// 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;
// }
// }
// }
// }

166
src/language_name.rs Normal file
View File

@ -0,0 +1,166 @@
use std::fmt;
#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub enum LanguageName {
ActionScript,
Assembly,
Bash,
Batch,
C,
CHeader,
Clojure,
CoffeeScript,
ColdFusion,
ColdFusionScript,
Coq,
Cpp,
CppHeader,
CSharp,
CShell,
Css,
D,
Dart,
DeviceTree,
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,
Oz,
Pascal,
Perl,
Polly,
Php,
Protobuf,
Prolog,
Python,
Qcl,
R,
Ruby,
RubyHtml,
Rust,
Sass,
Scala,
Sml,
Sql,
Swift,
Tex,
Text,
Toml,
TypeScript,
VimScript,
UnrealScript,
Wolfram,
Xml,
Yaml,
Zsh,
__Total,
}
impl LanguageName {
pub fn name(&self) -> &'static str {
use self::LanguageName::*;
match *self {
ActionScript => "ActionScript",
Assembly => "Assembly",
Bash => "BASH",
Batch => "Batch",
C => "C",
CHeader => "C Header",
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",
Erlang => "Erlang",
FortranLegacy => "FORTRAN Legacy",
FortranModern => "FORTRAN Modern",
Go => "Go",
Haskell => "Haskell",
Html => "HTML",
Idris => "Idris",
Jai => "JAI",
Java => "Java",
JavaScript => "JavaScript",
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",
Oz => "Oz",
Pascal => "Pascal",
Perl => "Perl",
Polly => "Polly",
Php => "PHP",
Protobuf => "Protocol Buffers",
Prolog => "Prolog",
Python => "Python",
Qcl => "QCL",
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",
UnrealScript => "Unreal Script",
VimScript => "Vim Script",
Wolfram => "Wolfram",
Xml => "XML",
Yaml => "YAML",
Zsh => "Zsh",
__Total => "Total",
}
}
}
impl fmt::Display for LanguageName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name())
}
}

View File

@ -1,316 +1,13 @@
// 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.
#[macro_use]
extern crate clap;
extern crate glob;
#[macro_use]
extern crate maplit;
extern crate glob;
extern crate walkdir;
extern crate rayon;
#[macro_use]
mod macros;
mod consts;
mod fsutil;
mod language;
mod stats;
extern crate serde;
extern crate serde_cbor;
extern crate serde_json;
extern crate serde_yaml;
extern crate walkdir;
use std::io::Read;
use std::fs::File;
use std::thread;
use std::time::Duration;
use std::sync::mpsc::channel;
use clap::App;
use rayon::prelude::*;
use consts::*;
use fsutil::*;
use language::{Language, LanguageName};
use language::LanguageName::*;
use stats::Stats;
fn main() {
let yaml = load_yaml!("../cli.yml");
let matches = App::from_yaml(yaml).get_matches();
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 mut languages = btreemap! {
ActionScript => Language::new_c(),
Assembly => Language::new_single(";"),
Bash => Language::new_hash(),
Batch => Language::new_single("REM"),
C => Language::new_c(),
CHeader => Language::new_c(),
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_hash(),
Css => Language::new_c(),
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("!"),
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(),
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_hash(),
Markdown => Language::new_blank(),
Mustache => Language::new_multi("{{!", "}}"),
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("#,//", "/*", "*/"),
Polly => Language::new_html(),
Prolog => Language::new_pro(),
Protobuf => Language::new_single("//"),
Python => Language::new("#", "'''", "'''"),
Qcl => Language::new_c(),
R => Language::new_hash(),
Ruby => Language::new("#", "=begin", "=end"),
RubyHtml => Language::new_html(),
Rust => Language::new("//,///,//!", "/*", "*/"),
Sass => Language::new_c(),
Sml => Language::new_func(),
Sql => Language::new("--", "/*", "*/"),
Swift => Language::new_c(),
Tex => Language::new_single("%"),
Text => Language::new_blank(),
Toml => Language::new_hash(),
TypeScript => Language::new_c(),
UnrealScript => Language::new_c(),
VimScript => Language::new_single("\""),
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);
}
return;
}
let paths = matches.values_of("input").unwrap();
let ignored_directories = {
let mut ignored_directories = vec![".git"];
if let Some(user_ignored) = matches.values_of("exclude") {
for ignored in user_ignored {
ignored_directories.push(ignored);
}
}
ignored_directories
};
let sort = if let Some(sort_by) = matches.value_of("sort") {
match &*sort_by.to_lowercase() {
BLANKS | CODE | COMMENTS | FILES | TOTAL => Some(sort_by.to_lowercase()),
_ => unreachable!(),
}
} else {
None
};
println!("{}", ROW);
println!(" {:<12} {:>12} {:>12} {:>12} {:>12} {:>12}",
"Language",
"Files",
"Lines",
"Code",
"Comments",
"Blanks");
println!("{}", ROW);
get_all_files(paths, &mut languages, ignored_directories);
let mut total = Language::new_blank();
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));
}
});
languages.par_iter_mut()
.for_each(|&mut (name, ref mut language)| {
if language.files.is_empty() {
return;
}
language.total_files = 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));
let mut is_in_comments = false;
let lines = contents.lines();
if language.is_blank() {
stats.code += lines.count();
continue;
}
'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 'line;
}
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) ||
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 {
if !language.is_empty() {
total += language;
}
}
if let Some(sort_category) = sort {
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 => 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 (name, language) in languages {
if !language.is_empty() {
if !files_option {
language.print(name);
} else {
language.print(name);
println!("{}", ROW);
for file in &language.stats {
println!("{}", file);
}
println!("{}", ROW);
}
}
}
}
if !files_option {
println!("{}", ROW);
}
total.print(__Total);
println!("{}", ROW);
print!("\x1B[?25h\r");
}
include!(concat!(env!("OUT_DIR"), "/main.rs"));

364
src/main.rs.in Normal file
View File

@ -0,0 +1,364 @@
// 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.
#[macro_use]
mod macros;
mod consts;
mod fsutil;
mod language;
mod language_name;
mod stats;
use std::fs::File;
use std::io::Read;
use std::thread;
use std::time::Duration;
use std::sync::mpsc::channel;
use clap::App;
use rayon::prelude::*;
use consts::*;
use fsutil::*;
use language::Language;
use language_name::LanguageName::*;
use stats::Stats;
fn main() {
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");
let language_option = matches.is_present("languages");
let sort_option = matches.value_of("sort");
let paths = matches.values_of("input").unwrap();
let ignored_directories = {
let mut ignored_directories = vec![".git"];
if let Some(user_ignored) = matches.values_of("exclude") {
for ignored in user_ignored {
ignored_directories.push(ignored);
}
}
ignored_directories
};
// Languages are placed inside a BTreeMap over a HashMap, in order to be printed alphabetically
// by default.
let mut languages = btreemap! {
ActionScript => Language::new_c(),
Assembly => Language::new_single(";"),
Bash => Language::new_hash(),
Batch => Language::new_single("REM"),
C => Language::new_c(),
CHeader => Language::new_c(),
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_hash(),
Css => Language::new_c(),
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("!"),
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(),
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_hash(),
Markdown => Language::new_blank(),
Mustache => Language::new_multi("{{!", "}}"),
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("#,//", "/*", "*/"),
Polly => Language::new_html(),
Prolog => Language::new_pro(),
Protobuf => Language::new_single("//"),
Python => Language::new("#", "'''", "'''"),
Qcl => Language::new_c(),
R => Language::new_hash(),
Ruby => Language::new("#", "=begin", "=end"),
RubyHtml => Language::new_html(),
Rust => Language::new("//,///,//!", "/*", "*/"),
Sass => Language::new_c(),
Sml => Language::new_func(),
Sql => Language::new("--", "/*", "*/"),
Swift => Language::new_c(),
Tex => Language::new_single("%"),
Text => Language::new_blank(),
Toml => Language::new_hash(),
TypeScript => Language::new_c(),
UnrealScript => Language::new_c(),
VimScript => Language::new_single("\""),
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);
}
return;
}
if let Some(input) = input_option {
let res = match File::open(input) {
Ok(mut file) => {
let contents = {
let mut contents = Vec::new();
file.read_to_end(&mut contents).unwrap();
contents
};
convert_input(&contents)
}
Err(_) => {
if input == "stdin" {
let mut stdin = std::io::stdin();
let mut buffer = Vec::new();
let _ = stdin.read_to_string(&mut buffer);
convert_input(&buffer)
} else {
convert_input(&input.to_bytes())
}
}
};
if let Some(res) = res {
for (name, res_language) in res {
if let Some(language) = languages.get_mut(&name) {
*language += res_language;
}
}
} else {
panic!("Input provided wasn't a path, or valid CBOR, JSON, or YAML.");
}
}
if output_option == None {
println!("{}", ROW);
println!(" {:<12} {:>12} {:>12} {:>12} {:>12} {:>12}",
"Language",
"Files",
"Lines",
"Code",
"Comments",
"Blanks");
println!("{}", ROW);
}
get_all_files(paths, &mut languages, ignored_directories);
let mut total = Language::new_blank();
let mut languages: Vec<_> = languages.into_iter().collect();
let print_animation = output_option == None;
let (tx, rx) = channel();
let child = thread::spawn(move || {
loop {
if let Ok(_) = rx.try_recv() {
break;
}
if print_animation {
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));
}
}
});
languages.par_iter_mut().for_each(|&mut (name, ref mut language)| {
if language.files.is_empty() {
return;
}
language.total_files = language.files.len();
let is_fortran = name == FortranModern || name == FortranLegacy;
let files: Vec<_> = language.files.drain(..).collect();
for file in files {
let mut contents = String::new();
let mut is_in_comments = false;
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));
let lines = contents.lines();
if language.is_blank() {
stats.code += lines.count();
continue;
}
'line: for line in lines {
// FORTRAN has a rule where it only counts as a comment if it's the first character
// in the column, so removing starting whitespace could cause a miscount.
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) ||
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;
}
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!("{}", CLEAR);
if !language.is_empty() {
if sort_option == None && output_option == None {
if files_option {
language.print(name);
println!("{}", ROW);
for stat in &language.stats {
println!("{}", stat);
}
println!("{}", ROW);
} else if output_option == None {
language.print(name);
}
}
}
});
let _ = tx.send(());
let _ = child.join();
for &(_, ref language) in &languages {
if !language.is_empty() {
total += language;
}
}
if let Some(format) = output_option {
match &*format {
"cbor" => {
let cbor: Vec<_> = serde_cbor::to_vec(&languages).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()),
_ => unreachable!(),
}
} else if let Some(sort_category) = sort_option {
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 => 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 (name, language) in languages {
if !language.is_empty() {
if !files_option {
language.print(name);
} else {
language.print(name);
println!("{}", ROW);
for file in &language.stats {
println!("{}", file);
}
println!("{}", ROW);
}
}
}
}
if output_option == None {
if !files_option {
println!("{}", ROW);
}
total.print(__Total);
println!("{}", ROW);
}
print!("\x1B[?25h\r");
}

View File

@ -1,6 +1,6 @@
use std::fmt;
#[derive(Default, Debug, Eq, Ord, PartialEq, PartialOrd)]
#[derive(Default, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Stats {
pub name: String,
pub code: usize,