diff --git a/README.md b/README.md index 1e5e120372..54117e08e3 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,7 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat | date (--utc) | Get the current datetime | | ps | View current processes | | sys | View information about the current system | +| which filename | Finds a program file. | | open {filename or url} | Load a file into a cell, convert to table if possible (avoid by appending '--raw') | | post url body (--user ) (--password ) | Post content to a url and retrieve data as a table if possible | | rm {file or directory} | Remove a file, (for removing directory append '--recursive') | @@ -217,6 +218,8 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat | p | Go to previous shell | | n | Go to next shell | | shells | Display the list of current shells | +| help | Display help information about commands | +| version | Display Nu version | ## Filters on tables (structured data) | command | description | @@ -230,8 +233,11 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat | add field value | Add a new field to the table | | sum | Sum a column of values | | edit field value | Edit an existing field to have a new value | +| reverse | Reverses the table. | | skip amount | Skip a number of rows | +| skip-while condition | Skips rows while the condition matches. | | first amount | Show only the first number of rows | +| last amount | Show only the last number of rows | | nth row-number | Return only the selected row | | str (field) | Apply string function. Optional use the field of a table | | tags | Read the tags (metadata) for values | @@ -240,13 +246,13 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat | to-json | Convert table into .json text | | to-toml | Convert table into .toml text | | to-yaml | Convert table into .yaml text | +| to-bson | Convert table into .bson text | | to-csv | Convert table into .csv text | | to-bson | Convert table into .bson binary data | | to-tsv | Convert table into .tsv text | | to-sqlite | Convert table to sqlite .db binary data | | reverse | Reverse the rows of a table | - ## Filters on text (unstructured data) | command | description | | ------------- | ------------- | @@ -256,7 +262,7 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat | from-json | Parse text as .json and create table | | from-sqlite | Parse binary data as sqlite .db and create table | | from-toml | Parse text as .toml and create table | -| from-tsv | Parse text as .tsv and create table | +| from-tsv | Parse text as .tsv and create table | | from-xml | Parse text as .xml and create a table | | from-yaml | Parse text as a .yaml/.yml and create a table | | lines | Split single string into rows, one per line | diff --git a/src/cli.rs b/src/cli.rs index e6592bd540..949c7a359f 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -212,6 +212,7 @@ pub async fn cli() -> Result<(), Box> { whole_stream_command(Config), whole_stream_command(SkipWhile), per_item_command(Enter), + per_item_command(Help), whole_stream_command(Exit), whole_stream_command(Autoview), per_item_command(Cpy), diff --git a/src/commands.rs b/src/commands.rs index d547422f31..0da8cadbd4 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -25,6 +25,7 @@ pub(crate) mod from_tsv; pub(crate) mod from_xml; pub(crate) mod from_yaml; pub(crate) mod get; +pub(crate) mod help; pub(crate) mod last; pub(crate) mod lines; pub(crate) mod ls; @@ -91,6 +92,7 @@ pub(crate) use from_xml::FromXML; pub(crate) use from_yaml::FromYAML; pub(crate) use from_yaml::FromYML; pub(crate) use get::Get; +pub(crate) use help::Help; pub(crate) use last::Last; pub(crate) use lines::Lines; pub(crate) use ls::LS; diff --git a/src/commands/autoview.rs b/src/commands/autoview.rs index 7d754d9adc..844a093c4a 100644 --- a/src/commands/autoview.rs +++ b/src/commands/autoview.rs @@ -12,6 +12,14 @@ impl WholeStreamCommand for Autoview { "autoview" } + fn signature(&self) -> Signature { + Signature::build("autoview") + } + + fn usage(&self) -> &str { + "View the contents of the pipeline as a table or list." + } + fn run( &self, args: CommandArgs, @@ -19,10 +27,6 @@ impl WholeStreamCommand for Autoview { ) -> Result { Ok(args.process_raw(registry, autoview)?.run()) } - - fn signature(&self) -> Signature { - Signature::build("autoview") - } } pub fn autoview( diff --git a/src/commands/cd.rs b/src/commands/cd.rs index 718f2846f4..a84e66fce9 100644 --- a/src/commands/cd.rs +++ b/src/commands/cd.rs @@ -5,6 +5,19 @@ use crate::prelude::*; pub struct CD; impl WholeStreamCommand for CD { + fn name(&self) -> &str { + "cd" + } + + fn signature(&self) -> Signature { + Signature::build("cd") + .optional("directory", SyntaxType::Path) + } + + fn usage(&self) -> &str { + "Change to a new path." + } + fn run( &self, args: CommandArgs, @@ -12,14 +25,6 @@ impl WholeStreamCommand for CD { ) -> Result { cd(args, registry) } - - fn name(&self) -> &str { - "cd" - } - - fn signature(&self) -> Signature { - Signature::build("cd").optional("directory", SyntaxType::Path) - } } fn cd(args: CommandArgs, registry: &CommandRegistry) -> Result { diff --git a/src/commands/classified.rs b/src/commands/classified.rs index 1430707637..6babb6c9ce 100644 --- a/src/commands/classified.rs +++ b/src/commands/classified.rs @@ -140,6 +140,29 @@ impl InternalCommand { context.add_span_source(uuid, span_source); } CommandAction::Exit => std::process::exit(0), + CommandAction::EnterHelpShell(value) => { + match value { + Tagged { + item: Value::Primitive(Primitive::String(cmd)), + .. + } => { + context.shell_manager.insert_at_current(Box::new( + HelpShell::for_command( + Tagged::from_simple_spanned_item( + Value::string(cmd), + Span::unknown(), + ), + &context.registry().clone(), + )?, + )); + } + _ => { + context.shell_manager.insert_at_current(Box::new( + HelpShell::index(&context.registry().clone())?, + )); + } + } + } CommandAction::EnterValueShell(value) => { context .shell_manager diff --git a/src/commands/clip.rs b/src/commands/clip.rs index 535c8f7450..9bf7fa9f3a 100644 --- a/src/commands/clip.rs +++ b/src/commands/clip.rs @@ -18,6 +18,15 @@ pub mod clipboard { fn name(&self) -> &str { "clip" } + + fn signature(&self) -> Signature { + Signature::build("clip") + } + + fn usage(&self) -> &str { + "Copy the contents of the pipeline to the copy/paste buffer" + } + fn run( &self, args: CommandArgs, @@ -25,10 +34,6 @@ pub mod clipboard { ) -> Result { args.process(registry, clip)?.run() } - - fn signature(&self) -> Signature { - Signature::build("clip") - } } pub fn clip( diff --git a/src/commands/command.rs b/src/commands/command.rs index 404d1d6b89..10611b41b0 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -417,6 +417,7 @@ pub enum CommandAction { Exit, EnterShell(String), EnterValueShell(Tagged), + EnterHelpShell(Tagged), PreviousShell, NextShell, LeaveShell, @@ -434,6 +435,9 @@ impl ToDebug for CommandAction { CommandAction::EnterValueShell(t) => { write!(f, "action:enter-value-shell={:?}", t.debug()) } + CommandAction::EnterHelpShell(t) => { + write!(f, "action:enter-help-shell={:?}", t.debug()) + } CommandAction::PreviousShell => write!(f, "action:previous-shell"), CommandAction::NextShell => write!(f, "action:next-shell"), CommandAction::LeaveShell => write!(f, "action:leave-shell"), @@ -488,26 +492,42 @@ impl ReturnSuccess { pub trait WholeStreamCommand: Send + Sync { fn name(&self) -> &str; - fn run( - &self, - args: CommandArgs, - registry: ®istry::CommandRegistry, - ) -> Result; - fn signature(&self) -> Signature { Signature { name: self.name().to_string(), + usage: self.usage().to_string(), positional: vec![], rest_positional: None, named: indexmap::IndexMap::new(), is_filter: true, } } + + fn usage(&self) -> &str; + + fn run( + &self, + args: CommandArgs, + registry: ®istry::CommandRegistry, + ) -> Result; } pub trait PerItemCommand: Send + Sync { fn name(&self) -> &str; + fn signature(&self) -> Signature { + Signature { + name: self.name().to_string(), + usage: self.usage().to_string(), + positional: vec![], + rest_positional: None, + named: indexmap::IndexMap::new(), + is_filter: true, + } + } + + fn usage(&self) -> &str; + fn run( &self, call_info: &CallInfo, @@ -515,16 +535,6 @@ pub trait PerItemCommand: Send + Sync { raw_args: &RawCommandArgs, input: Tagged, ) -> Result; - - fn signature(&self) -> Signature { - Signature { - name: self.name().to_string(), - positional: vec![], - rest_positional: None, - named: indexmap::IndexMap::new(), - is_filter: true, - } - } } pub enum Command { @@ -547,6 +557,13 @@ impl Command { } } + pub fn usage(&self) -> &str { + match self { + Command::WholeStream(command) => command.usage(), + Command::PerItem(command) => command.usage(), + } + } + pub fn run(&self, args: CommandArgs, registry: ®istry::CommandRegistry) -> OutputStream { match self { Command::WholeStream(command) => match command.run(args, registry) { @@ -618,6 +635,10 @@ impl WholeStreamCommand for FnFilterCommand { &self.name } + fn usage(&self) -> &str { + "usage" + } + fn run( &self, args: CommandArgs, diff --git a/src/commands/config.rs b/src/commands/config.rs index c41c1d374a..56cce62270 100644 --- a/src/commands/config.rs +++ b/src/commands/config.rs @@ -32,6 +32,10 @@ impl WholeStreamCommand for Config { .switch("path") } + fn usage(&self) -> &str { + "Configuration management." + } + fn run( &self, args: CommandArgs, diff --git a/src/commands/cp.rs b/src/commands/cp.rs index ee1a289cd8..8160fc9d2d 100644 --- a/src/commands/cp.rs +++ b/src/commands/cp.rs @@ -15,16 +15,6 @@ pub struct CopyArgs { } impl PerItemCommand for Cpy { - fn run( - &self, - call_info: &CallInfo, - _registry: &CommandRegistry, - raw_args: &RawCommandArgs, - _input: Tagged, - ) -> Result { - call_info.process(&raw_args.shell_manager, cp)?.run() - } - fn name(&self) -> &str { "cp" } @@ -36,6 +26,20 @@ impl PerItemCommand for Cpy { .named("file", SyntaxType::Any) .switch("recursive") } + + fn usage(&self) -> &str { + "Copy files." + } + + fn run( + &self, + call_info: &CallInfo, + _registry: &CommandRegistry, + raw_args: &RawCommandArgs, + _input: Tagged, + ) -> Result { + call_info.process(&raw_args.shell_manager, cp)?.run() + } } fn cp(args: CopyArgs, context: &RunnablePerItemContext) -> Result { diff --git a/src/commands/date.rs b/src/commands/date.rs index b979dfe3e7..0e2fee563a 100644 --- a/src/commands/date.rs +++ b/src/commands/date.rs @@ -12,6 +12,20 @@ use indexmap::IndexMap; pub struct Date; impl WholeStreamCommand for Date { + fn name(&self) -> &str { + "date" + } + + fn signature(&self) -> Signature { + Signature::build("date") + .switch("utc") + .switch("local") + } + + fn usage(&self) -> &str { + "Get the current datetime." + } + fn run( &self, args: CommandArgs, @@ -19,13 +33,6 @@ impl WholeStreamCommand for Date { ) -> Result { date(args, registry) } - fn name(&self) -> &str { - "date" - } - - fn signature(&self) -> Signature { - Signature::build("date").switch("utc").switch("local") - } } pub fn date_to_value(dt: DateTime, span: Span) -> Tagged diff --git a/src/commands/debug.rs b/src/commands/debug.rs index 9562aee38e..80da5fe1c6 100644 --- a/src/commands/debug.rs +++ b/src/commands/debug.rs @@ -5,14 +5,6 @@ use crate::prelude::*; pub struct Debug; impl WholeStreamCommand for Debug { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - debug(args, registry) - } - fn name(&self) -> &str { "debug" } @@ -20,6 +12,18 @@ impl WholeStreamCommand for Debug { fn signature(&self) -> Signature { Signature::build("debug") } + + fn usage(&self) -> &str { + "Debug input fed." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + debug(args, registry) + } } pub fn debug(args: CommandArgs, _registry: &CommandRegistry) -> Result { diff --git a/src/commands/enter.rs b/src/commands/enter.rs index 63316b7082..d2170b00d6 100644 --- a/src/commands/enter.rs +++ b/src/commands/enter.rs @@ -17,6 +17,10 @@ impl PerItemCommand for Enter { Signature::build("enter").required("location", SyntaxType::Block) } + fn usage(&self) -> &str { + "Create a new shell and begin at this path." + } + fn run( &self, call_info: &CallInfo, @@ -33,7 +37,13 @@ impl PerItemCommand for Enter { } => { let location = location.to_string(); let location_clone = location.to_string(); - if PathBuf::from(location).is_dir() { + + if registry.has(&location) { + Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell( + Value::string(location_clone).tagged(Tag::unknown()), + )))] + .into()) + } else if PathBuf::from(location).is_dir() { Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterShell( location_clone, )))] diff --git a/src/commands/exit.rs b/src/commands/exit.rs index ce5f1d19e9..feed8f7c4f 100644 --- a/src/commands/exit.rs +++ b/src/commands/exit.rs @@ -6,6 +6,19 @@ use crate::prelude::*; pub struct Exit; impl WholeStreamCommand for Exit { + fn name(&self) -> &str { + "exit" + } + + fn signature(&self) -> Signature { + Signature::build("exit") + .switch("now") + } + + fn usage(&self) -> &str { + "Exit the current shell (or all shells)" + } + fn run( &self, args: CommandArgs, @@ -13,14 +26,6 @@ impl WholeStreamCommand for Exit { ) -> Result { exit(args, registry) } - - fn name(&self) -> &str { - "exit" - } - - fn signature(&self) -> Signature { - Signature::build("exit").switch("now") - } } pub fn exit(args: CommandArgs, registry: &CommandRegistry) -> Result { diff --git a/src/commands/first.rs b/src/commands/first.rs index 48f1871fd9..af61dc8be5 100644 --- a/src/commands/first.rs +++ b/src/commands/first.rs @@ -6,6 +6,19 @@ use crate::prelude::*; pub struct First; impl WholeStreamCommand for First { + fn name(&self) -> &str { + "first" + } + + fn signature(&self) -> Signature { + Signature::build("first") + .required("amount", SyntaxType::Literal) + } + + fn usage(&self) -> &str { + "Show only the first number of rows." + } + fn run( &self, args: CommandArgs, @@ -13,14 +26,6 @@ impl WholeStreamCommand for First { ) -> Result { first(args, registry) } - - fn name(&self) -> &str { - "first" - } - - fn signature(&self) -> Signature { - Signature::build("first").required("amount", SyntaxType::Literal) - } } fn first(args: CommandArgs, registry: &CommandRegistry) -> Result { diff --git a/src/commands/from_array.rs b/src/commands/from_array.rs index 3fb04c9bfd..93ba87ecea 100644 --- a/src/commands/from_array.rs +++ b/src/commands/from_array.rs @@ -5,14 +5,6 @@ use crate::prelude::*; pub struct FromArray; impl WholeStreamCommand for FromArray { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - from_array(args, registry) - } - fn name(&self) -> &str { "from-array" } @@ -20,6 +12,18 @@ impl WholeStreamCommand for FromArray { fn signature(&self) -> Signature { Signature::build("from-array") } + + fn usage(&self) -> &str { + "Expand an array/list into rows" + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + from_array(args, registry) + } } fn from_array(args: CommandArgs, _registry: &CommandRegistry) -> Result { diff --git a/src/commands/from_bson.rs b/src/commands/from_bson.rs index 6b5ed571ce..0d5f05024f 100644 --- a/src/commands/from_bson.rs +++ b/src/commands/from_bson.rs @@ -7,14 +7,6 @@ use std::str::FromStr; pub struct FromBSON; impl WholeStreamCommand for FromBSON { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - from_bson(args, registry) - } - fn name(&self) -> &str { "from-bson" } @@ -22,6 +14,18 @@ impl WholeStreamCommand for FromBSON { fn signature(&self) -> Signature { Signature::build("from-bson") } + + fn usage(&self) -> &str { + "Parse text as .bson and create table." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + from_bson(args, registry) + } } fn convert_bson_value_to_nu_value(v: &Bson, tag: impl Into) -> Tagged { diff --git a/src/commands/from_csv.rs b/src/commands/from_csv.rs index 97aa981249..9f4a96da3e 100644 --- a/src/commands/from_csv.rs +++ b/src/commands/from_csv.rs @@ -16,7 +16,12 @@ impl WholeStreamCommand for FromCSV { } fn signature(&self) -> Signature { - Signature::build("from-csv").switch("headerless") + Signature::build("from-csv") + .switch("headerless") + } + + fn usage(&self) -> &str { + "Parse text as .csv and create table" } fn run( diff --git a/src/commands/from_ini.rs b/src/commands/from_ini.rs index d1f7bb4f8a..8495c4b221 100644 --- a/src/commands/from_ini.rs +++ b/src/commands/from_ini.rs @@ -6,14 +6,6 @@ use std::collections::HashMap; pub struct FromINI; impl WholeStreamCommand for FromINI { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - from_ini(args, registry) - } - fn name(&self) -> &str { "from-ini" } @@ -21,6 +13,18 @@ impl WholeStreamCommand for FromINI { fn signature(&self) -> Signature { Signature::build("from-ini") } + + fn usage(&self) -> &str { + "Parse text as .ini and create table" + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + from_ini(args, registry) + } } fn convert_ini_second_to_nu_value( diff --git a/src/commands/from_json.rs b/src/commands/from_json.rs index b4b1f7980e..e902d0a3de 100644 --- a/src/commands/from_json.rs +++ b/src/commands/from_json.rs @@ -15,7 +15,12 @@ impl WholeStreamCommand for FromJSON { } fn signature(&self) -> Signature { - Signature::build("from-json").switch("objects") + Signature::build("from-json") + .switch("objects") + } + + fn usage(&self) -> &str { + "Parse text as .json and create table." } fn run( diff --git a/src/commands/from_sqlite.rs b/src/commands/from_sqlite.rs index bc288ff396..88bd30375e 100644 --- a/src/commands/from_sqlite.rs +++ b/src/commands/from_sqlite.rs @@ -9,14 +9,6 @@ use std::path::Path; pub struct FromSQLite; impl WholeStreamCommand for FromSQLite { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - from_sqlite(args, registry) - } - fn name(&self) -> &str { "from-sqlite" } @@ -24,11 +16,11 @@ impl WholeStreamCommand for FromSQLite { fn signature(&self) -> Signature { Signature::build("from-sqlite") } -} -pub struct FromDB; + fn usage(&self) -> &str { + "Parse binary data as sqlite .db and create table." + } -impl WholeStreamCommand for FromDB { fn run( &self, args: CommandArgs, @@ -36,7 +28,11 @@ impl WholeStreamCommand for FromDB { ) -> Result { from_sqlite(args, registry) } +} +pub struct FromDB; + +impl WholeStreamCommand for FromDB { fn name(&self) -> &str { "from-db" } @@ -44,6 +40,18 @@ impl WholeStreamCommand for FromDB { fn signature(&self) -> Signature { Signature::build("from-db") } + + fn usage(&self) -> &str { + "Parse binary data as db and create table." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + from_sqlite(args, registry) + } } pub fn convert_sqlite_file_to_nu_value( diff --git a/src/commands/from_toml.rs b/src/commands/from_toml.rs index 6df13d6860..b4b341ecaa 100644 --- a/src/commands/from_toml.rs +++ b/src/commands/from_toml.rs @@ -5,14 +5,6 @@ use crate::prelude::*; pub struct FromTOML; impl WholeStreamCommand for FromTOML { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - from_toml(args, registry) - } - fn name(&self) -> &str { "from-toml" } @@ -20,6 +12,18 @@ impl WholeStreamCommand for FromTOML { fn signature(&self) -> Signature { Signature::build("from-toml") } + + fn usage(&self) -> &str { + "Parse text as .toml and create table." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + from_toml(args, registry) + } } pub fn convert_toml_value_to_nu_value(v: &toml::Value, tag: impl Into) -> Tagged { diff --git a/src/commands/from_tsv.rs b/src/commands/from_tsv.rs index ed37bf4531..366621d435 100644 --- a/src/commands/from_tsv.rs +++ b/src/commands/from_tsv.rs @@ -19,6 +19,10 @@ impl WholeStreamCommand for FromTSV { Signature::build("from-tsv").switch("headerless") } + fn usage(&self) -> &str { + "Parse text as .tsv and create table." + } + fn run( &self, args: CommandArgs, diff --git a/src/commands/from_xml.rs b/src/commands/from_xml.rs index adf39240de..4e4be72bc2 100644 --- a/src/commands/from_xml.rs +++ b/src/commands/from_xml.rs @@ -5,14 +5,6 @@ use crate::prelude::*; pub struct FromXML; impl WholeStreamCommand for FromXML { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - from_xml(args, registry) - } - fn name(&self) -> &str { "from-xml" } @@ -20,6 +12,18 @@ impl WholeStreamCommand for FromXML { fn signature(&self) -> Signature { Signature::build("from-xml") } + + fn usage(&self) -> &str { + "Parse text as .xml and create table." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + from_xml(args, registry) + } } fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>, tag: impl Into) -> Tagged { diff --git a/src/commands/from_yaml.rs b/src/commands/from_yaml.rs index a5f229a033..e67c045038 100644 --- a/src/commands/from_yaml.rs +++ b/src/commands/from_yaml.rs @@ -5,14 +5,6 @@ use crate::prelude::*; pub struct FromYAML; impl WholeStreamCommand for FromYAML { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - from_yaml(args, registry) - } - fn name(&self) -> &str { "from-yaml" } @@ -20,11 +12,11 @@ impl WholeStreamCommand for FromYAML { fn signature(&self) -> Signature { Signature::build("from-yaml") } -} -pub struct FromYML; + fn usage(&self) -> &str { + "Parse text as .yaml/.yml and create table." + } -impl WholeStreamCommand for FromYML { fn run( &self, args: CommandArgs, @@ -32,7 +24,11 @@ impl WholeStreamCommand for FromYML { ) -> Result { from_yaml(args, registry) } +} +pub struct FromYML; + +impl WholeStreamCommand for FromYML { fn name(&self) -> &str { "from-yml" } @@ -40,6 +36,18 @@ impl WholeStreamCommand for FromYML { fn signature(&self) -> Signature { Signature::build("from-yml") } + + fn usage(&self) -> &str { + "Parse text as .yaml/.yml and create table." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + from_yaml(args, registry) + } } fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value, tag: impl Into) -> Tagged { diff --git a/src/commands/get.rs b/src/commands/get.rs index cd8db615a7..7f0512a7bc 100644 --- a/src/commands/get.rs +++ b/src/commands/get.rs @@ -15,6 +15,14 @@ impl WholeStreamCommand for Get { "get" } + fn signature(&self) -> Signature { + Signature::build("get").rest(SyntaxType::Member) + } + + fn usage(&self) -> &str { + "Open given cells as text." + } + fn run( &self, args: CommandArgs, @@ -22,10 +30,6 @@ impl WholeStreamCommand for Get { ) -> Result { args.process(registry, get)?.run() } - - fn signature(&self) -> Signature { - Signature::build("get").rest(SyntaxType::Member) - } } fn get_member(path: &Tagged, obj: &Tagged) -> Result, ShellError> { diff --git a/src/commands/help.rs b/src/commands/help.rs new file mode 100644 index 0000000000..def2f33385 --- /dev/null +++ b/src/commands/help.rs @@ -0,0 +1,55 @@ +use crate::commands::command::CommandAction; +use crate::commands::PerItemCommand; +use crate::errors::ShellError; +use crate::parser::registry; +use crate::prelude::*; + +pub struct Help; + +impl PerItemCommand for Help { + fn name(&self) -> &str { + "help" + } + + fn signature(&self) -> registry::Signature { + Signature::build("help").rest(SyntaxType::Any) + } + + fn usage(&self) -> &str { + "Display help information about commands." + } + + fn run( + &self, + call_info: &CallInfo, + _registry: &CommandRegistry, + _raw_args: &RawCommandArgs, + _input: Tagged, + ) -> Result { + let span = call_info.name_span; + + if call_info.args.len() == 0 { + return Ok( + vec![ + Ok(ReturnSuccess::Action( + CommandAction::EnterHelpShell( + Tagged::from_simple_spanned_item(Value::nothing(), span) + )))].into() + ) + } + + match call_info.args.expect_nth(0)? { + Tagged { + item: Value::Primitive(Primitive::String(document)), + .. + } => Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell( + Tagged::from_simple_spanned_item(Value::string(document), span) + )))] + .into()), + x => Ok( + vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell(x.clone())))] + .into(), + ), + } + } +} diff --git a/src/commands/last.rs b/src/commands/last.rs index f776b7d654..29fe773775 100644 --- a/src/commands/last.rs +++ b/src/commands/last.rs @@ -6,6 +6,19 @@ use crate::prelude::*; pub struct Last; impl WholeStreamCommand for Last { + fn name(&self) -> &str { + "last" + } + + fn signature(&self) -> Signature { + Signature::build("last") + .required("amount", SyntaxType::Number) + } + + fn usage(&self) -> &str { + "Show only the last number of rows." + } + fn run( &self, args: CommandArgs, @@ -13,14 +26,6 @@ impl WholeStreamCommand for Last { ) -> Result { last(args, registry) } - - fn name(&self) -> &str { - "last" - } - - fn signature(&self) -> Signature { - Signature::build("last").required("amount", SyntaxType::Literal) - } } fn last(args: CommandArgs, registry: &CommandRegistry) -> Result { diff --git a/src/commands/lines.rs b/src/commands/lines.rs index e6ce32b3f2..0195177542 100644 --- a/src/commands/lines.rs +++ b/src/commands/lines.rs @@ -7,14 +7,6 @@ use log::trace; pub struct Lines; impl WholeStreamCommand for Lines { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - lines(args, registry) - } - fn name(&self) -> &str { "lines" } @@ -22,6 +14,18 @@ impl WholeStreamCommand for Lines { fn signature(&self) -> Signature { Signature::build("lines") } + + fn usage(&self) -> &str { + "Split single string into rows, one per line." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + lines(args, registry) + } } // TODO: "Amount remaining" wrapper diff --git a/src/commands/ls.rs b/src/commands/ls.rs index bc020c17d0..7096141507 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -5,14 +5,6 @@ use crate::prelude::*; pub struct LS; impl WholeStreamCommand for LS { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - ls(args, registry) - } - fn name(&self) -> &str { "ls" } @@ -20,6 +12,18 @@ impl WholeStreamCommand for LS { fn signature(&self) -> Signature { Signature::build("ls").optional("path", SyntaxType::Path) } + + fn usage(&self) -> &str { + "View the contents of the current or given path." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + ls(args, registry) + } } fn ls(args: CommandArgs, registry: &CommandRegistry) -> Result { diff --git a/src/commands/mkdir.rs b/src/commands/mkdir.rs index 96fd16afaf..9dec9a3142 100644 --- a/src/commands/mkdir.rs +++ b/src/commands/mkdir.rs @@ -12,6 +12,18 @@ pub struct MkdirArgs { } impl PerItemCommand for Mkdir { + fn name(&self) -> &str { + "mkdir" + } + + fn signature(&self) -> Signature { + Signature::build("mkdir").rest(SyntaxType::Path) + } + + fn usage(&self) -> &str { + "Make directories, creates intermediary directories as required." + } + fn run( &self, call_info: &CallInfo, @@ -21,14 +33,6 @@ impl PerItemCommand for Mkdir { ) -> Result { call_info.process(&raw_args.shell_manager, mkdir)?.run() } - - fn name(&self) -> &str { - "mkdir" - } - - fn signature(&self) -> Signature { - Signature::build("mkdir").rest(SyntaxType::Path) - } } fn mkdir(args: MkdirArgs, context: &RunnablePerItemContext) -> Result { diff --git a/src/commands/mv.rs b/src/commands/mv.rs index af93dde382..130e5996e8 100644 --- a/src/commands/mv.rs +++ b/src/commands/mv.rs @@ -25,6 +25,10 @@ impl PerItemCommand for Move { .named("file", SyntaxType::Any) } + fn usage(&self) -> &str { + "Move files or directories." + } + fn run( &self, call_info: &CallInfo, diff --git a/src/commands/next.rs b/src/commands/next.rs index de0d3dbe24..359f262312 100644 --- a/src/commands/next.rs +++ b/src/commands/next.rs @@ -6,14 +6,6 @@ use crate::prelude::*; pub struct Next; impl WholeStreamCommand for Next { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - next(args, registry) - } - fn name(&self) -> &str { "n" } @@ -21,6 +13,18 @@ impl WholeStreamCommand for Next { fn signature(&self) -> Signature { Signature::build("n") } + + fn usage(&self) -> &str { + "Go to next shell." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + next(args, registry) + } } fn next(_args: CommandArgs, _registry: &CommandRegistry) -> Result { diff --git a/src/commands/nth.rs b/src/commands/nth.rs index 5651d84123..98ab6a10a9 100644 --- a/src/commands/nth.rs +++ b/src/commands/nth.rs @@ -11,14 +11,6 @@ struct NthArgs { pub struct Nth; impl WholeStreamCommand for Nth { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - args.process(registry, nth)?.run() - } - fn name(&self) -> &str { "nth" } @@ -26,6 +18,18 @@ impl WholeStreamCommand for Nth { fn signature(&self) -> Signature { Signature::build("nth").required("amount", SyntaxType::Any) } + + fn usage(&self) -> &str { + "Return only the selected row" + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + args.process(registry, nth)?.run() + } } fn nth( diff --git a/src/commands/open.rs b/src/commands/open.rs index 205ad62ff7..202f8eae18 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -23,6 +23,10 @@ impl PerItemCommand for Open { .switch("raw") } + fn usage(&self) -> &str { + "Load a file into a cell, convert to table if possible (avoid by appending '--raw')" + } + fn run( &self, call_info: &CallInfo, diff --git a/src/commands/pick.rs b/src/commands/pick.rs index 6c7fca8f25..927edf8b3d 100644 --- a/src/commands/pick.rs +++ b/src/commands/pick.rs @@ -20,6 +20,10 @@ impl WholeStreamCommand for Pick { Signature::build("pick").rest(SyntaxType::Any) } + fn usage(&self) -> &str { + "Down-select table to only these columns." + } + fn run( &self, args: CommandArgs, diff --git a/src/commands/plugin.rs b/src/commands/plugin.rs index bd25db852b..a14cb1a609 100644 --- a/src/commands/plugin.rs +++ b/src/commands/plugin.rs @@ -51,6 +51,10 @@ impl WholeStreamCommand for PluginCommand { self.config.clone() } + fn usage(&self) -> &str { + &self.config.usage + } + fn run( &self, args: CommandArgs, @@ -270,6 +274,10 @@ impl WholeStreamCommand for PluginSink { self.config.clone() } + fn usage(&self) -> &str { + &self.config.usage + } + fn run( &self, args: CommandArgs, diff --git a/src/commands/post.rs b/src/commands/post.rs index adab330248..993605eb1f 100644 --- a/src/commands/post.rs +++ b/src/commands/post.rs @@ -27,6 +27,10 @@ impl PerItemCommand for Post { .switch("raw") } + fn usage(&self) -> &str { + "Post content to a url and retrieve data as a table if possible." + } + fn run( &self, call_info: &CallInfo, diff --git a/src/commands/prev.rs b/src/commands/prev.rs index 4291e93802..970cce3436 100644 --- a/src/commands/prev.rs +++ b/src/commands/prev.rs @@ -7,14 +7,6 @@ use crate::commands::WholeStreamCommand; pub struct Previous; impl WholeStreamCommand for Previous { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - previous(args, registry) - } - fn name(&self) -> &str { "p" } @@ -22,6 +14,18 @@ impl WholeStreamCommand for Previous { fn signature(&self) -> Signature { Signature::build("p") } + + fn usage(&self) -> &str { + "Go to previous shell." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + previous(args, registry) + } } fn previous(_args: CommandArgs, _registry: &CommandRegistry) -> Result { diff --git a/src/commands/ps.rs b/src/commands/ps.rs index 15a19a8578..b11e797961 100644 --- a/src/commands/ps.rs +++ b/src/commands/ps.rs @@ -12,14 +12,6 @@ use heim::units::{ratio, Ratio}; pub struct PS; impl WholeStreamCommand for PS { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - ps(args, registry) - } - fn name(&self) -> &str { "ps" } @@ -27,6 +19,18 @@ impl WholeStreamCommand for PS { fn signature(&self) -> Signature { Signature::build("ps") } + + fn usage(&self) -> &str { + "View current processes." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + ps(args, registry) + } } async fn usage(process: Process) -> ProcessResult<(process::Process, Ratio)> { diff --git a/src/commands/reject.rs b/src/commands/reject.rs index 92aff1cb2e..b519f8ea64 100644 --- a/src/commands/reject.rs +++ b/src/commands/reject.rs @@ -11,14 +11,6 @@ pub struct RejectArgs { pub struct Reject; impl WholeStreamCommand for Reject { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - args.process(registry, reject)?.run() - } - fn name(&self) -> &str { "reject" } @@ -26,6 +18,18 @@ impl WholeStreamCommand for Reject { fn signature(&self) -> Signature { Signature::build("reject").rest(SyntaxType::Member) } + + fn usage(&self) -> &str { + "Remove the given columns from the table." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + args.process(registry, reject)?.run() + } } fn reject( diff --git a/src/commands/reverse.rs b/src/commands/reverse.rs index 2b43f01470..8b81297249 100644 --- a/src/commands/reverse.rs +++ b/src/commands/reverse.rs @@ -6,14 +6,6 @@ use crate::prelude::*; pub struct Reverse; impl WholeStreamCommand for Reverse { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - reverse(args, registry) - } - fn name(&self) -> &str { "reverse" } @@ -21,6 +13,18 @@ impl WholeStreamCommand for Reverse { fn signature(&self) -> Signature { Signature::build("reverse") } + + fn usage(&self) -> &str { + "Reverses the table." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + reverse(args, registry) + } } fn reverse(args: CommandArgs, registry: &CommandRegistry) -> Result { diff --git a/src/commands/rm.rs b/src/commands/rm.rs index 36f7aa6d8a..60bb5c6e4a 100644 --- a/src/commands/rm.rs +++ b/src/commands/rm.rs @@ -24,6 +24,10 @@ impl PerItemCommand for Remove { .switch("recursive") } + fn usage(&self) -> &str { + "Remove a file, (for removing directory append '--recursive')" + } + fn run( &self, call_info: &CallInfo, diff --git a/src/commands/save.rs b/src/commands/save.rs index 953d90f966..4723c4bda6 100644 --- a/src/commands/save.rs +++ b/src/commands/save.rs @@ -23,6 +23,10 @@ impl WholeStreamCommand for Save { .switch("raw") } + fn usage(&self) -> &str { + "Save the contents of the pipeline to a file." + } + fn run( &self, args: CommandArgs, diff --git a/src/commands/shells.rs b/src/commands/shells.rs index f31a16fd56..5e0159e147 100644 --- a/src/commands/shells.rs +++ b/src/commands/shells.rs @@ -6,14 +6,6 @@ use crate::prelude::*; pub struct Shells; impl WholeStreamCommand for Shells { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - shells(args, registry) - } - fn name(&self) -> &str { "shells" } @@ -21,6 +13,18 @@ impl WholeStreamCommand for Shells { fn signature(&self) -> Signature { Signature::build("shells") } + + fn usage(&self) -> &str { + "Display the list of current shells." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + shells(args, registry) + } } fn shells(args: CommandArgs, _registry: &CommandRegistry) -> Result { diff --git a/src/commands/size.rs b/src/commands/size.rs index 2af7d47e89..02da0460cb 100644 --- a/src/commands/size.rs +++ b/src/commands/size.rs @@ -6,14 +6,6 @@ use crate::prelude::*; pub struct Size; impl WholeStreamCommand for Size { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - size(args, registry) - } - fn name(&self) -> &str { "size" } @@ -21,6 +13,18 @@ impl WholeStreamCommand for Size { fn signature(&self) -> Signature { Signature::build("size") } + + fn usage(&self) -> &str { + "Gather word count statistics on the text." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + size(args, registry) + } } fn size(args: CommandArgs, _registry: &CommandRegistry) -> Result { diff --git a/src/commands/skip_while.rs b/src/commands/skip_while.rs index d0237b16ad..90ba24b996 100644 --- a/src/commands/skip_while.rs +++ b/src/commands/skip_while.rs @@ -20,6 +20,10 @@ impl WholeStreamCommand for SkipWhile { .filter() } + fn usage(&self) -> &str { + "Skips rows while the condition matches." + } + fn run( &self, args: CommandArgs, diff --git a/src/commands/sort_by.rs b/src/commands/sort_by.rs index c538fdf97f..edce33b963 100644 --- a/src/commands/sort_by.rs +++ b/src/commands/sort_by.rs @@ -10,14 +10,6 @@ pub struct SortByArgs { } impl WholeStreamCommand for SortBy { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - args.process(registry, sort_by)?.run() - } - fn name(&self) -> &str { "sort-by" } @@ -25,6 +17,18 @@ impl WholeStreamCommand for SortBy { fn signature(&self) -> Signature { Signature::build("sort-by").rest(SyntaxType::String) } + + fn usage(&self) -> &str { + "Sort by the given columns." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + args.process(registry, sort_by)?.run() + } } fn sort_by( diff --git a/src/commands/split_column.rs b/src/commands/split_column.rs index ab5e7f5783..4bde5e25b0 100644 --- a/src/commands/split_column.rs +++ b/src/commands/split_column.rs @@ -15,14 +15,6 @@ struct SplitColumnArgs { pub struct SplitColumn; impl WholeStreamCommand for SplitColumn { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - args.process(registry, split_column)?.run() - } - fn name(&self) -> &str { "split-column" } @@ -33,6 +25,18 @@ impl WholeStreamCommand for SplitColumn { .switch("collapse-empty") .rest(SyntaxType::Member) } + + fn usage(&self) -> &str { + "Split row contents across multiple columns via the separator." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + args.process(registry, split_column)?.run() + } } fn split_column( diff --git a/src/commands/split_row.rs b/src/commands/split_row.rs index 592d301bea..fa95225f4f 100644 --- a/src/commands/split_row.rs +++ b/src/commands/split_row.rs @@ -12,6 +12,19 @@ struct SplitRowArgs { pub struct SplitRow; impl WholeStreamCommand for SplitRow { + fn name(&self) -> &str { + "split-row" + } + + fn signature(&self) -> Signature { + Signature::build("split-row") + .required("separator", SyntaxType::Any) + } + + fn usage(&self) -> &str { + "Split row contents over multiple rows via the separator." + } + fn run( &self, args: CommandArgs, @@ -19,14 +32,6 @@ impl WholeStreamCommand for SplitRow { ) -> Result { args.process(registry, split_row)?.run() } - - fn name(&self) -> &str { - "split-row" - } - - fn signature(&self) -> Signature { - Signature::build("split-row").required("separator", SyntaxType::Any) - } } fn split_row( diff --git a/src/commands/table.rs b/src/commands/table.rs index 0f58e34bf4..4efd6f821f 100644 --- a/src/commands/table.rs +++ b/src/commands/table.rs @@ -13,6 +13,15 @@ impl WholeStreamCommand for Table { fn name(&self) -> &str { "table" } + + fn signature(&self) -> Signature { + Signature::build("table") + } + + fn usage(&self) -> &str { + "View the contents of the pipeline as a table." + } + fn run( &self, args: CommandArgs, @@ -20,9 +29,6 @@ impl WholeStreamCommand for Table { ) -> Result { args.process(registry, table)?.run() } - fn signature(&self) -> Signature { - Signature::build("table") - } } pub fn table(_args: TableArgs, context: RunnableContext) -> Result { diff --git a/src/commands/tags.rs b/src/commands/tags.rs index 01c7565d55..973105709c 100644 --- a/src/commands/tags.rs +++ b/src/commands/tags.rs @@ -6,14 +6,6 @@ use crate::prelude::*; pub struct Tags; impl WholeStreamCommand for Tags { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - tags(args, registry) - } - fn name(&self) -> &str { "tags" } @@ -21,6 +13,18 @@ impl WholeStreamCommand for Tags { fn signature(&self) -> Signature { Signature::build("tags") } + + fn usage(&self) -> &str { + "Read the tags (metadata) for values." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + tags(args, registry) + } } fn tags(args: CommandArgs, _registry: &CommandRegistry) -> Result { diff --git a/src/commands/to_array.rs b/src/commands/to_array.rs index 43984ce58b..04c429e1b4 100644 --- a/src/commands/to_array.rs +++ b/src/commands/to_array.rs @@ -5,14 +5,6 @@ use crate::prelude::*; pub struct ToArray; impl WholeStreamCommand for ToArray { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - to_array(args, registry) - } - fn name(&self) -> &str { "to-array" } @@ -20,6 +12,18 @@ impl WholeStreamCommand for ToArray { fn signature(&self) -> Signature { Signature::build("to-array") } + + fn usage(&self) -> &str { + "Collapse rows into a single list." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + to_array(args, registry) + } } fn to_array(args: CommandArgs, registry: &CommandRegistry) -> Result { diff --git a/src/commands/to_bson.rs b/src/commands/to_bson.rs index 025484d8d3..64ba9aa4af 100644 --- a/src/commands/to_bson.rs +++ b/src/commands/to_bson.rs @@ -7,14 +7,6 @@ use std::convert::TryInto; pub struct ToBSON; impl WholeStreamCommand for ToBSON { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - to_bson(args, registry) - } - fn name(&self) -> &str { "to-bson" } @@ -22,6 +14,18 @@ impl WholeStreamCommand for ToBSON { fn signature(&self) -> Signature { Signature::build("to-bson") } + + fn usage(&self) -> &str { + "Convert table into .bson text." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + to_bson(args, registry) + } } pub fn value_to_bson_value(v: &Value) -> Bson { diff --git a/src/commands/to_csv.rs b/src/commands/to_csv.rs index 65651396ab..58ad208192 100644 --- a/src/commands/to_csv.rs +++ b/src/commands/to_csv.rs @@ -16,7 +16,12 @@ impl WholeStreamCommand for ToCSV { } fn signature(&self) -> Signature { - Signature::build("to-csv").switch("headerless") + Signature::build("to-csv") + .switch("headerless") + } + + fn usage(&self) -> &str { + "Convert table into .csv text " } fn run( diff --git a/src/commands/to_json.rs b/src/commands/to_json.rs index 3559459cdc..a1c0e22987 100644 --- a/src/commands/to_json.rs +++ b/src/commands/to_json.rs @@ -5,14 +5,6 @@ use crate::prelude::*; pub struct ToJSON; impl WholeStreamCommand for ToJSON { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - to_json(args, registry) - } - fn name(&self) -> &str { "to-json" } @@ -20,6 +12,18 @@ impl WholeStreamCommand for ToJSON { fn signature(&self) -> Signature { Signature::build("to-json") } + + fn usage(&self) -> &str { + "Convert table into .json text" + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + to_json(args, registry) + } } pub fn value_to_json_value(v: &Value) -> serde_json::Value { diff --git a/src/commands/to_sqlite.rs b/src/commands/to_sqlite.rs index fcbf96e3b3..dca953c235 100644 --- a/src/commands/to_sqlite.rs +++ b/src/commands/to_sqlite.rs @@ -8,14 +8,6 @@ use std::io::Read; pub struct ToSQLite; impl WholeStreamCommand for ToSQLite { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - to_sqlite(args, registry) - } - fn name(&self) -> &str { "to-sqlite" } @@ -23,11 +15,11 @@ impl WholeStreamCommand for ToSQLite { fn signature(&self) -> Signature { Signature::build("to-sqlite") } -} -pub struct ToDB; + fn usage(&self) -> &str { + "Convert table to sqlite .db binary data" + } -impl WholeStreamCommand for ToDB { fn run( &self, args: CommandArgs, @@ -35,7 +27,11 @@ impl WholeStreamCommand for ToDB { ) -> Result { to_sqlite(args, registry) } +} +pub struct ToDB; + +impl WholeStreamCommand for ToDB { fn name(&self) -> &str { "to-db" } @@ -43,6 +39,18 @@ impl WholeStreamCommand for ToDB { fn signature(&self) -> Signature { Signature::build("to-db") } + + fn usage(&self) -> &str { + "Convert table to db data" + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + to_sqlite(args, registry) + } } fn comma_concat(acc: String, current: String) -> String { diff --git a/src/commands/to_toml.rs b/src/commands/to_toml.rs index 5d60807390..d8216f9004 100644 --- a/src/commands/to_toml.rs +++ b/src/commands/to_toml.rs @@ -6,14 +6,6 @@ use crate::prelude::*; pub struct ToTOML; impl WholeStreamCommand for ToTOML { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - to_toml(args, registry) - } - fn name(&self) -> &str { "to-toml" } @@ -21,6 +13,18 @@ impl WholeStreamCommand for ToTOML { fn signature(&self) -> Signature { Signature::build("to-toml") } + + fn usage(&self) -> &str { + "Convert table into .toml text" + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + to_toml(args, registry) + } } pub fn value_to_toml_value(v: &Value) -> Result { diff --git a/src/commands/to_tsv.rs b/src/commands/to_tsv.rs index b999ce12d6..1a229d768e 100644 --- a/src/commands/to_tsv.rs +++ b/src/commands/to_tsv.rs @@ -16,7 +16,12 @@ impl WholeStreamCommand for ToTSV { } fn signature(&self) -> Signature { - Signature::build("to-tsv").switch("headerless") + Signature::build("to-tsv") + .switch("headerless") + } + + fn usage(&self) -> &str { + "Convert table into .tsv text" } fn run( diff --git a/src/commands/to_yaml.rs b/src/commands/to_yaml.rs index f0aa0219e0..9b91cbc0cc 100644 --- a/src/commands/to_yaml.rs +++ b/src/commands/to_yaml.rs @@ -5,14 +5,6 @@ use crate::prelude::*; pub struct ToYAML; impl WholeStreamCommand for ToYAML { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - to_yaml(args, registry) - } - fn name(&self) -> &str { "to-yaml" } @@ -20,6 +12,18 @@ impl WholeStreamCommand for ToYAML { fn signature(&self) -> Signature { Signature::build("to-yaml") } + + fn usage(&self) -> &str { + "Convert table into .yaml/.yml text" + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + to_yaml(args, registry) + } } pub fn value_to_yaml_value(v: &Value) -> serde_yaml::Value { diff --git a/src/commands/trim.rs b/src/commands/trim.rs index 22a29a36b6..66152843f0 100644 --- a/src/commands/trim.rs +++ b/src/commands/trim.rs @@ -6,14 +6,6 @@ use crate::prelude::*; pub struct Trim; impl WholeStreamCommand for Trim { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - trim(args, registry) - } - fn name(&self) -> &str { "trim" } @@ -21,6 +13,18 @@ impl WholeStreamCommand for Trim { fn signature(&self) -> Signature { Signature::build("trim") } + + fn usage(&self) -> &str { + "Trim leading and following whitespace from text data." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + trim(args, registry) + } } fn trim(args: CommandArgs, _registry: &CommandRegistry) -> Result { diff --git a/src/commands/version.rs b/src/commands/version.rs index e13017ab51..def335420a 100644 --- a/src/commands/version.rs +++ b/src/commands/version.rs @@ -8,14 +8,6 @@ use indexmap::IndexMap; pub struct Version; impl WholeStreamCommand for Version { - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - date(args, registry) - } - fn name(&self) -> &str { "version" } @@ -23,6 +15,18 @@ impl WholeStreamCommand for Version { fn signature(&self) -> Signature { Signature::build("version") } + + fn usage(&self) -> &str { + "Display Nu version" + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + date(args, registry) + } } pub fn date(args: CommandArgs, registry: &CommandRegistry) -> Result { diff --git a/src/commands/vtable.rs b/src/commands/vtable.rs index 4e26c05efd..5abd4c6d1f 100644 --- a/src/commands/vtable.rs +++ b/src/commands/vtable.rs @@ -12,6 +12,15 @@ impl WholeStreamCommand for VTable { fn name(&self) -> &str { "vtable" } + + fn signature(&self) -> Signature { + Signature::build("vtable") + } + + fn usage(&self) -> &str { + "View the contents of the pipeline as a vertical (rotated) table." + } + fn run( &self, args: CommandArgs, @@ -19,9 +28,6 @@ impl WholeStreamCommand for VTable { ) -> Result { args.process(registry, vtable)?.run() } - fn signature(&self) -> Signature { - Signature::build("vtable") - } } pub fn vtable(_args: VTableArgs, context: RunnableContext) -> Result { diff --git a/src/commands/where_.rs b/src/commands/where_.rs index 5f037ded43..b09c341b4a 100644 --- a/src/commands/where_.rs +++ b/src/commands/where_.rs @@ -12,7 +12,12 @@ impl PerItemCommand for Where { } fn signature(&self) -> registry::Signature { - Signature::build("where").required("condition", SyntaxType::Block) + Signature::build("where") + .required("condition", SyntaxType::Block) + } + + fn usage(&self) -> &str { + "Filter table to match the condition." } fn run( diff --git a/src/commands/which_.rs b/src/commands/which_.rs index 0ffbc19dba..fdd722d892 100644 --- a/src/commands/which_.rs +++ b/src/commands/which_.rs @@ -8,6 +8,19 @@ use crate::parser::registry::Signature; pub struct Which; impl WholeStreamCommand for Which { + fn name(&self) -> &str { + "which" + } + + fn signature(&self) -> Signature { + Signature::build("which") + .required("name", SyntaxType::Any) + } + + fn usage(&self) -> &str { + "Finds a program file." + } + fn run( &self, args: CommandArgs, @@ -15,13 +28,6 @@ impl WholeStreamCommand for Which { ) -> Result { which(args, registry) } - fn name(&self) -> &str { - "which" - } - - fn signature(&self) -> Signature { - Signature::build("which").required("name", SyntaxType::Any) - } } pub fn which(args: CommandArgs, registry: &CommandRegistry) -> Result { diff --git a/src/context.rs b/src/context.rs index 5bade25f21..577a55c20d 100644 --- a/src/context.rs +++ b/src/context.rs @@ -53,7 +53,7 @@ impl CommandRegistry { registry.get(name).map(|c| c.clone()) } - fn has(&self, name: &str) -> bool { + pub(crate) fn has(&self, name: &str) -> bool { let registry = self.registry.lock().unwrap(); registry.contains_key(name) diff --git a/src/object.rs b/src/object.rs index dc5ecfc085..e2a8df1020 100644 --- a/src/object.rs +++ b/src/object.rs @@ -1,4 +1,5 @@ pub(crate) mod base; +pub(crate) mod command; pub(crate) mod config; pub(crate) mod dict; pub(crate) mod files; @@ -8,5 +9,6 @@ pub(crate) mod types; #[allow(unused)] pub(crate) use base::{Block, Primitive, Switch, Value}; -pub(crate) use dict::{Dictionary, TaggedDictBuilder}; +pub(crate) use dict::{Dictionary, TaggedListBuilder, TaggedDictBuilder}; pub(crate) use files::dir_entry_dict; +pub(crate) use command::command_dict; diff --git a/src/object/command.rs b/src/object/command.rs new file mode 100644 index 0000000000..317fe5fa34 --- /dev/null +++ b/src/object/command.rs @@ -0,0 +1,67 @@ +use crate::commands::command::Command; +use crate::object::{TaggedDictBuilder, TaggedListBuilder, Value}; +use crate::parser::registry::{NamedType, PositionalType, Signature}; +use crate::prelude::*; +use std::ops::Deref; + +pub(crate) fn command_dict(command: Arc, tag: impl Into) -> Tagged { + let tag = tag.into(); + + let mut cmd_dict = TaggedDictBuilder::new(tag); + + cmd_dict.insert("name", Value::string(command.name())); + + cmd_dict.insert( + "type", + Value::string(match command.deref() { + Command::WholeStream(_) => "Command", + Command::PerItem(_) => "Filter", + }), + ); + + cmd_dict.insert_tagged("signature", signature_dict(command.signature(), tag)); + cmd_dict.insert("usage", Value::string(command.usage())); + + cmd_dict.into_tagged_value() +} + +fn for_spec(name: &str, ty: &str, required: bool, tag: impl Into) -> Tagged { + let tag = tag.into(); + + let mut spec = TaggedDictBuilder::new(tag); + + spec.insert("name", Value::string(name)); + spec.insert("type", Value::string(ty)); + spec.insert("required", Value::string(if required { "yes" } else { "no" })); + + spec.into_tagged_value() +} + +fn signature_dict(signature: Signature, tag: impl Into) -> Tagged { + let tag = tag.into(); + let mut sig = TaggedListBuilder::new(tag); + + for arg in signature.positional.iter() { + let is_required = match arg { + PositionalType::Mandatory(_,_) => true, + PositionalType::Optional(_,_) => false, + }; + + sig.insert_tagged(for_spec(arg.name(), "argument", is_required, tag)); + } + + if let Some(_) = signature.rest_positional { + let is_required = false; + sig.insert_tagged(for_spec("rest", "argument", is_required, tag)); + } + + for (name, ty) in signature.named.iter() { + match ty { + NamedType::Mandatory(_) => sig.insert_tagged(for_spec(name, "flag", true, tag)), + NamedType::Optional(_) => sig.insert_tagged(for_spec(name, "flag", false, tag)), + NamedType::Switch => sig.insert_tagged(for_spec(name, "switch", false, tag)), + } + } + + sig.into_tagged_value() +} diff --git a/src/object/dict.rs b/src/object/dict.rs index b090e4ef71..2f85fcfa65 100644 --- a/src/object/dict.rs +++ b/src/object/dict.rs @@ -1,5 +1,4 @@ use crate::prelude::*; - use crate::object::{Primitive, Value}; use derive_new::new; use indexmap::IndexMap; diff --git a/src/parser/hir/baseline_parse_tokens.rs b/src/parser/hir/baseline_parse_tokens.rs index a1119bc765..89bffc3f5f 100644 --- a/src/parser/hir/baseline_parse_tokens.rs +++ b/src/parser/hir/baseline_parse_tokens.rs @@ -49,6 +49,24 @@ pub enum SyntaxType { Boolean, } +impl std::fmt::Display for SyntaxType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + SyntaxType::Any => write!(f, "Any"), + SyntaxType::List => write!(f, "List"), + SyntaxType::Literal => write!(f, "Literal"), + SyntaxType::String => write!(f, "String"), + SyntaxType::Member => write!(f, "Member"), + SyntaxType::Variable => write!(f, "Variable"), + SyntaxType::Number => write!(f, "Number"), + SyntaxType::Path => write!(f, "Path"), + SyntaxType::Binary => write!(f, "Binary"), + SyntaxType::Block => write!(f, "Block"), + SyntaxType::Boolean => write!(f, "Boolean") + } + } +} + pub fn baseline_parse_next_expr( tokens: &mut TokensIterator, context: &Context, diff --git a/src/parser/registry.rs b/src/parser/registry.rs index 52d49ea5c0..7d22e4f85d 100644 --- a/src/parser/registry.rs +++ b/src/parser/registry.rs @@ -73,6 +73,8 @@ impl PositionalType { pub struct Signature { pub name: String, #[new(default)] + pub usage: String, + #[new(default)] pub positional: Vec, #[new(value = "None")] pub rest_positional: Option, @@ -87,6 +89,11 @@ impl Signature { Signature::new(name.into()) } + pub fn desc(mut self, usage: impl Into) -> Signature { + self.usage = usage.into(); + self + } + pub fn required(mut self, name: impl Into, ty: impl Into) -> Signature { self.positional .push(PositionalType::Mandatory(name.into(), ty.into())); diff --git a/src/plugins/add.rs b/src/plugins/add.rs index 93c519212e..27a12e677e 100644 --- a/src/plugins/add.rs +++ b/src/plugins/add.rs @@ -43,6 +43,7 @@ impl Add { impl Plugin for Add { fn config(&mut self) -> Result { Ok(Signature::build("add") + .desc("Add a new field to the table.") .required("Field", SyntaxType::String) .required("Value", SyntaxType::String) .rest(SyntaxType::String).filter()) diff --git a/src/plugins/binaryview.rs b/src/plugins/binaryview.rs index fb9c2213a2..7601621cd1 100644 --- a/src/plugins/binaryview.rs +++ b/src/plugins/binaryview.rs @@ -12,7 +12,9 @@ impl BinaryView { impl Plugin for BinaryView { fn config(&mut self) -> Result { - Ok(Signature::build("binaryview").switch("lores")) + Ok(Signature::build("binaryview") + .desc("Autoview of binary data.") + .switch("lores")) } fn sink(&mut self, call_info: CallInfo, input: Vec>) { diff --git a/src/plugins/edit.rs b/src/plugins/edit.rs index 902c038bc1..ab8a25aa68 100644 --- a/src/plugins/edit.rs +++ b/src/plugins/edit.rs @@ -42,6 +42,7 @@ impl Edit { impl Plugin for Edit { fn config(&mut self) -> Result { Ok(Signature::build("edit") + .desc("Edit an existing field to have a new value.") .required("Field", SyntaxType::String) .required("Value", SyntaxType::String) .filter()) diff --git a/src/plugins/inc.rs b/src/plugins/inc.rs index ece83b7f21..5e6a2a293f 100644 --- a/src/plugins/inc.rs +++ b/src/plugins/inc.rs @@ -70,7 +70,7 @@ impl Inc { self.error = Some(message.to_string()); } - fn usage(&self) -> &'static str { + pub fn usage() -> &'static str { "Usage: inc field [--major|--minor|--patch]" } @@ -116,6 +116,7 @@ impl Inc { impl Plugin for Inc { fn config(&mut self) -> Result { Ok(Signature::build("inc") + .desc("Increment a value or version. Optional use the field of a table.") .switch("major") .switch("minor") .switch("patch") @@ -159,7 +160,7 @@ impl Plugin for Inc { match &self.error { Some(reason) => { - return Err(ShellError::string(format!("{}: {}", reason, self.usage()))) + return Err(ShellError::string(format!("{}: {}", reason, Inc::usage()))) } None => Ok(vec![]), } diff --git a/src/plugins/skip.rs b/src/plugins/skip.rs index 6f78351fee..bb80534218 100644 --- a/src/plugins/skip.rs +++ b/src/plugins/skip.rs @@ -1,4 +1,3 @@ -use indexmap::IndexMap; use nu::{ serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature, SyntaxType, Tagged, Value, @@ -15,13 +14,10 @@ impl Skip { impl Plugin for Skip { fn config(&mut self) -> Result { - Ok(Signature { - name: "skip".to_string(), - positional: vec![], - is_filter: true, - named: IndexMap::new(), - rest_positional: Some(SyntaxType::Number), - }) + Ok(Signature::build("skip") + .desc("Skip a number of rows") + .rest(SyntaxType::Number) + .filter()) } fn begin_filter(&mut self, call_info: CallInfo) -> Result, ShellError> { if let Some(args) = call_info.args.positional { diff --git a/src/plugins/str.rs b/src/plugins/str.rs index 0656d5f780..8aa24b4907 100644 --- a/src/plugins/str.rs +++ b/src/plugins/str.rs @@ -124,7 +124,7 @@ impl Str { } } - fn usage(&self) -> &'static str { + pub fn usage() -> &'static str { "Usage: str field [--downcase|--upcase|--to-int|--replace|--find-replace]" } } @@ -154,7 +154,7 @@ impl Str { None => Err(ShellError::string(format!( "{}: {}", "str needs a field when applying it to a value in an object", - self.usage() + Str::usage() ))), }, x => Err(ShellError::string(format!( @@ -168,6 +168,7 @@ impl Str { impl Plugin for Str { fn config(&mut self) -> Result { Ok(Signature::build("str") + .desc("Apply string function. Optional use the field of a table") .switch("downcase") .switch("upcase") .switch("to-int") @@ -240,7 +241,7 @@ impl Plugin for Str { match &self.error { Some(reason) => { - return Err(ShellError::string(format!("{}: {}", reason, self.usage()))) + return Err(ShellError::string(format!("{}: {}", reason, Str::usage()))) } None => Ok(vec![]), } diff --git a/src/plugins/sum.rs b/src/plugins/sum.rs index 1c983b1ad8..bd30cef98e 100644 --- a/src/plugins/sum.rs +++ b/src/plugins/sum.rs @@ -64,7 +64,9 @@ impl Sum { impl Plugin for Sum { fn config(&mut self) -> Result { - Ok(Signature::build("sum").filter()) + Ok(Signature::build("sum") + .desc("Sum a column of values.") + .filter()) } fn begin_filter(&mut self, _: CallInfo) -> Result, ShellError> { diff --git a/src/plugins/sys.rs b/src/plugins/sys.rs index 74d87befe0..e7ff919d8f 100644 --- a/src/plugins/sys.rs +++ b/src/plugins/sys.rs @@ -309,7 +309,9 @@ async fn sysinfo(tag: Tag) -> Vec> { impl Plugin for Sys { fn config(&mut self) -> Result { - Ok(Signature::build("sys").filter()) + Ok(Signature::build("sys") + .desc("View information about the current system.") + .filter()) } fn begin_filter(&mut self, callinfo: CallInfo) -> Result, ShellError> { diff --git a/src/plugins/textview.rs b/src/plugins/textview.rs index 81097179a5..81db9dd194 100644 --- a/src/plugins/textview.rs +++ b/src/plugins/textview.rs @@ -26,7 +26,8 @@ impl TextView { impl Plugin for TextView { fn config(&mut self) -> Result { - Ok(Signature::build("textview")) + Ok(Signature::build("textview") + .desc("Autoview of text data.")) } fn sink(&mut self, call_info: CallInfo, input: Vec>) { diff --git a/src/plugins/tree.rs b/src/plugins/tree.rs index 9784e854c3..f57a705eca 100644 --- a/src/plugins/tree.rs +++ b/src/plugins/tree.rs @@ -80,7 +80,8 @@ struct TreeViewer; impl Plugin for TreeViewer { fn config(&mut self) -> Result { - Ok(Signature::build("tree")) + Ok(Signature::build("tree") + .desc("View the contents of the pipeline as a tree.")) } fn sink(&mut self, _call_info: CallInfo, input: Vec>) { diff --git a/src/prelude.rs b/src/prelude.rs index 8e511f82cd..d781ff22ce 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -68,6 +68,7 @@ pub(crate) use crate::parser::registry::Signature; pub(crate) use crate::shell::filesystem_shell::FilesystemShell; pub(crate) use crate::shell::shell_manager::ShellManager; pub(crate) use crate::shell::value_shell::ValueShell; +pub(crate) use crate::shell::help_shell::HelpShell; pub(crate) use crate::stream::{InputStream, OutputStream}; pub(crate) use crate::traits::{HasSpan, ToDebug}; pub(crate) use crate::Span; diff --git a/src/shell.rs b/src/shell.rs index 77670c5ec7..caa1443ac7 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -4,5 +4,6 @@ pub(crate) mod helper; pub(crate) mod shell; pub(crate) mod shell_manager; pub(crate) mod value_shell; +pub(crate) mod help_shell; pub(crate) use helper::Helper; diff --git a/src/shell/help_shell.rs b/src/shell/help_shell.rs new file mode 100644 index 0000000000..59f141b8c0 --- /dev/null +++ b/src/shell/help_shell.rs @@ -0,0 +1,234 @@ +use crate::commands::command::EvaluatedWholeStreamCommandArgs; +use crate::commands::cp::CopyArgs; +use crate::commands::mkdir::MkdirArgs; +use crate::commands::mv::MoveArgs; +use crate::commands::rm::RemoveArgs; +use crate::context::SourceMap; +use crate::object::{TaggedDictBuilder, command_dict}; +use crate::prelude::*; +use crate::shell::shell::Shell; +use std::ffi::OsStr; +use std::path::PathBuf; + +#[derive(Clone, Debug)] +pub struct HelpShell { + pub(crate) path: String, + pub(crate) value: Tagged, +} + +impl HelpShell { + pub fn index(registry: &CommandRegistry) -> Result { + let mut cmds = TaggedDictBuilder::new(Tag::unknown()); + let mut specs = Vec::new(); + + for cmd in registry.names() { + let mut spec = TaggedDictBuilder::new(Tag::unknown()); + let value = command_dict(registry.get_command(&cmd).unwrap(), Tag::unknown()); + + spec.insert("name", cmd); + spec.insert("description", value.get_data_by_key("usage").unwrap().as_string().unwrap()); + spec.insert_tagged("details", value); + + specs.push(spec.into_tagged_value()); + } + + cmds.insert("help", Value::List(specs)); + + Ok(HelpShell { + path: "/help".to_string(), + value: cmds.into_tagged_value(), + }) + } + + pub fn for_command( + cmd: Tagged, + registry: &CommandRegistry, + ) -> Result { + let mut sh = HelpShell::index(®istry)?; + + if let Tagged { + item: Value::Primitive(Primitive::String(name)), .. + } = cmd { + sh.set_path(format!("/help/{:}/details", name)); + } + + Ok(sh) + } + + fn commands(&self) -> VecDeque> { + let mut cmds = VecDeque::new(); + let full_path = PathBuf::from(&self.path); + + let mut viewed = self.value.clone(); + let sep_string = std::path::MAIN_SEPARATOR.to_string(); + let sep = OsStr::new(&sep_string); + + for p in full_path.iter() { + match p { + x if x == sep => {} + step => match viewed.get_data_by_key(step.to_str().unwrap()) { + Some(v) => { + viewed = v.clone(); + } + _ => {} + }, + } + } + match viewed { + Tagged { + item: Value::List(l), + .. + } => { + for item in l { + cmds.push_back(item.clone()); + } + } + x => { + cmds.push_back(x.clone()); + } + } + + cmds + } +} + +impl Shell for HelpShell { + fn name(&self, source_map: &SourceMap) -> String { + let origin_name = self.value.origin_name(source_map); + format!( + "{}", + match origin_name { + Some(x) => format!("{{{}}}", x), + None => format!("<{}>", self.value.item.type_name(),), + } + ) + } + + fn homedir(&self) -> Option { + dirs::home_dir() + } + + fn path(&self) -> String { + self.path.clone() + } + + fn set_path(&mut self, path: String) { + let _ = std::env::set_current_dir(&path); + self.path = path.clone(); + } + + fn ls(&self, _args: EvaluatedWholeStreamCommandArgs) -> Result { + Ok(self + .commands() + .map(|x| ReturnSuccess::value(x)) + .to_output_stream()) + } + + fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result { + let path = match args.nth(0) { + None => "/".to_string(), + Some(v) => { + let target = v.as_path()?; + + let mut cwd = PathBuf::from(&self.path); + + if target == PathBuf::from("..") { + cwd.pop(); + } else { + match target.to_str() { + Some(target) => match target.chars().nth(0) { + Some(x) if x == '/' => cwd = PathBuf::from(target), + _ => cwd.push(target), + }, + None => cwd.push(target), + } + } + cwd.to_string_lossy().to_string() + } + }; + + let mut stream = VecDeque::new(); + stream.push_back(ReturnSuccess::change_cwd(path)); + Ok(stream.into()) + } + + fn cp(&self, _args: CopyArgs, _name: Span, _path: &str) -> Result { + Ok(OutputStream::empty()) + } + + fn mv(&self, _args: MoveArgs, _name: Span, _path: &str) -> Result { + Ok(OutputStream::empty()) + } + + fn mkdir( + &self, + _args: MkdirArgs, + _name: Span, + _path: &str, + ) -> Result { + Ok(OutputStream::empty()) + } + + fn rm(&self, _args: RemoveArgs, _name: Span, _path: &str) -> Result { + Ok(OutputStream::empty()) + } + + fn complete( + &self, + line: &str, + pos: usize, + _ctx: &rustyline::Context<'_>, + ) -> Result<(usize, Vec), rustyline::error::ReadlineError> { + let mut completions = vec![]; + + let mut possible_completion = vec![]; + let commands = self.commands(); + for cmd in commands { + match cmd { + Tagged { item, .. } => { + for desc in item.data_descriptors() { + possible_completion.push(desc); + } + } + } + } + + let line_chars: Vec<_> = line.chars().collect(); + let mut replace_pos = pos; + while replace_pos > 0 { + if line_chars[replace_pos - 1] == ' ' { + break; + } + replace_pos -= 1; + } + + for command in possible_completion.iter() { + let mut pos = replace_pos; + let mut matched = true; + if pos < line_chars.len() { + for chr in command.chars() { + if line_chars[pos] != chr { + matched = false; + break; + } + pos += 1; + if pos == line_chars.len() { + break; + } + } + } + + if matched { + completions.push(rustyline::completion::Pair { + display: command.to_string(), + replacement: command.to_string(), + }); + } + } + Ok((replace_pos, completions)) + } + + fn hint(&self, _line: &str, _pos: usize, _ctx: &rustyline::Context<'_>) -> Option { + None + } +} diff --git a/src/shell/shell.rs b/src/shell/shell.rs index 4157cacb68..dc1f104b6f 100644 --- a/src/shell/shell.rs +++ b/src/shell/shell.rs @@ -12,6 +12,7 @@ use std::path::PathBuf; pub trait Shell: std::fmt::Debug { fn name(&self, source_map: &SourceMap) -> String; fn homedir(&self) -> Option; + fn ls(&self, args: EvaluatedWholeStreamCommandArgs) -> Result; fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result; fn cp(&self, args: CopyArgs, name: Span, path: &str) -> Result; diff --git a/tests/filters_test.rs b/tests/filters_test.rs index 33baf67fe3..d7bfd10644 100644 --- a/tests/filters_test.rs +++ b/tests/filters_test.rs @@ -19,10 +19,10 @@ fn converts_structured_table_to_csv_text() { sandbox.with_files(vec![FileWithContentToBeTrimmed( "csv_text_sample.txt", r#" - importer,shipper,tariff_item,name,origin - Plasticos Rival,Reverte,2509000000,Calcium carbonate,Spain - Tigre Ecuador,OMYA Andina,3824909999,Calcium carbonate,Colombia - "#, + importer,shipper,tariff_item,name,origin + Plasticos Rival,Reverte,2509000000,Calcium carbonate,Spain + Tigre Ecuador,OMYA Andina,3824909999,Calcium carbonate,Colombia + "#, )]); let actual = nu!( @@ -49,10 +49,10 @@ fn converts_structured_table_to_csv_text_skipping_headers_after_conversion() { sandbox.with_files(vec![FileWithContentToBeTrimmed( "csv_text_sample.txt", r#" - importer,shipper,tariff_item,name,origin - Plasticos Rival,Reverte,2509000000,Calcium carbonate,Spain - Tigre Ecuador,OMYA Andina,3824909999,Calcium carbonate,Colombia - "#, + importer,shipper,tariff_item,name,origin + Plasticos Rival,Reverte,2509000000,Calcium carbonate,Spain + Tigre Ecuador,OMYA Andina,3824909999,Calcium carbonate,Colombia + "#, )]); let actual = nu!( @@ -75,19 +75,19 @@ fn converts_structured_table_to_csv_text_skipping_headers_after_conversion() { fn converts_from_csv_text_to_structured_table() { Playground::setup("filter_from_csv_test_1", |dirs, sandbox| { sandbox.with_files(vec![FileWithContentToBeTrimmed( - "los_tres_amigos.txt", + "los_tres_caballeros.txt", r#" - first_name,last_name,rusty_luck - Andrés,Robalino,1 - Jonathan,Turner,1 - Yehuda,Katz,1 - "#, + first_name,last_name,rusty_luck + Andrés,Robalino,1 + Jonathan,Turner,1 + Yehuda,Katz,1 + "#, )]); let actual = nu!( cwd: dirs.test(), h::pipeline( r#" - open los_tres_amigos.txt + open los_tres_caballeros.txt | from-csv | get rusty_luck | str --to-int @@ -106,11 +106,11 @@ fn converts_from_csv_text_skipping_headers_to_structured_table() { sandbox.with_files(vec![FileWithContentToBeTrimmed( "los_tres_amigos.txt", r#" - first_name,last_name,rusty_luck - Andrés,Robalino,1 - Jonathan,Turner,1 - Yehuda,Katz,1 - "#, + first_name,last_name,rusty_luck + Andrés,Robalino,1 + Jonathan,Turner,1 + Yehuda,Katz,1 + "#, )]); let actual = nu!( @@ -151,15 +151,15 @@ fn converts_from_json_text_to_structured_table() { sandbox.with_files(vec![FileWithContentToBeTrimmed( "katz.txt", r#" - { - "katz": [ - {"name": "Yehuda", "rusty_luck": 1}, - {"name": "Jonathan", "rusty_luck": 1}, - {"name": "Andres", "rusty_luck": 1}, - {"name":"GorbyPuff", "rusty_luck": 1} - ] - } - "#, + { + "katz": [ + {"name": "Yehuda", "rusty_luck": 1}, + {"name": "Jonathan", "rusty_luck": 1}, + {"name": "Andres", "rusty_luck": 1}, + {"name":"GorbyPuff", "rusty_luck": 1} + ] + } + "#, )]); let actual = nu!( @@ -177,11 +177,11 @@ fn converts_from_json_text_recognizing_objects_independendtly_to_structured_tabl sandbox.with_files(vec![FileWithContentToBeTrimmed( "katz.txt", r#" - {"name": "Yehuda", "rusty_luck": 1} - {"name": "Jonathan", "rusty_luck": 1} - {"name": "Andres", "rusty_luck": 1} - {"name":"GorbyPuff", "rusty_luck": 3} - "#, + {"name": "Yehuda", "rusty_luck": 1} + {"name": "Jonathan", "rusty_luck": 1} + {"name": "Andres", "rusty_luck": 1} + {"name":"GorbyPuff", "rusty_luck": 3} + "#, )]); let actual = nu!( @@ -205,9 +205,9 @@ fn converts_structured_table_to_json_text() { sandbox.with_files(vec![FileWithContentToBeTrimmed( "sample.txt", r#" - JonAndrehudaTZ,3 - GorbyPuff,100 - "#, + JonAndrehudaTZ,3 + GorbyPuff,100 + "#, )]); let actual = nu!( @@ -245,10 +245,10 @@ fn converts_structured_table_to_tsv_text() { sandbox.with_files(vec![FileWithContentToBeTrimmed( "tsv_text_sample.txt", r#" - importer shipper tariff_item name origin - Plasticos Rival Reverte 2509000000 Calcium carbonate Spain - Tigre Ecuador OMYA Andina 3824909999 Calcium carbonate Colombia - "#, + importer shipper tariff_item name origin + Plasticos Rival Reverte 2509000000 Calcium carbonate Spain + Tigre Ecuador OMYA Andina 3824909999 Calcium carbonate Colombia + "#, )]); let actual = nu!( @@ -275,10 +275,10 @@ fn converts_structured_table_to_tsv_text_skipping_headers_after_conversion() { sandbox.with_files(vec![FileWithContentToBeTrimmed( "tsv_text_sample.txt", r#" - importer shipper tariff_item name origin - Plasticos Rival Reverte 2509000000 Calcium carbonate Spain - Tigre Ecuador OMYA Andina 3824909999 Calcium carbonate Colombia - "#, + importer shipper tariff_item name origin + Plasticos Rival Reverte 2509000000 Calcium carbonate Spain + Tigre Ecuador OMYA Andina 3824909999 Calcium carbonate Colombia + "#, )]); let actual = nu!( @@ -303,11 +303,11 @@ fn converts_from_tsv_text_to_structured_table() { sandbox.with_files(vec![FileWithContentToBeTrimmed( "los_tres_amigos.txt", r#" - first Name Last Name rusty_luck - Andrés Robalino 1 - Jonathan Turner 1 - Yehuda Katz 1 - "#, + first Name Last Name rusty_luck + Andrés Robalino 1 + Jonathan Turner 1 + Yehuda Katz 1 + "#, )]); let actual = nu!( @@ -332,11 +332,11 @@ fn converts_from_tsv_text_skipping_headers_to_structured_table() { sandbox.with_files(vec![FileWithContentToBeTrimmed( "los_tres_amigos.txt", r#" - first Name Last Name rusty_luck - Andrés Robalino 1 - Jonathan Turner 1 - Yehuda Katz 1 - "#, + first Name Last Name rusty_luck + Andrés Robalino 1 + Jonathan Turner 1 + Yehuda Katz 1 + "#, )]); let actual = nu!( @@ -359,14 +359,15 @@ fn converts_from_tsv_text_skipping_headers_to_structured_table() { fn can_convert_table_to_bson_and_back_into_table() { let actual = nu!( cwd: "tests/fixtures/formats", h::pipeline( - r#" - open sample.bson - | to-bson - | from-bson - | get root - | nth 1 - | get b - | echo $it"# + r#" + open sample.bson + | to-bson + | from-bson + | get root + | nth 1 + | get b + | echo $it + "# )); assert_eq!(actual, "whel"); @@ -376,14 +377,15 @@ fn can_convert_table_to_bson_and_back_into_table() { fn can_convert_table_to_sqlite_and_back_into_table() { let actual = nu!( cwd: "tests/fixtures/formats", h::pipeline( - r#" - open sample.db - | to-sqlite - | from-sqlite - | get table_values - | nth 2 - | get x - | echo $it"# + r#" + open sample.db + | to-sqlite + | from-sqlite + | get table_values + | nth 2 + | get x + | echo $it + "# )); assert_eq!(actual, "hello"); @@ -393,12 +395,13 @@ fn can_convert_table_to_sqlite_and_back_into_table() { fn can_convert_table_to_toml_text_and_from_toml_text_back_into_table() { let actual = nu!( cwd: "tests/fixtures/formats", h::pipeline( - r#" - open cargo_sample.toml - | to-toml - | from-toml - | get package.name - | echo $it"# + r#" + open cargo_sample.toml + | to-toml + | from-toml + | get package.name + | echo $it + "# )); assert_eq!(actual, "nu");