First draft

This commit is contained in:
Aaronepower 2016-07-17 22:17:49 +01:00
parent 4e671b5fa9
commit bfbfaa60fc
9 changed files with 391 additions and 269 deletions

2
Cargo.lock generated
View File

@ -1,6 +1,6 @@
[root]
name = "tokei"
version = "3.0.1"
version = "3.0.2"
dependencies = [
"clap 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -21,9 +21,18 @@ name = "tokei"
path = "src/main.rs"
doc = false
[features]
default = []
io = ["serde_codegen", "serde", "serializable_enum"]
json = ["io", "serde_json"]
cbor = ["io", "rustc-serialize","serde_cbor"]
toml-io = ["io", "toml/serde"]
yaml = ["io", "serde_yaml"]
all = ["json", "cbor", "toml-io", "yaml"]
# For building serde in stable.
[build-dependencies]
serde_codegen = "0.7.10"
serde_codegen = {version = "0.7.10", optional = true}
# Dependencies, and why they are used.
# - Clap: For CLI argument parsing.
@ -43,15 +52,16 @@ clap = {version = "2.5.1", features = ["yaml"]}
glob = "0.2.11"
maplit = "0.1.3"
rayon = "0.3.1"
rustc-serialize = "0.3.19"
serde = "0.7.10"
serde_cbor = "0.3.3"
serde_json = "0.7.1"
serde_yaml = "0.2.5"
serializable_enum = "0.3.0"
rustc-serialize = { version = "0.3.19", optional = true }
serde = { version = "0.7.10", optional = true }
serde_cbor = {version = "0.3.3", optional = true }
serde_json = { version = "0.7.1", optional = true }
serde_yaml = { version = "0.2.5", optional = true }
serializable_enum = { version = "0.3.0", optional = true }
walkdir = "0.1.5"
[dependencies.toml]
version = "0.1.30"
default-features = false
features = ["serde"]
optional = true

View File

@ -1,13 +1,23 @@
#[cfg(feature = "io")]
extern crate serde_codegen;
use std::env;
use std::path::Path;
pub fn main() {
expand();
}
#[cfg(feature = "io")]
fn expand() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let src = Path::new("src/lib/lib.rs.in");
let dst = Path::new(&out_dir).join("lib.rs");
let dst = Path::new(&out_dir).join("lib.rs.in");
serde_codegen::expand(&src, &dst).unwrap();
}
#[cfg(not(feature = "io"))]
fn expand() {}

View File

