Skip to content
This repository has been archived by the owner on Nov 14, 2023. It is now read-only.

Commit

Permalink
feat: initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
kbknapp committed Aug 21, 2015
1 parent 466b50c commit b6e968f
Show file tree
Hide file tree
Showing 13 changed files with 1,146 additions and 1 deletion.
10 changes: 10 additions & 0 deletions .clog.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[clog]
repository = "https://github.com/kbknapp/cargo-count"
outfile = "CHANGELOG.md"
from-latest-tag = true

[sections]
Performance = ["perf"]
Improvements = ["impr", "im", "imp"]
Documentation = ["docs"]
Deprecations = ["depr"]
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@

# Generated by Cargo
/target/

# temp files
.*~
17 changes: 17 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
language: rust
rust:
- nightly
- beta
- stable
before_script:
- |
pip install 'travis-cargo<0.2' --user &&
export PATH=$HOME/.local/bin:$PATH
script:
- |
travis-cargo build &&
travis-cargo test
env:
global:
secure: JLBlgHY6OEmhJ8woewNJHmuBokTNUv7/WvLkJGV8xk0t6bXBwSU0jNloXwlH7FiQTc4TccX0PumPDD4MrMgxIAVFPmmmlQOCmdpYP4tqZJ8xo189E5zk8lKF5OyaVYCs5SMmFC3cxCsKjfwGIexNu3ck5Uhwe9jI0tqgkgM3URA=
93 changes: 93 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "cargo-count"
version = "0.1.0"
authors = ["Kevin K <kbknapp@gmail.com>"]

[dependencies]
clap = "~1.2.1"
glob = "~0.2.10"
tabwriter = "~0.1.23"
regex = "~0.1.41"

[dependencies.ansi_term]
version = "~0.6.3"
optional = true

[dependencies.regex_macros]
version = "*"
optional = true

[features]
default = ["color"]
color = ["ansi_term"]
debug = []
# unstable = ["regex_macros"]
unstable = []
File renamed without changes.
97 changes: 96 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,97 @@
# cargo-count
a cargo subcommand for counting lines of code in Rust (based on rusty-cloc by Aaronepower)
Linux: [![Build Status](https://travis-ci.org/kbknapp/cargo-count.svg?branch=master)](https://travis-ci.org/kbknapp/cargo-count)

A cargo subcommand for displaying line counts of source code in projects

## Demo

Running `cargo count -s , --unsafe-statistics` in the [Rust](https://github.com/rust-lang/rust) repo yields these results:

```
Gathering information...
Language Files Lines Blanks Comments Code Unsafe (%)
-------- ----- ----- ------ -------- ---- ----------
Rust 6,015 527,198 63,300 161,789 302,109 1,162 (0.38%)
CSS 4 1,262 99 490 673
Python 31 4,797 822 680 3,295
C 54 9,962 1,154 2,945 5,863 5,836 (99.54%)
C Header 13 1,865 243 650 972 937 (96.40%)
JavaScript 4 1,118 131 142 845
C++ 4 1,611 185 81 1,345 1,345 (100.00%)
-------- ----- ----- ------ -------- ---- ----------
Totals: 6,125 547,813 65,934 166,777 315,102 9,280 (2.95%)
```

The `-s ,` sets a `,` character as the thousands separator, and `--unsafe-statistics` looks for, and counts `unsafe` blocks.

## Compiling

Follow these instructions to compile `cargo-count`, then skip down to Installation.

1. Ensure you have current version of `cargo` and [Rust](https://www.rust-lang.org) installed
2. Clone the project `$ git clone https://github.com/kbknapp/cargo-count && cd cargo-count`
3. Build the project `$ cargo build --release`
4. Once complete, the binary will be located at `target/release/cargo-count`

## Installation and Usage

All you need to do is place `cargo-count` somewhere in your `$PATH`. Then run `cargo count` anywhere in your project directory. For full details see below.

### Linux / OS X

You have two options, place `cargo-count` into a directory that is already located in your `$PATH` variable (To see which directories those are, open a terminal and type `echo "${PATH//:/\n}"`, the quotation marks are important), or you can add a custom directory to your `$PATH`

**Option 1**
If you have write permission to a directory listed in your `$PATH` or you have root permission (or via `sudo`), simply copy the `cargo-count` to that directory `# sudo cp cargo-count /usr/local/bin`

**Option 2**
If you do not have root, `sudo`, or write permission to any directory already in `$PATH` you can create a directory inside your home directory, and add that. Many people use `$HOME/.bin` to keep it hidden (and not clutter your home directory), or `$HOME/bin` if you want it to be always visible. Here is an example to make the directory, add it to `$PATH`, and copy `cargo-count` there.

Simply change `bin` to whatever you'd like to name the directory, and `.bashrc` to whatever your shell startup file is (usually `.bashrc`, `.bash_profile`, or `.zshrc`)

```sh
$ mkdir ~/bin
$ echo "export PATH=$PATH:$HOME/bin" >> ~/.bashrc
$ cp cargo-count ~/bin
$ source ~/.bashrc
```

### Windows

On Windows 7/8 you can add directory to the `PATH` variable by opening a command line as an administrator and running

```sh
C:\> setx path "%path%;C:\path\to\cargo-count\binary"
```

Otherwise, ensure you have the `cargo-count` binary in the directory which you operating in the command line from, because Windows automatically adds your current directory to PATH (i.e. if you open a command line to `C:\my_project\` to use `cargo-count` ensure `cargo-count.exe` is inside that directory as well).


### Options

There are a few options for using `cargo-count` which should be somewhat self explanitory.

```
USAGE:
cargo count [FLAGS] [OPTIONS] [--] [ARGS]
FLAGS:
-h, --help Prints help information
--ignore Ignore files and streams with invalid UTF-8
--unsafe-statistics Displays percentages of "unsafe" code
-V, --version Prints version information
-v, --verbose Print verbose output
OPTIONS:
-l, --language <exts>... The languages to count by file extension (i.e. '-l js py cpp')
-e, --exclude <paths>... Files or directories to exclude
-s, --separator <sep> Set the thousands separator for pretty printing
ARGS:
to_count... The file or directory to count
(defaults to current working directory when omitted)
```

## License

`cargo-count` is released under the terms of either the MIT or Apache 2.0 license. See the LICENSE-MIT or LICENSE-APACHE file for the details.
62 changes: 62 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::error::Error;
use std::fmt::{Display, Formatter};
use std::fmt::Result as FmtResult;

use fmt::Format;

#[derive(Debug)]
#[allow(dead_code)]
pub enum CliError {
Generic(String),
UnknownExt(String),
Unknown
}

// Copies clog::error::Error;
impl CliError {
/// Return whether this was a fatal error or not.
#[allow(dead_code)]
pub fn is_fatal(&self) -> bool {
// For now all errors are fatal
true
}

/// Print this error and immediately exit the program.
///
/// If the error is non-fatal then the error is printed to stdout and the
/// exit status will be `0`. Otherwise, when the error is fatal, the error
/// is printed to stderr and the exit status will be `1`.
pub fn exit(&self) -> ! {
if self.is_fatal() {
wlnerr!("{}", self);
::std::process::exit(1)
} else {
println!("{}", self);
::std::process::exit(0)
}
}
}

impl Display for CliError {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "{} {}", Format::Error("error:"), self.description())
}
}

impl Error for CliError {
fn description<'a>(&'a self) -> &'a str {
match *self {
CliError::Generic(ref d) => &*d,
CliError::UnknownExt(ref d) => &*d,
CliError::Unknown => "An unknown fatal error has occurred, please consider filing a bug-report!"
}
}

fn cause(&self) -> Option<&Error> {
match *self {
CliError::Generic(..) => None,
CliError::UnknownExt(..) => None,
CliError::Unknown => None,
}
}
}
76 changes: 76 additions & 0 deletions src/fmt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use std::fmt;

#[cfg(all(feature = "color", not(target_os = "windows")))]
use ansi_term::Colour::{Red, Green, Yellow};
#[cfg(all(feature = "color", not(target_os = "windows")))]
use ansi_term::ANSIString;

#[allow(dead_code)]
pub enum Format<T> {
Error(T),
Warning(T),
Good(T),
}

#[cfg(all(feature = "color", not(target_os = "windows")))]
impl<T: AsRef<str>> Format<T> {
fn format(&self) -> ANSIString {
match *self {
Format::Error(ref e) => Red.bold().paint(e.as_ref()),
Format::Warning(ref e) => Yellow.paint(e.as_ref()),
Format::Good(ref e) => Green.paint(e.as_ref()),
}
}

}

#[cfg(all(feature = "color", not(target_os = "windows")))]
impl<T: AsRef<str>> fmt::Display for Format<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self.format())
}
}

#[cfg(any(not(feature = "color"), target_os = "windows"))]
impl<T: fmt::Display> Format<T> {
fn format(&self) -> &T {
match *self {
Format::Error(ref e) => e,
Format::Warning(ref e) => e,
Format::Good(ref e) => e,
}
}
}

#[cfg(any(not(feature = "color"), target_os = "windows"))]
impl<T: fmt::Display> fmt::Display for Format<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self.format())
}
}

pub fn format_number(n: u64, sep: Option<char>) -> String {
debugln!("executing; format_number; n={}", n);
let s = format!("{}", n);
if let Some(sep) = sep {
debugln!("There was a separator {}", sep);
let mut ins_sep = s.len() % 3;
ins_sep = if ins_sep == 0 { 3 } else {ins_sep};
let mut ret = vec![];
for (i, c) in s.chars().enumerate() {
debugln!("iter; c={}; ins_sep={}; ret={:?}", c, ins_sep, ret);
if ins_sep == 0 && i != 0 {
debugln!("Inserting the separator");
ret.push(sep);
ins_sep = 3;
}
ret.push(c);
ins_sep -= 1;
}
debugln!("returning; ret={}", ret.iter().cloned().collect::<String>());
ret.iter().cloned().collect()
} else {
debugln!("There was not a separator");
s
}
}
Loading

0 comments on commit b6e968f

Please sign in to comment.