mirror of
https://github.com/XAMPPRocky/tokei
synced 2024-10-01 05:23:37 +00:00
version 5: optimised stats, language generation
This commit is contained in:
parent
5e11c4852f
commit
c08f113c2d
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
tests/data/* linguist-documentation
|
24
Cargo.lock
generated
24
Cargo.lock
generated
|
@ -1,18 +1,18 @@
|
||||||
[root]
|
[root]
|
||||||
name = "tokei"
|
name = "tokei"
|
||||||
version = "4.5.4"
|
version = "5.0.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 2.19.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.19.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"errln 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"errln 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"handlebars 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"handlebars 0.24.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ignore 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ignore 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"maplit 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"maplit 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rayon 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_cbor 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_cbor 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -171,14 +171,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "handlebars"
|
name = "handlebars"
|
||||||
version = "0.21.1"
|
version = "0.24.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"serde_json 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -251,7 +252,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "0.2.13"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -282,11 +283,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "0.4.2"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -577,7 +579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum errln 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba822d3275762d55fd527b698dcf8f233a488885ea5e75c683fb5fd94af946"
|
"checksum errln 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba822d3275762d55fd527b698dcf8f233a488885ea5e75c683fb5fd94af946"
|
||||||
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
|
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
|
||||||
"checksum globset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a9853491e657bd919f5a7e7c3dd1dfcdd2ba674b4d2465c042be2bfb36b642d9"
|
"checksum globset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a9853491e657bd919f5a7e7c3dd1dfcdd2ba674b4d2465c042be2bfb36b642d9"
|
||||||
"checksum handlebars 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "937e9d49d65ffb5f70e95710a6c8539addf40200275ad8b6cdba0f0a59d5814d"
|
"checksum handlebars 0.24.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd60b0a45ee5f649490244d804b1e8ead7687493938325211b4825761ea06ef5"
|
||||||
"checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa"
|
"checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa"
|
||||||
"checksum ignore 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "038e0fe6111065719d5ae5b724284d9505be4bbe6195f3418b1ba98995b9e181"
|
"checksum ignore 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "038e0fe6111065719d5ae5b724284d9505be4bbe6195f3418b1ba98995b9e181"
|
||||||
"checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1"
|
"checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1"
|
||||||
|
@ -588,12 +590,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum maplit 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "be384c560e0c3ad868b590ffb88d2c0a1effde6f59885234e4ea811c1202bfea"
|
"checksum maplit 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "be384c560e0c3ad868b590ffb88d2c0a1effde6f59885234e4ea811c1202bfea"
|
||||||
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
||||||
"checksum num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a16a42856a256b39c6d3484f097f6713e14feacd9bfb02290917904fae46c81c"
|
"checksum num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a16a42856a256b39c6d3484f097f6713e14feacd9bfb02290917904fae46c81c"
|
||||||
"checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3"
|
"checksum num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "55aabf4e2d6271a2e4e4c0f2ea1f5b07cc589cc1a9e9213013b54a76678ca4f3"
|
||||||
"checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8"
|
"checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8"
|
||||||
"checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c"
|
"checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c"
|
||||||
"checksum quote 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)" = "6732e32663c9c271bfc7c1823486b471f18c47a2dbf87c066897b7b51afc83be"
|
"checksum quote 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)" = "6732e32663c9c271bfc7c1823486b471f18c47a2dbf87c066897b7b51afc83be"
|
||||||
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
|
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
|
||||||
"checksum rayon 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "655df67c314c30fa3055a365eae276eb88aa4f3413a352a1ab32c1320eda41ea"
|
"checksum rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50c575b58c2b109e2fbc181820cbe177474f35610ff9e357dc75f6bac854ffbf"
|
||||||
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
|
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
|
||||||
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
|
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
|
||||||
"checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b"
|
"checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b"
|
||||||
|
|
55
Cargo.toml
55
Cargo.toml
|
@ -8,67 +8,70 @@ license = "MIT/Apache-2.0"
|
||||||
name = "tokei"
|
name = "tokei"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/Aaronepower/tokei.git"
|
repository = "https://github.com/Aaronepower/tokei.git"
|
||||||
version = "4.5.4"
|
version = "5.0.3"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
panic="abort"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
serde = "~0.8.19"
|
serde = "0.8"
|
||||||
serde_json = "~0.8.4"
|
serde_json = "0.8"
|
||||||
errln = "0.1.0"
|
errln = "0.1"
|
||||||
|
|
||||||
[build-dependencies.handlebars]
|
[build-dependencies.handlebars]
|
||||||
features = ["serde_type"]
|
features = ["serde_type"]
|
||||||
version = "0.21.1"
|
version = "~0.24"
|
||||||
|
|
||||||
[build-dependencies.serde_codegen]
|
[build-dependencies.serde_codegen]
|
||||||
optional = true
|
optional = true
|
||||||
version = "0.8.19"
|
version = "0.8"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
encoding = "~0.2.33"
|
encoding = "0.2"
|
||||||
errln = "0.1.0"
|
errln = "0.1"
|
||||||
ignore = "~0.1.5"
|
ignore = "0.1"
|
||||||
lazy_static = "~0.2.1"
|
lazy_static = "0.2"
|
||||||
log = "~0.3.6"
|
log = "0.3"
|
||||||
maplit = "~0.1.3"
|
maplit = "0.1"
|
||||||
rayon = "=0.4.2"
|
rayon = "0.6"
|
||||||
regex = "~0.1.80"
|
regex = "0.1"
|
||||||
|
|
||||||
[dependencies.clap]
|
[dependencies.clap]
|
||||||
features = ["yaml"]
|
features = ["yaml"]
|
||||||
version = "~2.19.1"
|
version = "2.19"
|
||||||
|
|
||||||
[dependencies.env_logger]
|
[dependencies.env_logger]
|
||||||
features = []
|
features = []
|
||||||
version = "~0.3.5"
|
version = "0.3"
|
||||||
|
|
||||||
|
[dependencies.hex]
|
||||||
|
version = "0.2"
|
||||||
|
optional = true
|
||||||
|
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
optional = true
|
optional = true
|
||||||
version = "~0.8.19"
|
version = "0.8"
|
||||||
|
|
||||||
[dependencies.serde_cbor]
|
[dependencies.serde_cbor]
|
||||||
optional = true
|
optional = true
|
||||||
version = "~0.4.0"
|
version = "0.4"
|
||||||
|
|
||||||
[dependencies.serde_json]
|
[dependencies.serde_json]
|
||||||
optional = true
|
optional = true
|
||||||
version = "~0.8.4"
|
version = "0.8"
|
||||||
|
|
||||||
[dependencies.serde_yaml]
|
[dependencies.serde_yaml]
|
||||||
optional = true
|
optional = true
|
||||||
version = "~0.4.0"
|
version = "0.4"
|
||||||
|
|
||||||
[dependencies.toml]
|
[dependencies.toml]
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["serde"]
|
features = ["serde"]
|
||||||
optional = true
|
optional = true
|
||||||
version = "~0.2.1"
|
version = "0.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempdir = "~0.3.5"
|
tempdir = "0.3"
|
||||||
|
|
||||||
[dependencies.hex]
|
|
||||||
version = "~0.2.0"
|
|
||||||
optional = true
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
all = ["json", "cbor", "toml-io", "yaml"]
|
all = ["json", "cbor", "toml-io", "yaml"]
|
||||||
|
|
5
build.rs
5
build.rs
|
@ -5,7 +5,7 @@ extern crate handlebars;
|
||||||
#[macro_use] extern crate errln;
|
#[macro_use] extern crate errln;
|
||||||
|
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use handlebars::{Context, Handlebars};
|
use handlebars::Handlebars;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
@ -62,11 +62,10 @@ fn render_handlebars(out_dir: &OsString) -> PathBuf {
|
||||||
let mut handlebars = Handlebars::new();
|
let mut handlebars = Handlebars::new();
|
||||||
handlebars.register_escape_fn(handlebars::no_escape);
|
handlebars.register_escape_fn(handlebars::no_escape);
|
||||||
|
|
||||||
let raw_data: Value = serde_json::from_reader(
|
let data: Value = serde_json::from_reader(
|
||||||
File::open(&"languages.json").expect("Can't open JSON")
|
File::open(&"languages.json").expect("Can't open JSON")
|
||||||
).expect("Can't parse JSON");
|
).expect("Can't parse JSON");
|
||||||
|
|
||||||
let data = Context::wraps(&raw_data);
|
|
||||||
let out = Path::new(&out_dir).join("language_type.rs");
|
let out = Path::new(&out_dir).join("language_type.rs");
|
||||||
let mut source_template = File::open(&"src/language/language_type.hbs.rs")
|
let mut source_template = File::open(&"src/language/language_type.hbs.rs")
|
||||||
.expect("Can't find Template");
|
.expect("Can't find Template");
|
||||||
|
|
2
cli.yml
2
cli.yml
|
@ -5,7 +5,7 @@ about: Count Code, Quickly.
|
||||||
author: Aaron P. <theaaronepower@gmail.com>
|
author: Aaron P. <theaaronepower@gmail.com>
|
||||||
bin_name: Tokei
|
bin_name: Tokei
|
||||||
name: Tokei
|
name: Tokei
|
||||||
version: 4.5.4
|
version: '5'
|
||||||
args:
|
args:
|
||||||
- exclude:
|
- exclude:
|
||||||
help: Ignore all files & directories containing the word.
|
help: Ignore all files & directories containing the word.
|
||||||
|
|
|
@ -85,7 +85,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"Sh":{
|
"Sh":{
|
||||||
"name":"sh",
|
"name":"Shell",
|
||||||
"base":"hash",
|
"base":"hash",
|
||||||
"quotes":[
|
"quotes":[
|
||||||
[
|
[
|
||||||
|
@ -452,10 +452,9 @@
|
||||||
"single":[
|
"single":[
|
||||||
"//"
|
"//"
|
||||||
],
|
],
|
||||||
"multi":[[
|
"multi":[
|
||||||
"(*",
|
["(*", "*)"]
|
||||||
"*)"
|
],
|
||||||
]],
|
|
||||||
"extensions":[
|
"extensions":[
|
||||||
"fs",
|
"fs",
|
||||||
"fsi",
|
"fsi",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::ops::AddAssign;
|
use std::ops::AddAssign;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
use regex::{self, Regex};
|
use regex::{self, Regex};
|
||||||
|
|
||||||
|
@ -24,10 +25,15 @@ fn generate_regex(multi_line: &[(&'static str, &'static str)]) -> Cow<'static, R
|
||||||
Cow::Owned(Regex::new(&raw_regex).unwrap())
|
Cow::Owned(Regex::new(&raw_regex).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
fn get_c_regex() -> &'static Regex {
|
||||||
static ref C_REGEX: Regex = Regex::new(r"/\*").unwrap();
|
lazy_static! {
|
||||||
|
static ref C_REGEX: Regex = Regex::new(r"/\*").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
&*C_REGEX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Language {
|
impl Language {
|
||||||
/// Constructs a new empty Language with the comments provided.
|
/// Constructs a new empty Language with the comments provided.
|
||||||
///
|
///
|
||||||
|
@ -43,6 +49,7 @@ impl Language {
|
||||||
line_comment: line_comment,
|
line_comment: line_comment,
|
||||||
regex: Some(generate_regex(&multi_line)),
|
regex: Some(generate_regex(&multi_line)),
|
||||||
multi_line: multi_line,
|
multi_line: multi_line,
|
||||||
|
quotes: vec![("\"", "\"")],
|
||||||
..Self::default()
|
..Self::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +83,7 @@ impl Language {
|
||||||
line_comment: vec!["//"],
|
line_comment: vec!["//"],
|
||||||
multi_line: vec![("/*", "*/")],
|
multi_line: vec![("/*", "*/")],
|
||||||
quotes: vec![("\"", "\"")],
|
quotes: vec![("\"", "\"")],
|
||||||
regex: Some(Cow::Borrowed(&*C_REGEX)),
|
regex: Some(Cow::Borrowed(get_c_regex())),
|
||||||
..Self::default()
|
..Self::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +101,7 @@ impl Language {
|
||||||
/// ```
|
/// ```
|
||||||
pub fn new_func() -> Self {
|
pub fn new_func() -> Self {
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref FUNC_REGEX: Regex = Regex::new(r"\(\*").unwrap();
|
static ref FUNC_REGEX: Regex = Regex::new(®ex::quote(r"\(\*")).unwrap();
|
||||||
}
|
}
|
||||||
Language {
|
Language {
|
||||||
multi_line: vec![("(*", "*)")],
|
multi_line: vec![("(*", "*)")],
|
||||||
|
@ -155,7 +162,7 @@ impl Language {
|
||||||
/// ```
|
/// ```
|
||||||
pub fn new_haskell() -> Self {
|
pub fn new_haskell() -> Self {
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref HASKELL_REGEX: Regex = Regex::new(r"\{-").unwrap();
|
static ref HASKELL_REGEX: Regex = Regex::new(®ex::quote(r"\{-")).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Language {
|
Language {
|
||||||
|
@ -199,7 +206,7 @@ impl Language {
|
||||||
line_comment: vec!["%"],
|
line_comment: vec!["%"],
|
||||||
multi_line: vec![("/*", "*/")],
|
multi_line: vec![("/*", "*/")],
|
||||||
quotes: vec![("\"", "\"")],
|
quotes: vec![("\"", "\"")],
|
||||||
regex: Some(Cow::Borrowed(&*C_REGEX)),
|
regex: Some(Cow::Borrowed(get_c_regex())),
|
||||||
..Self::default()
|
..Self::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -302,10 +309,12 @@ impl Language {
|
||||||
/// panic!'s if given the wrong category.
|
/// panic!'s if given the wrong category.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use tokei::*;
|
/// use tokei::{Language, Stats, Sort};
|
||||||
|
/// use std::path::PathBuf;
|
||||||
|
///
|
||||||
/// let mut rust = Language::new_c();
|
/// let mut rust = Language::new_c();
|
||||||
/// let mut foo_stats = Stats::new("foo");
|
/// let mut foo_stats = Stats::new(PathBuf::from("foo"));
|
||||||
/// let mut bar_stats = Stats::new("bar");
|
/// let mut bar_stats = Stats::new(PathBuf::from("bar"));
|
||||||
///
|
///
|
||||||
/// foo_stats.code += 20;
|
/// foo_stats.code += 20;
|
||||||
/// bar_stats.code += 10;
|
/// bar_stats.code += 10;
|
||||||
|
@ -332,32 +341,12 @@ impl Language {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddAssign for Language {
|
impl AddAssign for Language {
|
||||||
fn add_assign(&mut self, rhs: Self) {
|
fn add_assign(&mut self, mut rhs: Self) {
|
||||||
self.lines += rhs.lines;
|
self.lines += rhs.lines;
|
||||||
self.comments += rhs.comments;
|
self.comments += rhs.comments;
|
||||||
self.blanks += rhs.blanks;
|
self.blanks += rhs.blanks;
|
||||||
self.code += rhs.code;
|
self.code += rhs.code;
|
||||||
self.stats.extend_from_slice(&*rhs.stats);
|
self.stats.extend(mem::replace(&mut rhs.stats, Vec::new()));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> AddAssign<&'a Language> for Language {
|
|
||||||
fn add_assign(&mut self, rhs: &'a Self) {
|
|
||||||
self.lines += rhs.lines;
|
|
||||||
self.comments += rhs.comments;
|
|
||||||
self.blanks += rhs.blanks;
|
|
||||||
self.code += rhs.code;
|
|
||||||
self.stats.extend_from_slice(&*rhs.stats);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> AddAssign<&'a mut Language> for Language {
|
|
||||||
fn add_assign(&mut self, rhs: &mut Self) {
|
|
||||||
self.lines += rhs.lines;
|
|
||||||
self.comments += rhs.comments;
|
|
||||||
self.blanks += rhs.blanks;
|
|
||||||
self.code += rhs.code;
|
|
||||||
self.stats.extend_from_slice(&*rhs.stats);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ use std::fmt;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufRead, BufReader};
|
use std::io::{BufRead, BufReader};
|
||||||
use std::collections::BTreeMap;
|
|
||||||
|
|
||||||
use utils::fs;
|
use utils::fs;
|
||||||
use self::LanguageType::*;
|
use self::LanguageType::*;
|
||||||
|
@ -45,6 +44,15 @@ impl LanguageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Provides every variant in a Vec
|
||||||
|
pub fn list() -> Vec<Self> {
|
||||||
|
return vec! [
|
||||||
|
{{#each languages}}
|
||||||
|
{{@key}},
|
||||||
|
{{~/each}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
/// Get language from it's file extension.
|
/// Get language from it's file extension.
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
|
@ -74,10 +82,9 @@ impl LanguageType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Languages {
|
impl Languages {
|
||||||
#[inline]
|
pub fn generate_language(language: LanguageType) -> Language {
|
||||||
pub fn generate_languages() -> BTreeMap<LanguageType, Language> {
|
match language {
|
||||||
btreemap! {
|
{{#each languages}}
|
||||||
{{~#each languages}}
|
|
||||||
{{~@key}} =>
|
{{~@key}} =>
|
||||||
{{~#if this.base}}
|
{{~#if this.base}}
|
||||||
Language::new_{{this.base}}()
|
Language::new_{{this.base}}()
|
||||||
|
@ -192,11 +199,14 @@ impl<'a> From<&'a LanguageType> for Cow<'a, LanguageType> {
|
||||||
|
|
||||||
|
|
||||||
/// This is for getting the file type from the first line of a file
|
/// 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> {
|
pub fn get_filetype_from_shebang<P>(file: P) -> Option<&'static str>
|
||||||
|
where P: AsRef<Path>
|
||||||
|
{
|
||||||
let file = match File::open(file) {
|
let file = match File::open(file) {
|
||||||
Ok(file) => file,
|
Ok(file) => file,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut buf = BufReader::new(file);
|
let mut buf = BufReader::new(file);
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
let _ = buf.read_line(&mut line);
|
let _ = buf.read_line(&mut line);
|
||||||
|
|
|
@ -7,6 +7,7 @@ use std::collections::{btree_map, BTreeMap};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::iter::IntoIterator;
|
use std::iter::IntoIterator;
|
||||||
|
use std::mem;
|
||||||
use std::ops::{AddAssign, Deref, DerefMut};
|
use std::ops::{AddAssign, Deref, DerefMut};
|
||||||
use std::sync::{mpsc, Mutex};
|
use std::sync::{mpsc, Mutex};
|
||||||
|
|
||||||
|
@ -25,31 +26,22 @@ use super::LanguageType::*;
|
||||||
use super::{Language, LanguageType};
|
use super::{Language, LanguageType};
|
||||||
use utils::{fs, multi_line};
|
use utils::{fs, multi_line};
|
||||||
|
|
||||||
fn count_files(mut language_tuple: (&LanguageType, &mut Language)) {
|
fn count_files((name, ref mut language): (&LanguageType, &mut Language)) {
|
||||||
|
|
||||||
let (name, ref mut language) = language_tuple;
|
|
||||||
|
|
||||||
if language.files.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let is_fortran = name == &FortranModern || name == &FortranLegacy;
|
let is_fortran = name == &FortranModern || name == &FortranLegacy;
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
let has_multi_line = !language.multi_line.is_empty() &&
|
|
||||||
!language.nested_comments.is_empty();
|
|
||||||
let synced_tx = Mutex::new(tx);
|
let synced_tx = Mutex::new(tx);
|
||||||
|
let has_multi_line = !language.multi_line.is_empty() || !language.nested_comments.is_empty();
|
||||||
let is_blank = language.is_blank();
|
let is_blank = language.is_blank();
|
||||||
|
|
||||||
language.files.par_iter().for_each(|file| {
|
let files = mem::replace(&mut language.files, Vec::new());
|
||||||
let mut stats = Stats::new(
|
|
||||||
opt_ret_error!(file.to_str(), "Couldn't convert path to String.")
|
files.into_par_iter().for_each(|file| {
|
||||||
);
|
|
||||||
let mut stack = Vec::new();
|
let mut stack = Vec::new();
|
||||||
let mut contents = Vec::new();
|
let mut contents = Vec::new();
|
||||||
let mut quote = None;
|
let mut quote = None;
|
||||||
|
|
||||||
rs_ret_error!(rs_ret_error!(File::open(file)).read_to_end(&mut contents));
|
rs_ret_error!(rs_ret_error!(File::open(&file)).read_to_end(&mut contents));
|
||||||
|
|
||||||
let text = match encoding::decode(&contents, Replace, UTF_8) {
|
let text = match encoding::decode(&contents, Replace, UTF_8) {
|
||||||
(Ok(string), _) => Cow::Owned(string),
|
(Ok(string), _) => Cow::Owned(string),
|
||||||
|
@ -57,7 +49,7 @@ fn count_files(mut language_tuple: (&LanguageType, &mut Language)) {
|
||||||
};
|
};
|
||||||
|
|
||||||
let lines = text.lines();
|
let lines = text.lines();
|
||||||
|
let mut stats = Stats::new(file);
|
||||||
if is_blank {
|
if is_blank {
|
||||||
let count = lines.count();
|
let count = lines.count();
|
||||||
stats.lines += count;
|
stats.lines += count;
|
||||||
|
@ -120,7 +112,7 @@ fn count_files(mut language_tuple: (&LanguageType, &mut Language)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let &mut Some(quote_str) = &mut quote {
|
if let &mut Some(quote_str) = &mut quote {
|
||||||
if window.starts_with(&*b"\\") {
|
if window.starts_with(&*br"\") {
|
||||||
skip = 1;
|
skip = 1;
|
||||||
} else if window.starts_with(quote_str.as_bytes()) {
|
} else if window.starts_with(quote_str.as_bytes()) {
|
||||||
quote = None;
|
quote = None;
|
||||||
|
@ -139,7 +131,10 @@ fn count_files(mut language_tuple: (&LanguageType, &mut Language)) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if no_stack {
|
let starts_with_comment = language.multi_line.iter().chain(&language.nested_comments)
|
||||||
|
.any(|&(start, _)| line.starts_with(start));
|
||||||
|
|
||||||
|
if no_stack && !starts_with_comment {
|
||||||
stats.code += 1;
|
stats.code += 1;
|
||||||
} else {
|
} else {
|
||||||
stats.comments += 1;
|
stats.comments += 1;
|
||||||
|
@ -300,8 +295,7 @@ impl Languages {
|
||||||
/// let languages = Languages::new();
|
/// let languages = Languages::new();
|
||||||
/// ```
|
/// ```
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let map = Self::generate_languages();
|
Languages { inner: BTreeMap::new() }
|
||||||
Languages { inner: map }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new map that only contains non empty languages.
|
/// Creates a new map that only contains non empty languages.
|
||||||
|
@ -479,31 +473,6 @@ impl AddAssign<BTreeMap<LanguageType, Language>> for Languages {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> AddAssign<&'a BTreeMap<LanguageType, Language>> for Languages {
|
|
||||||
fn add_assign(&mut self, rhs: &'a BTreeMap<LanguageType, Language>) {
|
|
||||||
|
|
||||||
for (name, language) in rhs {
|
|
||||||
|
|
||||||
if let Some(result) = self.inner.get_mut(&name) {
|
|
||||||
*result += language;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> AddAssign<&'a mut BTreeMap<LanguageType, Language>> for Languages {
|
|
||||||
fn add_assign(&mut self, rhs: &'a mut BTreeMap<LanguageType, Language>) {
|
|
||||||
|
|
||||||
for (name, language) in rhs {
|
|
||||||
|
|
||||||
if let Some(result) = self.inner.get_mut(&name) {
|
|
||||||
*result += language;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl Deref for Languages {
|
impl Deref for Languages {
|
||||||
type Target = BTreeMap<LanguageType, Language>;
|
type Target = BTreeMap<LanguageType, Language>;
|
||||||
|
|
||||||
|
@ -511,105 +480,9 @@ impl Deref for Languages {
|
||||||
&self.inner
|
&self.inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerefMut for Languages {
|
impl DerefMut for Languages {
|
||||||
fn deref_mut(&mut self) -> &mut BTreeMap<LanguageType, Language> {
|
fn deref_mut(&mut self) -> &mut BTreeMap<LanguageType, Language> {
|
||||||
&mut self.inner
|
&mut self.inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod accuracy_tests {
|
|
||||||
extern crate tempdir;
|
|
||||||
use super::*;
|
|
||||||
use std::io::Write;
|
|
||||||
use std::fs::File;
|
|
||||||
use language::LanguageType;
|
|
||||||
use self::tempdir::TempDir;
|
|
||||||
|
|
||||||
|
|
||||||
fn test_accuracy(file_name: &'static str,
|
|
||||||
expected: usize,
|
|
||||||
contents: &'static str)
|
|
||||||
{
|
|
||||||
let tmp_dir = TempDir::new("test").expect("Couldn't create temp dir");
|
|
||||||
let file_name = tmp_dir.path().join(file_name);
|
|
||||||
let mut file = File::create(&file_name).expect("Couldn't create file");
|
|
||||||
file.write(contents.as_bytes()).expect("couldn't write to file");
|
|
||||||
|
|
||||||
let mut l = Languages::new();
|
|
||||||
let l_type = LanguageType::from_extension(&file_name)
|
|
||||||
.expect("Can't find language type");
|
|
||||||
l.get_statistics(vec![file_name.to_str().unwrap()], vec![]);
|
|
||||||
let language = l.get_mut(&l_type).expect("Couldn't find language");
|
|
||||||
|
|
||||||
assert_eq!(expected, language.code);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn inside_quotes() {
|
|
||||||
test_accuracy("inside_quotes.rs",
|
|
||||||
8,
|
|
||||||
r#"fn main() {
|
|
||||||
let start = "/*";
|
|
||||||
loop {
|
|
||||||
if x.len() >= 2 && x[0] == '*' && x[1] == '/' { // found the */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}"#)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn shouldnt_panic() {
|
|
||||||
test_accuracy("shouldnt_panic.rs",
|
|
||||||
9,
|
|
||||||
r#"fn foo() {
|
|
||||||
let this_ends = "a \"test/*.";
|
|
||||||
call1();
|
|
||||||
call2();
|
|
||||||
let this_does_not = /* a /* nested */ comment " */
|
|
||||||
"*/another /*test
|
|
||||||
call3();
|
|
||||||
*/";
|
|
||||||
}"#)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn all_quotes_no_comment() {
|
|
||||||
test_accuracy("all_quotes_no_comment.rs",
|
|
||||||
10,
|
|
||||||
r#"fn foobar() {
|
|
||||||
let does_not_start = // "
|
|
||||||
"until here,
|
|
||||||
test/*
|
|
||||||
test"; // a quote: "
|
|
||||||
let also_doesnt_start = /* " */
|
|
||||||
"until here,
|
|
||||||
test,*/
|
|
||||||
test"; // another quote: "
|
|
||||||
}"#)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn commenting_on_comments() {
|
|
||||||
test_accuracy("commenting_on_comments.rs",
|
|
||||||
5,
|
|
||||||
r#"fn foo() {
|
|
||||||
let a = 4; // /*
|
|
||||||
let b = 5;
|
|
||||||
let c = 6; // */
|
|
||||||
}"#)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn nesting_with_nesting_comments() {
|
|
||||||
test_accuracy("nesting_with_nesting_comments.d",
|
|
||||||
5,
|
|
||||||
r#"void main() {
|
|
||||||
auto x = 5; /+ a /+ nested +/ comment /* +/
|
|
||||||
writefln("hello");
|
|
||||||
auto y = 4; // */
|
|
||||||
}"#)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
74
src/main.rs
74
src/main.rs
|
@ -12,9 +12,6 @@ mod input;
|
||||||
use input::*;
|
use input::*;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::sync::mpsc::channel;
|
|
||||||
use std::thread;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use clap::App;
|
use clap::App;
|
||||||
use env_logger::LogBuilder;
|
use env_logger::LogBuilder;
|
||||||
|
@ -43,11 +40,9 @@ fn main() {
|
||||||
let verbose_option = matches.occurrences_of("verbose");
|
let verbose_option = matches.occurrences_of("verbose");
|
||||||
let sort_option = matches.value_of("sort");
|
let sort_option = matches.value_of("sort");
|
||||||
let ignored_directories = {
|
let ignored_directories = {
|
||||||
let mut ignored_directories: Vec<&str> = vec![".git"];
|
let mut ignored_directories: Vec<&str> = Vec::new();
|
||||||
if let Some(user_ignored) = matches.values_of("exclude") {
|
if let Some(user_ignored) = matches.values_of("exclude") {
|
||||||
for ignored in user_ignored {
|
ignored_directories.extend(user_ignored);
|
||||||
ignored_directories.push(ignored);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ignored_directories
|
ignored_directories
|
||||||
};
|
};
|
||||||
|
@ -65,7 +60,7 @@ fn main() {
|
||||||
let mut languages = Languages::new();
|
let mut languages = Languages::new();
|
||||||
|
|
||||||
if language_option {
|
if language_option {
|
||||||
for key in languages.keys() {
|
for key in LanguageType::list() {
|
||||||
println!("{:<25}", key);
|
println!("{:<25}", key);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -77,31 +72,9 @@ fn main() {
|
||||||
add_input(input, &mut languages);
|
add_input(input, &mut languages);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut total = Language::new_blank();
|
|
||||||
|
|
||||||
let print_animation = output_option == None;
|
|
||||||
let (tx, rx) = channel();
|
|
||||||
let child = thread::spawn(move || {
|
|
||||||
let time = 100;
|
|
||||||
loop {
|
|
||||||
if let Ok(_) = rx.try_recv() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if print_animation {
|
|
||||||
print!(" Counting files. \r");
|
|
||||||
thread::sleep(Duration::from_millis(time));
|
|
||||||
print!(" Counting files..\r");
|
|
||||||
thread::sleep(Duration::from_millis(time));
|
|
||||||
print!(" Counting files...\r");
|
|
||||||
thread::sleep(Duration::from_millis(time));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
languages.get_statistics(paths, ignored_directories);
|
languages.get_statistics(paths, ignored_directories);
|
||||||
|
|
||||||
if output_option == None {
|
if output_option.is_none() {
|
||||||
println!("{}", ROW);
|
println!("{}", ROW);
|
||||||
println!(" {:<12} {:>12} {:>12} {:>12} {:>12} {:>12}",
|
println!(" {:<12} {:>12} {:>12} {:>12} {:>12} {:>12}",
|
||||||
"Language",
|
"Language",
|
||||||
|
@ -111,32 +84,24 @@ fn main() {
|
||||||
"Comments",
|
"Comments",
|
||||||
"Blanks");
|
"Blanks");
|
||||||
println!("{}", ROW);
|
println!("{}", ROW);
|
||||||
}
|
|
||||||
|
|
||||||
for (name, language) in &languages {
|
if sort_option.is_none() {
|
||||||
if !language.is_empty() && sort_option == None && output_option == None {
|
for (name, language) in languages.iter().filter(isnt_empty) {
|
||||||
if files_option {
|
if files_option {
|
||||||
print_language(language, name);
|
print_language(language, name);
|
||||||
println!("{}", ROW);
|
println!("{}", ROW);
|
||||||
|
|
||||||
for stat in &language.stats {
|
for stat in &language.stats {
|
||||||
println!("{}", stat);
|
println!("{}", stat);
|
||||||
|
}
|
||||||
|
println!("{}", ROW);
|
||||||
|
} else if output_option.is_none() {
|
||||||
|
print_language(language, name);
|
||||||
}
|
}
|
||||||
println!("{}", ROW);
|
|
||||||
} else if output_option == None {
|
|
||||||
print_language(language, name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = tx.send(());
|
|
||||||
let _ = child.join();
|
|
||||||
|
|
||||||
for (_, language) in &languages {
|
|
||||||
if !language.is_empty() {
|
|
||||||
total += language;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(format) = output_option {
|
if let Some(format) = output_option {
|
||||||
match_output(format, languages);
|
match_output(format, languages);
|
||||||
|
@ -153,7 +118,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut languages: Vec<_> = languages.into_iter().collect();
|
let mut languages: Vec<_> = languages.iter().collect();
|
||||||
|
|
||||||
match &*sort_category {
|
match &*sort_category {
|
||||||
BLANKS => languages.sort_by(|a, b| b.1.blanks.cmp(&a.1.blanks)),
|
BLANKS => languages.sort_by(|a, b| b.1.blanks.cmp(&a.1.blanks)),
|
||||||
|
@ -184,6 +149,10 @@ fn main() {
|
||||||
if !files_option {
|
if !files_option {
|
||||||
println!("{}", ROW);
|
println!("{}", ROW);
|
||||||
}
|
}
|
||||||
|
let mut total = Language::new_blank();
|
||||||
|
for (_, language) in languages {
|
||||||
|
total += language;
|
||||||
|
}
|
||||||
println!(" {: <18} {: >6} {:>12} {:>12} {:>12} {:>12}",
|
println!(" {: <18} {: >6} {:>12} {:>12} {:>12} {:>12}",
|
||||||
"Total",
|
"Total",
|
||||||
total.stats.len(),
|
total.stats.len(),
|
||||||
|
@ -195,6 +164,9 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn isnt_empty(&(_, language): &(&LanguageType, &Language)) -> bool {
|
||||||
|
!language.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
fn print_language<'a, C>(language: &'a Language, name: C)
|
fn print_language<'a, C>(language: &'a Language, name: C)
|
||||||
where C: Into<Cow<'a, LanguageType>>
|
where C: Into<Cow<'a, LanguageType>>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
/// A struct representing the statistics of a file.
|
/// A struct representing the statistics of a file.
|
||||||
#[cfg_attr(feature = "io", derive(Deserialize, Serialize))]
|
#[cfg_attr(feature = "io", derive(Deserialize, Serialize))]
|
||||||
#[derive(Clone, Default, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
pub struct Stats {
|
pub struct Stats {
|
||||||
/// Number of blank lines within the file.
|
/// Number of blank lines within the file.
|
||||||
pub blanks: usize,
|
pub blanks: usize,
|
||||||
|
@ -11,6 +12,6 @@ pub struct Stats {
|
||||||
/// Total number of lines within the file.
|
/// Total number of lines within the file.
|
||||||
pub lines: usize,
|
pub lines: usize,
|
||||||
/// File name.
|
/// File name.
|
||||||
pub name: String,
|
pub name: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
68
src/stats.rs
68
src/stats.rs
|
@ -10,11 +10,27 @@ impl Stats {
|
||||||
/// Create a new `Stats` from a file path.
|
/// Create a new `Stats` from a file path.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use tokei::*;
|
/// use std::path::PathBuf;
|
||||||
/// let stats = Stats::new("src/main.rs");
|
/// use tokei::Stats;
|
||||||
|
///
|
||||||
|
/// let path = PathBuf::from("src/main.rs");
|
||||||
|
///
|
||||||
|
/// let stats = Stats::new(path);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn new<S: Into<String>>(name: S) -> Self {
|
pub fn new(name: PathBuf) -> Self {
|
||||||
Stats { name: name.into(), ..Self::default() }
|
Stats { name: name, ..Self::default() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Stats {
|
||||||
|
fn default() -> Self {
|
||||||
|
Stats {
|
||||||
|
name: PathBuf::new(),
|
||||||
|
lines: usize::default(),
|
||||||
|
code: usize::default(),
|
||||||
|
comments: usize::default(),
|
||||||
|
blanks: usize::default(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,26 +43,30 @@ fn find_char_boundary(s: &str, index: usize) -> usize {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Stats {
|
macro_rules! display_stats {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
($f:expr, $this:expr, $name:expr) => {
|
||||||
let name_length = self.name.len();
|
write!($f,
|
||||||
|
|
||||||
let name = if name_length == 25 {
|
|
||||||
self.name.clone()
|
|
||||||
} else if self.name.len() > 24 {
|
|
||||||
let mut name = String::from("|");
|
|
||||||
let from = find_char_boundary(&self.name, self.name.len() - 24);
|
|
||||||
name.push_str(&self.name[from..]);
|
|
||||||
name
|
|
||||||
} else {
|
|
||||||
self.name.clone()
|
|
||||||
};
|
|
||||||
write!(f,
|
|
||||||
" {: <25} {:>12} {:>12} {:>12} {:>12}",
|
" {: <25} {:>12} {:>12} {:>12} {:>12}",
|
||||||
name,
|
$name,
|
||||||
self.lines,
|
$this.lines,
|
||||||
self.code,
|
$this.code,
|
||||||
self.comments,
|
$this.comments,
|
||||||
self.blanks)
|
$this.blanks)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Stats {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let name = self.name.to_string_lossy();
|
||||||
|
let name_length = name.len();
|
||||||
|
|
||||||
|
if name_length == 25 || name_length <= 24 {
|
||||||
|
display_stats!(f, self, name)
|
||||||
|
} else {
|
||||||
|
let mut formatted = String::from("|");
|
||||||
|
let from = find_char_boundary(&name, name_length - 24);
|
||||||
|
formatted.push_str(&name[from..]);
|
||||||
|
display_stats!(f, self, formatted)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,20 +11,10 @@ use ignore::WalkBuilder;
|
||||||
use ignore::overrides::OverrideBuilder;
|
use ignore::overrides::OverrideBuilder;
|
||||||
use ignore::WalkState::*;
|
use ignore::WalkState::*;
|
||||||
|
|
||||||
use language::{Language, LanguageType};
|
use language::{Language, Languages, LanguageType};
|
||||||
use language::LanguageType::*;
|
use language::LanguageType::*;
|
||||||
pub use language::get_filetype_from_shebang;
|
pub use language::get_filetype_from_shebang;
|
||||||
|
|
||||||
macro_rules! get_language {
|
|
||||||
($languages:expr, $entry:expr) => {
|
|
||||||
if let Some(language_type) = LanguageType::from_extension($entry) {
|
|
||||||
opt_error!($languages.get_mut(&language_type), "Unknown Language? Shouldn't happen.")
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_all_files(paths: Vec<&str>,
|
pub fn get_all_files(paths: Vec<&str>,
|
||||||
ignored_directories: Vec<&str>,
|
ignored_directories: Vec<&str>,
|
||||||
languages: &mut BTreeMap<LanguageType, Language>)
|
languages: &mut BTreeMap<LanguageType, Language>)
|
||||||
|
@ -84,7 +74,9 @@ pub fn get_all_files(paths: Vec<&str>,
|
||||||
});
|
});
|
||||||
|
|
||||||
for (language_type, pathbuf) in rx {
|
for (language_type, pathbuf) in rx {
|
||||||
opt_error!(languages.get_mut(&language_type), "??!").files.push(pathbuf);
|
languages.entry(language_type)
|
||||||
|
.or_insert(Languages::generate_language(language_type))
|
||||||
|
.files.push(pathbuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,8 +116,8 @@ mod test {
|
||||||
create_dir(&path_name).expect("Couldn't create directory.rs within temp");
|
create_dir(&path_name).expect("Couldn't create directory.rs within temp");
|
||||||
|
|
||||||
let mut l = Languages::new();
|
let mut l = Languages::new();
|
||||||
get_all_files(vec![tmp_dir.into_path().to_str().unwrap()].into(), vec![].into(), &mut l);
|
get_all_files(vec![tmp_dir.into_path().to_str().unwrap()], vec![], &mut l);
|
||||||
|
|
||||||
assert_eq!(0, l.get(&LanguageType::Rust).unwrap().files.len());
|
assert!(l.get(&LanguageType::Rust).is_none());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,11 @@ pub fn handle_multi_line(line: &str,
|
||||||
'window: for window in line.as_bytes().windows(window_size) {
|
'window: for window in line.as_bytes().windows(window_size) {
|
||||||
while skip != 0 {
|
while skip != 0 {
|
||||||
skip -= 1;
|
skip -= 1;
|
||||||
continue;
|
continue 'window;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let &mut Some(quote_str) = quote {
|
if let &mut Some(quote_str) = quote {
|
||||||
if window.starts_with(b"\\") {
|
if window.starts_with(br"\") {
|
||||||
skip = 1;
|
skip = 1;
|
||||||
} else if window.starts_with(quote_str.as_bytes()) {
|
} else if window.starts_with(quote_str.as_bytes()) {
|
||||||
*quote = None;
|
*quote = None;
|
||||||
|
|
59
tests/accuracy.rs
Normal file
59
tests/accuracy.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#[macro_use] extern crate lazy_static;
|
||||||
|
extern crate regex;
|
||||||
|
extern crate tokei;
|
||||||
|
extern crate ignore;
|
||||||
|
|
||||||
|
use std::io::Read;
|
||||||
|
use std::fs::File;
|
||||||
|
|
||||||
|
use regex::Regex;
|
||||||
|
use tokei::Languages;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref LINES: Regex = Regex::new(r"\d+ lines").unwrap();
|
||||||
|
static ref CODE: Regex = Regex::new(r"\d+ code").unwrap();
|
||||||
|
static ref COMMENTS: Regex = Regex::new(r"\d+ comments").unwrap();
|
||||||
|
static ref BLANKS: Regex = Regex::new(r"\d+ blanks").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! get_digit {
|
||||||
|
($regex:expr, $text:expr) => {{
|
||||||
|
let (begin, end) = $regex.find(&$text).expect("Couldn't find category");
|
||||||
|
$text[begin..end].split_whitespace()
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.parse::<usize>()
|
||||||
|
.unwrap()
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn languages() {
|
||||||
|
use ignore::Walk;
|
||||||
|
let walker = Walk::new("./tests/data/").filter(|p| {
|
||||||
|
match p {
|
||||||
|
&Ok(ref p) => !p.metadata().unwrap().is_dir(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for path in walker {
|
||||||
|
let path = path.unwrap();
|
||||||
|
let path = path.path().to_str().unwrap();
|
||||||
|
let mut languages = Languages::new();
|
||||||
|
languages.get_statistics(vec![path], vec![]);
|
||||||
|
let mut contents = String::new();
|
||||||
|
File::open(path).unwrap().read_to_string(&mut contents).unwrap();
|
||||||
|
|
||||||
|
|
||||||
|
for (name, language) in languages {
|
||||||
|
assert_eq!(get_digit!(LINES, contents), language.lines);
|
||||||
|
println!("{} LINES MATCH", name);
|
||||||
|
assert_eq!(get_digit!(CODE, contents), language.code);
|
||||||
|
println!("{} CODE MATCH", name);
|
||||||
|
assert_eq!(get_digit!(COMMENTS, contents), language.comments);
|
||||||
|
println!("{} COMMENTS MATCH", name);
|
||||||
|
assert_eq!(get_digit!(BLANKS, contents), language.blanks);
|
||||||
|
println!("{} BLANKS MATCH", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
tests/data/d.d
Normal file
8
tests/data/d.d
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/* 8 lines 5 code 1 comments 2 blanks */
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
auto x = 5; /+ a /+ nested +/ comment /* +/
|
||||||
|
writefln("hello");
|
||||||
|
auto y = 4; // */
|
||||||
|
}
|
||||||
|
|
13
tests/data/fsharp.fs
Normal file
13
tests/data/fsharp.fs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
(* 13 lines 5 code 4 comments 4 blanks *)
|
||||||
|
|
||||||
|
// Comment
|
||||||
|
|
||||||
|
let foo = (*
|
||||||
|
Comment
|
||||||
|
*)
|
||||||
|
5
|
||||||
|
|
||||||
|
let bar = "(*
|
||||||
|
Code
|
||||||
|
*)"
|
||||||
|
|
38
tests/data/rust.rs
Normal file
38
tests/data/rust.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// 38 lines 32 code 1 comments 5 blanks
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let start = "/*";
|
||||||
|
loop {
|
||||||
|
if x.len() >= 2 && x[0] == '*' && x[1] == '/' { // found the */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
let this_ends = "a \"test/*.";
|
||||||
|
call1();
|
||||||
|
call2();
|
||||||
|
let this_does_not = /* a /* nested */ comment " */
|
||||||
|
"*/another /*test
|
||||||
|
call3();
|
||||||
|
*/";
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foobar() {
|
||||||
|
let does_not_start = // "
|
||||||
|
"until here,
|
||||||
|
test/*
|
||||||
|
test"; // a quote: "
|
||||||
|
let also_doesnt_start = /* " */
|
||||||
|
"until here,
|
||||||
|
test,*/
|
||||||
|
test"; // another quote: "
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
let a = 4; // /*
|
||||||
|
let b = 5;
|
||||||
|
let c = 6; // */
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue