This commit is contained in:
Aaron Power 2016-05-22 18:07:16 +01:00
parent bc83358d82
commit 350cb5f30f
10 changed files with 355 additions and 244 deletions

1
Cargo.lock generated
View file

@ -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)",

View file

@ -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
View file

@ -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

View file

@ -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";

View file

@ -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

View file

@ -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;
// }
// }
// }
// }

View file

@ -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 {

View file

@ -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;

View file

@ -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");
}