From a2b63f7e0c3d8294398e63486602663572fc5b54 Mon Sep 17 00:00:00 2001 From: Odin Dutton Date: Sun, 26 May 2019 12:04:13 +1000 Subject: [PATCH 1/2] Add size command --- src/cli.rs | 1 + src/commands.rs | 1 + src/commands/size.rs | 84 ++++++++++++++++++++++++++++++++++++++++++ src/shell/completer.rs | 2 +- 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 src/commands/size.rs diff --git a/src/cli.rs b/src/cli.rs index 0ec35c094f..5efd47ea88 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -60,6 +60,7 @@ pub async fn cli() -> Result<(), Box> { ("skip", Arc::new(skip::skip)), ("first", Arc::new(take::take)), ("select", Arc::new(select::select)), + ("size", Arc::new(size::size)), ("split", Arc::new(split::split)), ("reject", Arc::new(reject::reject)), ("to-array", Arc::new(to_array::to_array)), diff --git a/src/commands.rs b/src/commands.rs index b48af5b02f..6dcc6a83e6 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -6,6 +6,7 @@ crate mod ls; crate mod ps; crate mod reject; crate mod select; +crate mod size; crate mod skip; crate mod sort_by; crate mod split; diff --git a/src/commands/size.rs b/src/commands/size.rs new file mode 100644 index 0000000000..aea5995974 --- /dev/null +++ b/src/commands/size.rs @@ -0,0 +1,84 @@ +use crate::errors::ShellError; +use crate::object::dict::Dictionary; +use crate::object::Value; +use crate::prelude::*; +use std::fs::File; +use std::io::prelude::*; + +pub fn size(args: CommandArgs) -> Result { + if args.args.is_empty() { + return Err(ShellError::string("size requires at least one file")); + } + let cwd = args.env.lock().unwrap().cwd().to_path_buf(); + + let mut contents = String::new(); + let mut total_lines = 0; + let mut total_words = 0; + let mut total_chars = 0; + let mut total_bytes = 0; + + let mut list = VecDeque::new(); + for name in args.args { + let name = name.as_string()?; + let path = cwd.join(&name); + let mut file = File::open(path)?; + + file.read_to_string(&mut contents)?; + let (lines, words, chars, bytes) = count(&contents); + + total_lines += lines; + total_words += words; + total_chars += chars; + total_bytes += bytes; + + list.push_back(dict(&name, lines, words, chars, bytes)); + contents.clear(); + } + list.push_back(dict( + &"total".to_string(), + total_lines, + total_words, + total_chars, + total_bytes, + )); + + Ok(list.boxed()) +} + +fn count(contents: &str) -> (i64, i64, i64, i64) { + let mut lines: i64 = 0; + let mut words: i64 = 0; + let mut chars: i64 = 0; + let mut end_of_word = true; + + for c in contents.chars() { + chars += 1; + + match c { + '\n' => { + lines += 1; + end_of_word = true; + } + ' ' => end_of_word = true, + _ => { + if end_of_word { + words += 1; + } + end_of_word = false; + } + } + } + + (lines, words, chars, contents.len() as i64) +} + +fn dict(name: &str, lines: i64, words: i64, chars: i64, bytes: i64) -> ReturnValue { + let mut dict = Dictionary::default(); + dict.add("name", Value::string(name.to_owned())); + dict.add("lines", Value::int(lines)); + dict.add("words", Value::int(words)); + dict.add("chars", Value::int(chars)); + dict.add("max length", Value::int(bytes)); + + ReturnValue::Value(Value::Object(dict)) +} diff --git a/src/shell/completer.rs b/src/shell/completer.rs index f3912ca672..7afceb3543 100644 --- a/src/shell/completer.rs +++ b/src/shell/completer.rs @@ -17,7 +17,7 @@ impl Completer for NuCompleter { ) -> rustyline::Result<(usize, Vec)> { let commands = [ "ps", "ls", "cd", "view", "skip", "take", "select", "reject", "to-array", "where", - "sort-by", + "sort-by", "size", ]; let mut completions = self.file_completer.complete(line, pos, context)?.1; From 4296466cd21cb825096a394a32fbf44fd7654e99 Mon Sep 17 00:00:00 2001 From: Odin Dutton Date: Mon, 27 May 2019 08:38:26 +1000 Subject: [PATCH 2/2] Remove total from size command There is a plan to introduce general facility for subtotaling numeric columns. --- src/commands/size.rs | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/src/commands/size.rs b/src/commands/size.rs index aea5995974..3b0858a77e 100644 --- a/src/commands/size.rs +++ b/src/commands/size.rs @@ -12,43 +12,25 @@ pub fn size(args: CommandArgs) -> Result { let cwd = args.env.lock().unwrap().cwd().to_path_buf(); let mut contents = String::new(); - let mut total_lines = 0; - let mut total_words = 0; - let mut total_chars = 0; - let mut total_bytes = 0; let mut list = VecDeque::new(); for name in args.args { let name = name.as_string()?; let path = cwd.join(&name); let mut file = File::open(path)?; - file.read_to_string(&mut contents)?; - let (lines, words, chars, bytes) = count(&contents); - - total_lines += lines; - total_words += words; - total_chars += chars; - total_bytes += bytes; - - list.push_back(dict(&name, lines, words, chars, bytes)); + list.push_back(count(&name, &contents)); contents.clear(); } - list.push_back(dict( - &"total".to_string(), - total_lines, - total_words, - total_chars, - total_bytes, - )); Ok(list.boxed()) } -fn count(contents: &str) -> (i64, i64, i64, i64) { +fn count(name: &str, contents: &str) -> ReturnValue { let mut lines: i64 = 0; let mut words: i64 = 0; let mut chars: i64 = 0; + let bytes = contents.len() as i64; let mut end_of_word = true; for c in contents.chars() { @@ -69,10 +51,6 @@ fn count(contents: &str) -> (i64, i64, i64, i64) { } } - (lines, words, chars, contents.len() as i64) -} - -fn dict(name: &str, lines: i64, words: i64, chars: i64, bytes: i64) -> ReturnValue { let mut dict = Dictionary::default(); dict.add("name", Value::string(name.to_owned())); dict.add("lines", Value::int(lines));