From bc83358d820a8912bd9f3b9fe1c33e3aacf301d2 Mon Sep 17 00:00:00 2001 From: Aaronepower Date: Fri, 20 May 2016 12:44:24 +0100 Subject: [PATCH] ICE error --- Cargo.lock | 158 +++++++++++++++++++ Cargo.toml | 27 +++- cli.yml | 4 +- src/build.rs | 17 ++ src/consts.rs | 1 + src/fsutil.rs | 103 +++++------- src/language.rs | 201 ++++-------------------- src/language_name.rs | 166 ++++++++++++++++++++ src/main.rs | 317 +------------------------------------ src/main.rs.in | 364 +++++++++++++++++++++++++++++++++++++++++++ src/stats.rs | 2 +- 11 files changed, 808 insertions(+), 552 deletions(-) create mode 100644 src/build.rs create mode 100644 src/language_name.rs create mode 100644 src/main.rs.in diff --git a/Cargo.lock b/Cargo.lock index d964c59..6a7493b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 9436363..1b821c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/cli.yml b/cli.yml index 7ff3d22..c29b519 100644 --- a/cli.yml +++ b/cli.yml @@ -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] diff --git a/src/build.rs b/src/build.rs new file mode 100644 index 0000000..a0053ab --- /dev/null +++ b/src/build.rs @@ -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(); +} diff --git a/src/consts.rs b/src/consts.rs index d45e6b5..96c4907 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -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"; diff --git a/src/fsutil.rs b/src/fsutil.rs index beacb31..56df452 100644 --- a/src/fsutil.rs +++ b/src/fsutil.rs @@ -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>(entry: P) -> Option { 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>(entry: P) -> Option { } } +pub fn convert_input(contents: &[u8]) -> Option> { + 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::*; diff --git a/src/language.rs b/src/language.rs index c806683..b5bc49b 100644 --- a/src/language.rs +++ b/src/language.rs @@ -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, pub stats: Vec, 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 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> for BTreeMap { +// fn add_assign(&mut self, rhs: BTreeMap) { +// for (name, rhs_language) in rhs { +// if let Some(language) = self.get_mut(name) { +// language += rhs_language; +// } +// } +// } +// } diff --git a/src/language_name.rs b/src/language_name.rs new file mode 100644 index 0000000..6446e7d --- /dev/null +++ b/src/language_name.rs @@ -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()) + } +} diff --git a/src/main.rs b/src/main.rs index 4763f16..9d8fcf2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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")); diff --git a/src/main.rs.in b/src/main.rs.in new file mode 100644 index 0000000..fe5f46e --- /dev/null +++ b/src/main.rs.in @@ -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"); +} diff --git a/src/stats.rs b/src/stats.rs index 65c3f29..fe972f2 100644 --- a/src/stats.rs +++ b/src/stats.rs @@ -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,