@ -6,7 +6,8 @@ use sort::Sort::*;
use stats::Stats;
/// Struct representing a single Language.
#[derive(Clone, Debug, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[cfg_attr(feature = "io", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
pub struct Language {
/// Number of blank lines.
pub blanks: usize,
@ -15,20 +16,20 @@ pub struct Language {
/// Number of comments(both single, and multi-line)
pub comments: usize,
/// A collection of files to be analysed.
#[serde(skip_deserializing, skip_serializing)]
#[cfg_attr(feature = "io", serde(skip_deserializing, skip_serializing))]
pub files: Vec<PathBuf>,
/// A collection of statistics based on the files provide from `files`
pub stats: Vec<Stats>,
/// Number of total lines.
pub lines: usize,
/// A collection of single line comments in the language. ie. `//` in Rust.
#[serde(skip_deserializing, skip_serializing)]
#[cfg_attr(feature = "io", serde(skip_deserializing, skip_serializing))]
pub line_comment: Vec<&'static str>,
/// A collection of tuples representing the start and end of multi line comments. ie. `/* comment */` in Rust.
#[serde(skip_deserializing, skip_serializing)]
#[cfg_attr(feature = "io", serde(skip_deserializing, skip_serializing))]
pub multi_line: Vec<(&'static str, &'static str)>,
/// Whether the language supports nested multi line comments or not.
#[serde(skip_deserializing, skip_serializing)]
#[cfg_attr(feature = "io", serde(skip_deserializing, skip_serializing))]
pub nested: bool,
}

View File

@ -10,159 +10,157 @@ use std::path::Path;
use utils::*;
use self::LanguageType::*;
serializable_enum! {
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum LanguageType {
/// ActionScript
ActionScript,
/// Assembly
Assembly,
/// Autoconf
Autoconf,
/// 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,
/// Isabelle
Isabelle,
/// 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,
}
LanguageTypeVisitor
#[cfg_attr(feature = "io", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum LanguageType {
/// ActionScript
ActionScript,
/// Assembly
Assembly,
/// Autoconf
Autoconf,
/// 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,
/// Isabelle
Isabelle,
/// 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,
}
#[derive(Debug)]
@ -175,86 +173,86 @@ impl ::std::fmt::Display for Error {
write!(f, "{:?}", self)
}
}
impl_as_ref_from_str! {
LanguageType {
ActionScript => "ActionScript",
Assembly => "Assembly",
Autoconf => "Autoconf",
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",
Isabelle => "Isabelle",
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",
}
Error::Parse
}
// #[cfg(feature = "io")]
// impl_as_ref_from_str! {
// LanguageType {
// ActionScript => "ActionScript",
// Assembly => "Assembly",
// Autoconf => "Autoconf",
// 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",
// Isabelle => "Isabelle",
// 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",
// }
// Error::Parse
// }
impl LanguageType {

View File

@ -9,9 +9,13 @@ use std::io::Read;
use std::iter::IntoIterator;
use std::ops::{AddAssign, Deref, DerefMut};
#[cfg(feature = "cbor")]
use serde_cbor;
#[cfg(feature = "json")]
use serde_json;
#[cfg(feature = "yaml")]
use serde_yaml;
#[cfg(feature = "toml-io")]
use toml;
use rayon::prelude::*;
@ -20,6 +24,11 @@ use super::{Language, LanguageType};
use super::LanguageType::*;
use stats::Stats;
const CBOR_ERROR: &'static str = "Tokei was not compiled with the `cbor` flag.";
const JSON_ERROR: &'static str = "Tokei was not compiled with the `json` flag.";
const TOML_ERROR: &'static str = "Tokei was not compiled with the `toml-io` flag.";
const YAML_ERROR: &'static str = "Tokei was not compiled with the `yaml` flag.";
/// A collection of existing languages([_List of Languages_](https://github.com/Aaronepower/tokei#supported-languages))
#[derive(Debug, Clone)]
pub struct Languages {
@ -45,12 +54,17 @@ impl Languages {
/// assert_eq!(12, languages.get_mut(&LanguageType::Rust).unwrap().code);
/// # }
/// ```
#[cfg(feature = "cbor")]
pub fn from_cbor<'a, I: Into<&'a [u8]>>(cbor: I) -> serde_cbor::Result<Self> {
let map = try!(serde_cbor::from_slice(cbor.into()));
Ok(Self::from_previous(map))
}
#[cfg(not(feature = "cbor"))]
pub fn from_cbor<'a, I: Into<&'a [u8]>>(cbor: I) -> ! {
panic!(CBOR_ERROR)
}
/// Creates a `Languages` struct from json.
///
@ -76,12 +90,18 @@ impl Languages {
/// let mut languages = Languages::from_json(json.as_bytes()).unwrap();
/// assert_eq!(12, languages.get_mut(&LanguageType::Rust).unwrap().code);
/// ```
#[cfg(feature = "json")]
pub fn from_json<'a, I: Into<&'a [u8]>>(json: I) -> serde_json::Result<Self> {
let map = try!(serde_json::from_slice(json.into()));
Ok(Self::from_previous(map))
}
#[cfg(not(feature = "json"))]
pub fn from_json<'a, I: Into<&'a [u8]>>(json: I) -> ! {
panic!(JSON_ERROR)
}
/// Creates a `Languages` struct from json.
///
/// ```no_run
@ -106,12 +126,18 @@ impl Languages {
///
/// assert_eq!(12, languages.get_mut(&LanguageType::Rust).unwrap().code);
/// ```
#[cfg(feature = "yaml")]
pub fn from_yaml<'a, I: Into<&'a [u8]>>(yaml: I) -> serde_yaml::Result<Self> {
let map = try!(serde_yaml::from_slice(yaml.into()));
Ok(Self::from_previous(map))
}
#[cfg(not(feature = "yaml"))]
pub fn from_yaml<'a, I: Into<&'a [u8]>>(yaml: I) -> ! {
panic!(YAML_ERROR)
}
fn from_previous(map: BTreeMap<LanguageType, Language>) -> Self {
let mut _self = Self::new();
@ -373,10 +399,16 @@ impl Languages {
/// assert_eq!(cbor, languages.to_cbor().unwrap().to_hex());
/// # }
/// ```
#[cfg(feature = "cbor")]
pub fn to_cbor(&self) -> Result<Vec<u8>, serde_cbor::Error> {
serde_cbor::to_vec(&self.remove_empty())
}
#[cfg(not(feature = "cbor"))]
pub fn to_cbor(&self) -> ! {
panic!(CBOR_ERROR)
}
/// Converts `Languages` to JSON.
///
/// ```no_run
@ -404,14 +436,26 @@ impl Languages {
///
/// assert_eq!(json, languages.to_json().unwrap());
/// ```
#[cfg(feature = "json")]
pub fn to_json(&self) -> Result<String, serde_json::Error> {
serde_json::to_string(&self.remove_empty())
}
#[cfg(not(feature = "json"))]
pub fn to_json(&self) -> ! {
panic!(JSON_ERROR)
}
#[cfg(feature = "toml-io")]
pub fn to_toml(&self) -> String {
toml::encode_str(&self.remove_empty())
}
#[cfg(not(feature = "toml-io"))]
pub fn to_toml(&self) -> ! {
panic!(TOML_ERROR)
}
/// Converts `Languages` to YAML.
///
/// ```no_run
@ -434,9 +478,15 @@ impl Languages {
/// languages.get_statistics(&*vec!["src/lib/build.rs"], &*vec![".git"]);
///
/// assert_eq!(yaml, languages.to_yaml().unwrap());
#[cfg(feature = "yaml")]
pub fn to_yaml(&self) -> Result<String, serde_yaml::Error> {
serde_yaml::to_string(&self.remove_empty())
}
#[cfg(not(feature = "yaml"))]
pub fn to_yaml(&self) -> ! {
panic!(YAML_ERROR)
}
}
impl IntoIterator for Languages {

View File

@ -49,14 +49,24 @@
#[macro_use]
extern crate maplit;
#[macro_use]
#[cfg(feature = "io")]
extern crate serializable_enum;
extern crate glob;
extern crate rayon;
#[cfg(feature = "io")]
extern crate serde;
#[cfg(feature = "cbor")]
extern crate serde_cbor;
#[cfg(feature = "json")]
extern crate serde_json;
#[cfg(feature = "yaml")]
extern crate serde_yaml;
#[cfg(feature = "toml")]
extern crate toml;
extern crate walkdir;
include!(concat!(env!("OUT_DIR"), "/lib.rs"));
#[cfg(feature = "io")]
include!(concat!(env!("OUT_DIR"), "/lib.rs.in"));
#[not(cfg(feature = "io"))]
include!("lib.rs.in");

View File

@ -1,7 +1,8 @@
use std::fmt;
/// A struct representing the statistics of a file.
#[derive(Clone, Default, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[cfg_attr(feature = "io", derive(Deserialize, Serialize))]
#[derive(Clone, Default, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Stats {
/// Number of blank lines within the file.
pub blanks: usize,

View File

@ -4,10 +4,15 @@
#[macro_use]
extern crate clap;
#[cfg(feature = "cbor")]
extern crate serde_cbor;
#[cfg(feature = "json")]
extern crate serde_json;
#[cfg(feature = "yaml")]
extern crate serde_yaml;
#[cfg(feature = "toml-io")]
extern crate toml;
#[cfg(feature = "cbor")]
extern crate rustc_serialize;
extern crate tokei;
@ -20,17 +25,38 @@ use std::time::Duration;
use std::sync::mpsc::channel;
use clap::App;
#[cfg(feature = "cbor")]
use rustc_serialize::hex::FromHex;
use tokei::{Languages, Language, LanguageType};
use tokei::Sort::*;
pub const ROW: &'static str = "-------------------------------------------------------------------\
const ROW: &'static str = "-------------------------------------------------------------------\
------------";
pub const BLANKS: &'static str = "blanks";
pub const COMMENTS: &'static str = "comments";
pub const CODE: &'static str = "code";
pub const FILES: &'static str = "files";
pub const LINES: &'static str = "lines";
const BLANKS: &'static str = "blanks";
const COMMENTS: &'static str = "comments";
const CODE: &'static str = "code";
const FILES: &'static str = "files";
const LINES: &'static str = "lines";
const OUTPUT_ERROR: &'static str = "This version of tokei was compiled without any serialization
formats, to enable serialization, reinstall tokei with the features flag.
ALL:
cargo install tokei --features all
JSON:
cargo install tokei --features json
CBOR:
cargo install tokei --features cbor
TOML:
cargo install tokei --features toml
YAML:
cargo install toke --features yaml
You can also have any mix of json cbor toml, or yaml.
";
fn main() {
// Get options at the beginning, so the program doesn't have to make any extra calls to get the
@ -158,19 +184,7 @@ fn main() {
}
if let Some(format) = output_option {
match &*format {
"cbor" => {
let cbor: Vec<_> = languages.to_cbor().unwrap();
for byte in cbor {
print!("{:02x}", byte);
}
}
"json" => print!("{}", languages.to_json().unwrap()),
"toml" => print!("{}", languages.to_toml()),
"yaml" => print!("{}", languages.to_yaml().unwrap()),
_ => unreachable!(),
}
match_output(&format);
} else if let Some(sort_category) = sort_option {
for (_, ref mut language) in &mut languages {
@ -229,8 +243,8 @@ fn main() {
/// 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.
#[cfg(feature = "io")]
pub fn convert_input(contents: String) -> Option<BTreeMap<LanguageType, Language>> {
if contents.is_empty() {
None
} else if let Ok(result) = serde_json::from_str(&*contents) {
@ -250,6 +264,34 @@ pub fn convert_input(contents: String) -> Option<BTreeMap<LanguageType, Language
}
}
#[cfg(feature = "io")]
fn match_output(format: &str) {
match format {
"cbor" => {
// let cbor: Vec<u8> = languages.to_cbor().unwrap();
// for byte in cbor {
// print!("{:02x}", byte);
// }
}
"json" => print!("{}", languages.to_json().unwrap()),
"toml" => print!("{}", languages.to_toml()),
"yaml" => print!("{}", languages.to_yaml().unwrap()),
_ => unreachable!(),
}
}
#[cfg(not(feature = "io"))]
fn match_output(format: &str) -> ! {
panic!(OUTPUT_ERROR)
}
#[cfg(not(feature = "io"))]
pub fn convert_input(contents: String) -> ! {
panic!(OUTPUT_ERROR);
}
fn print_language<'a, C>(language: &'a Language, name: C)
where C: Into<Cow<'a, LanguageType>>
{