diff --git a/src/cli.rs b/src/cli.rs index 15158f39..638bc3b9 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -48,6 +48,7 @@ pub async fn cli() -> Result<(), Box> { ("view", Arc::new(view::view)), ("skip", Arc::new(skip::skip)), ("first", Arc::new(take::take)), + ("size", Arc::new(size::size)), ("from-json", Arc::new(from_json::from_json)), ("open", Arc::new(open::open)), ("column", Arc::new(select::select)), diff --git a/src/commands.rs b/src/commands.rs index 784d192a..e444f385 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -8,6 +8,7 @@ crate mod open; 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 00000000..3b0858a7 --- /dev/null +++ b/src/commands/size.rs @@ -0,0 +1,62 @@ +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 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)?; + list.push_back(count(&name, &contents)); + contents.clear(); + } + + Ok(list.boxed()) +} + +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() { + 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; + } + } + } + + 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 2099f527..03351a0d 100644 --- a/src/shell/completer.rs +++ b/src/shell/completer.rs @@ -19,6 +19,7 @@ impl Completer for NuCompleter { pos: usize, context: &rustyline::Context, ) -> rustyline::Result<(usize, Vec)> { + let commands: Vec = self.commands.keys().cloned().collect(); let mut completions = self.file_completer.complete(line, pos, context)?.1;