From 2873e943b3d0d533c8f03d5cb654a6e96322d7a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=BD=C3=A1dn=C3=ADk?= Date: Sun, 27 Mar 2022 22:25:30 +0300 Subject: [PATCH] Add search terms to Command and Signature (#4980) * Add search terms to command * Rename Signature desc to usage To be named uniformly with extra_usage * Throw in foldl search term for reduce * Add missing usage to post * Add search terms to signature * Try to add capnp Signature serialization --- crates/nu-command/src/core_commands/do_.rs | 1 - crates/nu-command/src/core_commands/help.rs | 62 ++++++++---- .../src/experimental/view_source.rs | 1 - crates/nu-command/src/filters/reduce.rs | 4 + crates/nu-command/src/network/fetch.rs | 27 +++++- crates/nu-command/src/network/post.rs | 9 +- crates/nu-command/src/system/ps.rs | 1 - crates/nu-command/src/system/sys.rs | 5 +- crates/nu-engine/src/documentation.rs | 13 ++- crates/nu-engine/src/eval.rs | 12 +++ crates/nu-plugin/src/plugin_capnp.rs | 96 +++++++++++++------ .../src/serializers/capnp/schema/plugin.capnp | 13 +-- .../src/serializers/capnp/signature.rs | 32 ++++++- crates/nu-protocol/src/engine/command.rs | 5 + crates/nu-protocol/src/engine/engine_state.rs | 11 +-- crates/nu-protocol/src/signature.rs | 31 +++++- crates/nu-protocol/tests/test_signature.rs | 6 +- crates/nu_plugin_example/src/nu/mod.rs | 6 +- crates/nu_plugin_gstat/src/nu/mod.rs | 2 +- crates/nu_plugin_inc/src/nu/mod.rs | 2 +- crates/nu_plugin_query/src/nu/mod.rs | 8 +- crates/old/nu_plugin_chart/src/nu/bar.rs | 2 +- crates/old/nu_plugin_chart/src/nu/line.rs | 2 +- crates/old/nu_plugin_from_bson/src/nu/mod.rs | 2 +- crates/old/nu_plugin_from_mp4/src/nu/mod.rs | 2 +- .../old/nu_plugin_from_sqlite/src/nu/mod.rs | 2 +- crates/old/nu_plugin_s3/src/nu/mod.rs | 2 +- crates/old/nu_plugin_start/src/nu/mod.rs | 2 +- crates/old/nu_plugin_to_bson/src/nu/mod.rs | 2 +- crates/old/nu_plugin_to_sqlite/src/nu/mod.rs | 2 +- crates/old/nu_plugin_tree/src/nu/mod.rs | 2 +- src/main.rs | 2 +- 32 files changed, 269 insertions(+), 100 deletions(-) diff --git a/crates/nu-command/src/core_commands/do_.rs b/crates/nu-command/src/core_commands/do_.rs index f493b8725..41c4741c8 100644 --- a/crates/nu-command/src/core_commands/do_.rs +++ b/crates/nu-command/src/core_commands/do_.rs @@ -17,7 +17,6 @@ impl Command for Do { fn signature(&self) -> nu_protocol::Signature { Signature::build("do") - .desc(self.usage()) .required("block", SyntaxShape::Any, "the block to run") .switch( "ignore-errors", diff --git a/crates/nu-command/src/core_commands/help.rs b/crates/nu-command/src/core_commands/help.rs index dc47a00ed..58ab6b27a 100644 --- a/crates/nu-command/src/core_commands/help.rs +++ b/crates/nu-command/src/core_commands/help.rs @@ -7,6 +7,8 @@ use nu_protocol::{ use nu_engine::{get_full_help, CallExt}; +use std::borrow::Borrow; + #[derive(Clone)] pub struct Help; @@ -96,14 +98,22 @@ fn help( let mut vals = vec![]; let decl = engine_state.get_decl(decl_id); - let sig = decl.signature(); + let sig = decl.signature().update_from_command(decl.borrow()); + + let key = sig.name; + let usage = sig.usage; + let search_terms = sig.search_terms; + let matches_term = if search_terms.is_empty() { + search_terms + .iter() + .any(|term| term.to_lowercase().contains(&search_string)) + } else { + false + }; - let key = sig.name.clone(); - let c = sig.usage.clone(); - let e = sig.extra_usage.clone(); if key.to_lowercase().contains(&search_string) - || c.to_lowercase().contains(&search_string) - || e.to_lowercase().contains(&search_string) + || usage.to_lowercase().contains(&search_string) + || matches_term { cols.push("name".into()); vals.push(Value::String { @@ -136,10 +146,20 @@ fn help( }); cols.push("usage".into()); - vals.push(Value::String { val: c, span: head }); + vals.push(Value::String { + val: usage, + span: head, + }); - cols.push("extra_usage".into()); - vals.push(Value::String { val: e, span: head }); + cols.push("search_terms".into()); + vals.push(if search_terms.is_empty() { + Value::nothing(head) + } else { + Value::String { + val: search_terms.join(", "), + span: head, + } + }); found_cmds_vec.push(Value::Record { cols, @@ -163,11 +183,11 @@ fn help( let mut vals = vec![]; let decl = engine_state.get_decl(decl_id); - let sig = decl.signature(); + let sig = decl.signature().update_from_command(decl.borrow()); - let key = sig.name.clone(); - let c = sig.usage.clone(); - let e = sig.extra_usage.clone(); + let key = sig.name; + let usage = sig.usage; + let search_terms = sig.search_terms; cols.push("name".into()); vals.push(Value::String { @@ -200,10 +220,20 @@ fn help( }); cols.push("usage".into()); - vals.push(Value::String { val: c, span: head }); + vals.push(Value::String { + val: usage, + span: head, + }); - cols.push("extra_usage".into()); - vals.push(Value::String { val: e, span: head }); + cols.push("search_terms".into()); + vals.push(if search_terms.is_empty() { + Value::nothing(head) + } else { + Value::String { + val: search_terms.join(", "), + span: head, + } + }); found_cmds_vec.push(Value::Record { cols, diff --git a/crates/nu-command/src/experimental/view_source.rs b/crates/nu-command/src/experimental/view_source.rs index ef54247ee..85d76566c 100644 --- a/crates/nu-command/src/experimental/view_source.rs +++ b/crates/nu-command/src/experimental/view_source.rs @@ -20,7 +20,6 @@ impl Command for ViewSource { fn signature(&self) -> nu_protocol::Signature { Signature::build("view-source") - .desc(self.usage()) .required("item", SyntaxShape::Any, "name or block to view") .category(Category::Core) } diff --git a/crates/nu-command/src/filters/reduce.rs b/crates/nu-command/src/filters/reduce.rs index c81955d60..f570479e6 100644 --- a/crates/nu-command/src/filters/reduce.rs +++ b/crates/nu-command/src/filters/reduce.rs @@ -36,6 +36,10 @@ impl Command for Reduce { "Aggregate a list table to a single value using an accumulator block." } + fn search_terms(&self) -> Vec<&str> { + vec!["map", "fold", "foldl"] + } + fn examples(&self) -> Vec { vec![ Example { diff --git a/crates/nu-command/src/network/fetch.rs b/crates/nu-command/src/network/fetch.rs index 404b3fb66..52d63472f 100644 --- a/crates/nu-command/src/network/fetch.rs +++ b/crates/nu-command/src/network/fetch.rs @@ -27,7 +27,6 @@ impl Command for SubCommand { fn signature(&self) -> Signature { Signature::build("fetch") - .desc("Load from a URL into a cell, convert to table if possible (avoid by appending '--raw').") .required( "URL", SyntaxShape::String, @@ -45,15 +44,33 @@ impl Command for SubCommand { "the password when authenticating", Some('p'), ) - .named("timeout", SyntaxShape::Int, "timeout period in seconds", Some('t')) - .named("headers",SyntaxShape::Any, "custom headers you want to add ", Some('H')) - .switch("raw", "fetch contents as text rather than a table", Some('r')) + .named( + "timeout", + SyntaxShape::Int, + "timeout period in seconds", + Some('t'), + ) + .named( + "headers", + SyntaxShape::Any, + "custom headers you want to add ", + Some('H'), + ) + .switch( + "raw", + "fetch contents as text rather than a table", + Some('r'), + ) .filter() .category(Category::Network) } fn usage(&self) -> &str { - "Fetch the contents from a URL (HTTP GET operation)." + "Fetch the contents from a URL." + } + + fn extra_usage(&self) -> &str { + "Performs HTTP GET operation." } fn run( diff --git a/crates/nu-command/src/network/post.rs b/crates/nu-command/src/network/post.rs index 178154d11..8c4ad63f4 100644 --- a/crates/nu-command/src/network/post.rs +++ b/crates/nu-command/src/network/post.rs @@ -24,7 +24,6 @@ impl Command for SubCommand { fn signature(&self) -> Signature { Signature::build("post") - .desc("Post content to a URL and retrieve data as a table if possible.") .required("path", SyntaxShape::String, "the URL to post to") .required("body", SyntaxShape::Any, "the contents of the post body") .named( @@ -70,9 +69,15 @@ impl Command for SubCommand { .filter() .category(Category::Network) } + fn usage(&self) -> &str { - "Post a body to a URL (HTTP POST operation)." + "Post a body to a URL." } + + fn extra_usage(&self) -> &str { + "Performs HTTP POST operation." + } + fn run( &self, engine_state: &EngineState, diff --git a/crates/nu-command/src/system/ps.rs b/crates/nu-command/src/system/ps.rs index 446370eae..0a36337d5 100644 --- a/crates/nu-command/src/system/ps.rs +++ b/crates/nu-command/src/system/ps.rs @@ -16,7 +16,6 @@ impl Command for Ps { fn signature(&self) -> Signature { Signature::build("ps") - .desc("View information about system processes.") .switch( "long", "list all available columns for each entry", diff --git a/crates/nu-command/src/system/sys.rs b/crates/nu-command/src/system/sys.rs index f1de36386..3750d9f7c 100644 --- a/crates/nu-command/src/system/sys.rs +++ b/crates/nu-command/src/system/sys.rs @@ -14,10 +14,7 @@ impl Command for Sys { } fn signature(&self) -> Signature { - Signature::build("sys") - .desc("View information about the current system.") - .filter() - .category(Category::System) + Signature::build("sys").filter().category(Category::System) } fn usage(&self) -> &str { diff --git a/crates/nu-engine/src/documentation.rs b/crates/nu-engine/src/documentation.rs index 3d33192b2..6eb34e902 100644 --- a/crates/nu-engine/src/documentation.rs +++ b/crates/nu-engine/src/documentation.rs @@ -4,6 +4,8 @@ use nu_protocol::{ engine::{EngineState, Stack}, Example, IntoPipelineData, Signature, Span, Value, }; + +use std::borrow::Borrow; use std::collections::HashMap; const COMMANDS_DOCS_DIR: &str = "docs/commands"; @@ -51,10 +53,12 @@ fn generate_doc( }); } + let signature = command.signature().update_from_command(command.borrow()); + cols.push("documentation".to_owned()); vals.push(Value::String { val: get_documentation( - &command.signature(), + &signature, &command.examples(), engine_state, stack, @@ -177,6 +181,13 @@ pub fn get_documentation( } } + if !sig.search_terms.is_empty() { + long_desc.push_str(&format!( + "Search terms: {}\n\n", + sig.search_terms.join(", ") + )); + } + long_desc.push_str(&format!("Usage:\n > {}\n", sig.call_signature())); if !subcommands.is_empty() { diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index 1247ea58e..f9dccdfd0 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -817,6 +817,7 @@ pub fn create_scope( let decl = engine_state.get_decl(*decl_id); let signature = decl.signature(); + cols.push("category".to_string()); vals.push(Value::String { val: signature.category.to_string(), @@ -1026,6 +1027,17 @@ pub fn create_scope( span, }); + let search_terms = decl.search_terms(); + cols.push("search_terms".to_string()); + vals.push(if search_terms.is_empty() { + Value::nothing(span) + } else { + Value::String { + val: search_terms.join(", "), + span, + } + }); + commands.push(Value::Record { cols, vals, span }) } } diff --git a/crates/nu-plugin/src/plugin_capnp.rs b/crates/nu-plugin/src/plugin_capnp.rs index 15f4b51cd..763cc76f2 100644 --- a/crates/nu-plugin/src/plugin_capnp.rs +++ b/crates/nu-plugin/src/plugin_capnp.rs @@ -1884,20 +1884,17 @@ pub mod signature { !self.reader.get_pointer_field(2).is_null() } #[inline] - pub fn get_required_positional( - self, - ) -> ::capnp::Result<::capnp::struct_list::Reader<'a, crate::plugin_capnp::argument::Owned>> - { + pub fn get_search_terms(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { ::capnp::traits::FromPointerReader::get_from_pointer( &self.reader.get_pointer_field(3), ::core::option::Option::None, ) } - pub fn has_required_positional(&self) -> bool { + pub fn has_search_terms(&self) -> bool { !self.reader.get_pointer_field(3).is_null() } #[inline] - pub fn get_optional_positional( + pub fn get_required_positional( self, ) -> ::capnp::Result<::capnp::struct_list::Reader<'a, crate::plugin_capnp::argument::Owned>> { @@ -1906,31 +1903,44 @@ pub mod signature { ::core::option::Option::None, ) } - pub fn has_optional_positional(&self) -> bool { + pub fn has_required_positional(&self) -> bool { !self.reader.get_pointer_field(4).is_null() } #[inline] - pub fn get_rest(self) -> ::capnp::Result> { + pub fn get_optional_positional( + self, + ) -> ::capnp::Result<::capnp::struct_list::Reader<'a, crate::plugin_capnp::argument::Owned>> + { ::capnp::traits::FromPointerReader::get_from_pointer( &self.reader.get_pointer_field(5), ::core::option::Option::None, ) } - pub fn has_rest(&self) -> bool { + pub fn has_optional_positional(&self) -> bool { !self.reader.get_pointer_field(5).is_null() } #[inline] + pub fn get_rest(self) -> ::capnp::Result> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(6), + ::core::option::Option::None, + ) + } + pub fn has_rest(&self) -> bool { + !self.reader.get_pointer_field(6).is_null() + } + #[inline] pub fn get_named( self, ) -> ::capnp::Result<::capnp::struct_list::Reader<'a, crate::plugin_capnp::flag::Owned>> { ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(6), + &self.reader.get_pointer_field(7), ::core::option::Option::None, ) } pub fn has_named(&self) -> bool { - !self.reader.get_pointer_field(6).is_null() + !self.reader.get_pointer_field(7).is_null() } #[inline] pub fn get_is_filter(self) -> bool { @@ -2068,12 +2078,40 @@ pub mod signature { !self.builder.get_pointer_field(2).is_null() } #[inline] + pub fn get_search_terms(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(3), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_search_terms( + &mut self, + value: ::capnp::text_list::Reader<'a>, + ) -> ::capnp::Result<()> { + ::capnp::traits::SetPointerBuilder::set_pointer_builder( + self.builder.get_pointer_field(3), + value, + false, + ) + } + #[inline] + pub fn init_search_terms(self, size: u32) -> ::capnp::text_list::Builder<'a> { + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(3), + size, + ) + } + pub fn has_search_terms(&self) -> bool { + !self.builder.get_pointer_field(3).is_null() + } + #[inline] pub fn get_required_positional( self, ) -> ::capnp::Result<::capnp::struct_list::Builder<'a, crate::plugin_capnp::argument::Owned>> { ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(3), + self.builder.get_pointer_field(4), ::core::option::Option::None, ) } @@ -2083,7 +2121,7 @@ pub mod signature { value: ::capnp::struct_list::Reader<'a, crate::plugin_capnp::argument::Owned>, ) -> ::capnp::Result<()> { ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.get_pointer_field(3), + self.builder.get_pointer_field(4), value, false, ) @@ -2094,12 +2132,12 @@ pub mod signature { size: u32, ) -> ::capnp::struct_list::Builder<'a, crate::plugin_capnp::argument::Owned> { ::capnp::traits::FromPointerBuilder::init_pointer( - self.builder.get_pointer_field(3), + self.builder.get_pointer_field(4), size, ) } pub fn has_required_positional(&self) -> bool { - !self.builder.get_pointer_field(3).is_null() + !self.builder.get_pointer_field(4).is_null() } #[inline] pub fn get_optional_positional( @@ -2107,7 +2145,7 @@ pub mod signature { ) -> ::capnp::Result<::capnp::struct_list::Builder<'a, crate::plugin_capnp::argument::Owned>> { ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(4), + self.builder.get_pointer_field(5), ::core::option::Option::None, ) } @@ -2117,7 +2155,7 @@ pub mod signature { value: ::capnp::struct_list::Reader<'a, crate::plugin_capnp::argument::Owned>, ) -> ::capnp::Result<()> { ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.get_pointer_field(4), + self.builder.get_pointer_field(5), value, false, ) @@ -2128,17 +2166,17 @@ pub mod signature { size: u32, ) -> ::capnp::struct_list::Builder<'a, crate::plugin_capnp::argument::Owned> { ::capnp::traits::FromPointerBuilder::init_pointer( - self.builder.get_pointer_field(4), + self.builder.get_pointer_field(5), size, ) } pub fn has_optional_positional(&self) -> bool { - !self.builder.get_pointer_field(4).is_null() + !self.builder.get_pointer_field(5).is_null() } #[inline] pub fn get_rest(self) -> ::capnp::Result> { ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(5), + self.builder.get_pointer_field(6), ::core::option::Option::None, ) } @@ -2148,17 +2186,17 @@ pub mod signature { value: crate::plugin_capnp::argument::Reader<'_>, ) -> ::capnp::Result<()> { ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.get_pointer_field(5), + self.builder.get_pointer_field(6), value, false, ) } #[inline] pub fn init_rest(self) -> crate::plugin_capnp::argument::Builder<'a> { - ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(5), 0) + ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(6), 0) } pub fn has_rest(&self) -> bool { - !self.builder.get_pointer_field(5).is_null() + !self.builder.get_pointer_field(6).is_null() } #[inline] pub fn get_named( @@ -2166,7 +2204,7 @@ pub mod signature { ) -> ::capnp::Result<::capnp::struct_list::Builder<'a, crate::plugin_capnp::flag::Owned>> { ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(6), + self.builder.get_pointer_field(7), ::core::option::Option::None, ) } @@ -2176,7 +2214,7 @@ pub mod signature { value: ::capnp::struct_list::Reader<'a, crate::plugin_capnp::flag::Owned>, ) -> ::capnp::Result<()> { ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.get_pointer_field(6), + self.builder.get_pointer_field(7), value, false, ) @@ -2187,12 +2225,12 @@ pub mod signature { size: u32, ) -> ::capnp::struct_list::Builder<'a, crate::plugin_capnp::flag::Owned> { ::capnp::traits::FromPointerBuilder::init_pointer( - self.builder.get_pointer_field(6), + self.builder.get_pointer_field(7), size, ) } pub fn has_named(&self) -> bool { - !self.builder.get_pointer_field(6).is_null() + !self.builder.get_pointer_field(7).is_null() } #[inline] pub fn get_is_filter(self) -> bool { @@ -2226,14 +2264,14 @@ pub mod signature { } impl Pipeline { pub fn get_rest(&self) -> crate::plugin_capnp::argument::Pipeline { - ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(5)) + ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(6)) } } mod _private { use capnp::private::layout; pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 1, - pointers: 7, + pointers: 8, }; pub const TYPE_ID: u64 = 0xec96_eeb4_8cb7_90fa; } diff --git a/crates/nu-plugin/src/serializers/capnp/schema/plugin.capnp b/crates/nu-plugin/src/serializers/capnp/schema/plugin.capnp index 5c78e4bbe..e148d0957 100644 --- a/crates/nu-plugin/src/serializers/capnp/schema/plugin.capnp +++ b/crates/nu-plugin/src/serializers/capnp/schema/plugin.capnp @@ -55,13 +55,14 @@ struct Signature { name @0 :Text; usage @1 :Text; extraUsage @2 :Text; - requiredPositional @3 :List(Argument); - optionalPositional @4 :List(Argument); + searchTerms @3 :List(Text); + requiredPositional @4 :List(Argument); + optionalPositional @5 :List(Argument); # Optional value. Check for existence when deserializing - rest @5 :Argument; - named @6 :List(Flag); - isFilter @7 :Bool; - category @8 :Category; + rest @6 :Argument; + named @7 :List(Flag); + isFilter @8 :Bool; + category @9 :Category; } enum Category { diff --git a/crates/nu-plugin/src/serializers/capnp/signature.rs b/crates/nu-plugin/src/serializers/capnp/signature.rs index 9d017f7d6..627f6d94f 100644 --- a/crates/nu-plugin/src/serializers/capnp/signature.rs +++ b/crates/nu-plugin/src/serializers/capnp/signature.rs @@ -30,6 +30,17 @@ pub(crate) fn serialize_signature(signature: &Signature, mut builder: signature: _ => builder.set_category(PluginCategory::Default), } + // Serializing list of search terms + let mut search_terms_builder = builder + .reborrow() + .init_search_terms(signature.search_terms.len() as u32); + + signature + .search_terms + .iter() + .enumerate() + .for_each(|(index, term)| search_terms_builder.set(index as u32, term.as_str())); + // Serializing list of required arguments let mut required_list = builder .reborrow() @@ -136,6 +147,17 @@ pub(crate) fn deserialize_signature(reader: signature::Reader) -> Result Category::Generators, }; + // Deserializing list of search terms + let search_terms = reader + .get_search_terms() + .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))? + .iter() + .map(|term| { + term.map_err(|e| ShellError::PluginFailedToDecode(e.to_string())) + .map(|term| term.to_string()) + }) + .collect::, ShellError>>()?; + // Deserializing required arguments let required_list = reader .get_required_positional() @@ -181,6 +203,7 @@ pub(crate) fn deserialize_signature(reader: signature::Reader) -> Result Option { None } + + // Related terms to help with command search + fn search_terms(&self) -> Vec<&str> { + vec![] + } } pub trait CommandClone { diff --git a/crates/nu-protocol/src/engine/engine_state.rs b/crates/nu-protocol/src/engine/engine_state.rs index 3ac5315a3..9ba7bf801 100644 --- a/crates/nu-protocol/src/engine/engine_state.rs +++ b/crates/nu-protocol/src/engine/engine_state.rs @@ -11,6 +11,7 @@ use std::{ use crate::Value; +use std::borrow::Borrow; use std::path::Path; #[cfg(feature = "plugin")] @@ -527,11 +528,7 @@ impl EngineState { .map(|id| { let decl = self.get_decl(id); - let mut signature = (*decl).signature(); - signature.usage = decl.usage().to_string(); - signature.extra_usage = decl.extra_usage().to_string(); - - signature + (*decl).signature().update_from_command(decl.borrow()) }) .collect() } @@ -549,9 +546,7 @@ impl EngineState { .map(|id| { let decl = self.get_decl(id); - let mut signature = (*decl).signature(); - signature.usage = decl.usage().to_string(); - signature.extra_usage = decl.extra_usage().to_string(); + let signature = (*decl).signature().update_from_command(decl.borrow()); ( signature, diff --git a/crates/nu-protocol/src/signature.rs b/crates/nu-protocol/src/signature.rs index 511e0534b..f65ecc9dc 100644 --- a/crates/nu-protocol/src/signature.rs +++ b/crates/nu-protocol/src/signature.rs @@ -95,6 +95,7 @@ pub struct Signature { pub name: String, pub usage: String, pub extra_usage: String, + pub search_terms: Vec, pub required_positional: Vec, pub optional_positional: Vec, pub rest_positional: Option, @@ -135,6 +136,7 @@ impl Signature { name: name.into(), usage: String::new(), extra_usage: String::new(), + search_terms: vec![], required_positional: vec![], optional_positional: vec![], rest_positional: None, @@ -144,13 +146,38 @@ impl Signature { category: Category::Default, } } + pub fn build(name: impl Into) -> Signature { Signature::new(name.into()) } /// Add a description to the signature - pub fn desc(mut self, usage: impl Into) -> Signature { - self.usage = usage.into(); + pub fn usage(mut self, msg: impl Into) -> Signature { + self.usage = msg.into(); + self + } + + /// Add an extra description to the signature + pub fn extra_usage(mut self, msg: impl Into) -> Signature { + self.extra_usage = msg.into(); + self + } + + /// Add search terms to the signature + pub fn search_terms(mut self, terms: Vec) -> Signature { + self.search_terms = terms; + self + } + + /// Update signature's fields from a Command trait implementation + pub fn update_from_command(mut self, command: &dyn Command) -> Signature { + self.search_terms = command + .search_terms() + .into_iter() + .map(|term| term.to_string()) + .collect(); + self.extra_usage = command.extra_usage().to_string(); + self.usage = command.usage().to_string(); self } diff --git a/crates/nu-protocol/tests/test_signature.rs b/crates/nu-protocol/tests/test_signature.rs index 99f50b60b..cf90d5bf6 100644 --- a/crates/nu-protocol/tests/test_signature.rs +++ b/crates/nu-protocol/tests/test_signature.rs @@ -9,14 +9,14 @@ fn test_signature() { assert_eq!(signature, from_build); // constructing signature with description - let signature = Signature::new("signature").desc("example usage"); + let signature = Signature::new("signature").usage("example usage"); assert_eq!(signature.usage, "example usage".to_string()) } #[test] fn test_signature_chained() { let signature = Signature::new("new_signature") - .desc("description") + .usage("description") .required("required", SyntaxShape::String, "required description") .optional("optional", SyntaxShape::String, "optional description") .required_named( @@ -129,7 +129,7 @@ fn test_signature_same_name() { #[test] fn test_signature_round_trip() { let signature = Signature::new("new_signature") - .desc("description") + .usage("description") .required("first", SyntaxShape::String, "first required") .required("second", SyntaxShape::Int, "second required") .optional("optional", SyntaxShape::String, "optional description") diff --git a/crates/nu_plugin_example/src/nu/mod.rs b/crates/nu_plugin_example/src/nu/mod.rs index 7a87e3f84..9e2b57c6b 100644 --- a/crates/nu_plugin_example/src/nu/mod.rs +++ b/crates/nu_plugin_example/src/nu/mod.rs @@ -9,7 +9,7 @@ impl Plugin for Example { // plugin is registered to nushell vec![ Signature::build("nu-example-1") - .desc("Signature test 1 for plugin. Returns Value::Nothing") + .usage("Signature test 1 for plugin. Returns Value::Nothing") .required("a", SyntaxShape::Int, "required integer value") .required("b", SyntaxShape::String, "required string value") .switch("flag", "a flag for the signature", Some('f')) @@ -18,7 +18,7 @@ impl Plugin for Example { .rest("rest", SyntaxShape::String, "rest value string") .category(Category::Experimental), Signature::build("nu-example-2") - .desc("Signature test 2 for plugin. Returns list of records") + .usage("Signature test 2 for plugin. Returns list of records") .required("a", SyntaxShape::Int, "required integer value") .required("b", SyntaxShape::String, "required string value") .switch("flag", "a flag for the signature", Some('f')) @@ -27,7 +27,7 @@ impl Plugin for Example { .rest("rest", SyntaxShape::String, "rest value string") .category(Category::Experimental), Signature::build("nu-example-3") - .desc("Signature test 3 for plugin. Returns labeled error") + .usage("Signature test 3 for plugin. Returns labeled error") .required("a", SyntaxShape::Int, "required integer value") .required("b", SyntaxShape::String, "required string value") .switch("flag", "a flag for the signature", Some('f')) diff --git a/crates/nu_plugin_gstat/src/nu/mod.rs b/crates/nu_plugin_gstat/src/nu/mod.rs index 3d0a8aa1d..e58916f3b 100644 --- a/crates/nu_plugin_gstat/src/nu/mod.rs +++ b/crates/nu_plugin_gstat/src/nu/mod.rs @@ -5,7 +5,7 @@ use nu_protocol::{Category, Signature, Spanned, SyntaxShape, Value}; impl Plugin for GStat { fn signature(&self) -> Vec { vec![Signature::build("gstat") - .desc("Get the git status of a repo") + .usage("Get the git status of a repo") .optional("path", SyntaxShape::Filepath, "path to repo") .category(Category::Custom("Prompt".to_string()))] } diff --git a/crates/nu_plugin_inc/src/nu/mod.rs b/crates/nu_plugin_inc/src/nu/mod.rs index 24103d83b..d3461ea4f 100644 --- a/crates/nu_plugin_inc/src/nu/mod.rs +++ b/crates/nu_plugin_inc/src/nu/mod.rs @@ -6,7 +6,7 @@ use nu_protocol::{ast::CellPath, Signature, SyntaxShape, Value}; impl Plugin for Inc { fn signature(&self) -> Vec { vec![Signature::build("inc") - .desc("Increment a value or version. Optionally use the column of a table.") + .usage("Increment a value or version. Optionally use the column of a table.") .optional("cell_path", SyntaxShape::CellPath, "cell path to update") .switch( "major", diff --git a/crates/nu_plugin_query/src/nu/mod.rs b/crates/nu_plugin_query/src/nu/mod.rs index 9fa567e5b..641665f5c 100644 --- a/crates/nu_plugin_query/src/nu/mod.rs +++ b/crates/nu_plugin_query/src/nu/mod.rs @@ -6,21 +6,21 @@ impl Plugin for Query { fn signature(&self) -> Vec { vec![ Signature::build("query") - .desc("Show all the query commands") + .usage("Show all the query commands") .category(Category::Filters), Signature::build("query json") - .desc("execute json query on json file (open --raw | query json 'query string')") + .usage("execute json query on json file (open --raw | query json 'query string')") .required("query", SyntaxShape::String, "json query") .category(Category::Filters), Signature::build("query xml") - .desc("execute xpath query on xml") + .usage("execute xpath query on xml") .required("query", SyntaxShape::String, "xpath query") .category(Category::Filters), Signature::build("query web") - .desc("execute selector query on html/web") + .usage("execute selector query on html/web") .named("query", SyntaxShape::String, "selector query", Some('q')) .switch("as-html", "return the query output as html", Some('m')) .named( diff --git a/crates/old/nu_plugin_chart/src/nu/bar.rs b/crates/old/nu_plugin_chart/src/nu/bar.rs index 4a47fc0e6..9d06c896e 100644 --- a/crates/old/nu_plugin_chart/src/nu/bar.rs +++ b/crates/old/nu_plugin_chart/src/nu/bar.rs @@ -129,7 +129,7 @@ fn display(model: &Model) -> Result<(), Box> { impl Plugin for SubCommand { fn config(&mut self) -> Result { Ok(Signature::build("chart bar") - .desc("Bar charts") + .usage("Bar charts") .switch("acc", "accumulate values", Some('a')) .optional( "columns", diff --git a/crates/old/nu_plugin_chart/src/nu/line.rs b/crates/old/nu_plugin_chart/src/nu/line.rs index 91f27c5ce..86911a77d 100644 --- a/crates/old/nu_plugin_chart/src/nu/line.rs +++ b/crates/old/nu_plugin_chart/src/nu/line.rs @@ -127,7 +127,7 @@ fn display(model: &Model) -> Result<(), Box> { impl Plugin for SubCommand { fn config(&mut self) -> Result { Ok(Signature::build("chart line") - .desc("Line charts") + .usage("Line charts") .switch("acc", "accumulate values", Some('a')) .optional( "columns", diff --git a/crates/old/nu_plugin_from_bson/src/nu/mod.rs b/crates/old/nu_plugin_from_bson/src/nu/mod.rs index 0a6584d01..a9f8bd496 100644 --- a/crates/old/nu_plugin_from_bson/src/nu/mod.rs +++ b/crates/old/nu_plugin_from_bson/src/nu/mod.rs @@ -10,7 +10,7 @@ use nu_source::Tag; impl Plugin for FromBson { fn config(&mut self) -> Result { Ok(Signature::build("from bson") - .desc("Convert from .bson binary into table") + .usage("Convert from .bson binary into table") .filter()) } diff --git a/crates/old/nu_plugin_from_mp4/src/nu/mod.rs b/crates/old/nu_plugin_from_mp4/src/nu/mod.rs index 4aa09ca7d..4e8a8144f 100644 --- a/crates/old/nu_plugin_from_mp4/src/nu/mod.rs +++ b/crates/old/nu_plugin_from_mp4/src/nu/mod.rs @@ -10,7 +10,7 @@ use nu_source::Tag; impl Plugin for FromMp4 { fn config(&mut self) -> Result { Ok(Signature::build("from mp4") - .desc("Get meta-data of mp4 file") + .usage("Get meta-data of mp4 file") .filter()) } diff --git a/crates/old/nu_plugin_from_sqlite/src/nu/mod.rs b/crates/old/nu_plugin_from_sqlite/src/nu/mod.rs index f39463386..5abb6767f 100644 --- a/crates/old/nu_plugin_from_sqlite/src/nu/mod.rs +++ b/crates/old/nu_plugin_from_sqlite/src/nu/mod.rs @@ -33,7 +33,7 @@ impl Plugin for FromSqlite { "Only convert specified tables", Some('t'), ) - .desc("Convert from sqlite binary into table") + .usage("Convert from sqlite binary into table") .filter()) } diff --git a/crates/old/nu_plugin_s3/src/nu/mod.rs b/crates/old/nu_plugin_s3/src/nu/mod.rs index 2ad0b88d0..f42c98e6c 100644 --- a/crates/old/nu_plugin_s3/src/nu/mod.rs +++ b/crates/old/nu_plugin_s3/src/nu/mod.rs @@ -9,7 +9,7 @@ use crate::handler::s3_helper; impl Plugin for handler::Handler { fn config(&mut self) -> Result { Ok(Signature::build("s3") - .desc("Load S3 resource into a cell, convert to table if possible (avoid by appending '--raw' or '-R')") + .usage("Load S3 resource into a cell, convert to table if possible (avoid by appending '--raw' or '-R')") .required( "RESOURCE", SyntaxShape::String, diff --git a/crates/old/nu_plugin_start/src/nu/mod.rs b/crates/old/nu_plugin_start/src/nu/mod.rs index 594fe3430..b7f1849a0 100644 --- a/crates/old/nu_plugin_start/src/nu/mod.rs +++ b/crates/old/nu_plugin_start/src/nu/mod.rs @@ -7,7 +7,7 @@ use crate::start::Start; impl Plugin for Start { fn config(&mut self) -> Result { Ok(Signature::build("start") - .desc("Opens each file/directory/URL using the default application") + .usage("Opens each file/directory/URL using the default application") .rest( "rest", SyntaxShape::String, diff --git a/crates/old/nu_plugin_to_bson/src/nu/mod.rs b/crates/old/nu_plugin_to_bson/src/nu/mod.rs index 515fafe21..bf4c1b253 100644 --- a/crates/old/nu_plugin_to_bson/src/nu/mod.rs +++ b/crates/old/nu_plugin_to_bson/src/nu/mod.rs @@ -10,7 +10,7 @@ use nu_source::Tag; impl Plugin for ToBson { fn config(&mut self) -> Result { Ok(Signature::build("to bson") - .desc("Convert table into .bson binary") + .usage("Convert table into .bson binary") .filter()) } diff --git a/crates/old/nu_plugin_to_sqlite/src/nu/mod.rs b/crates/old/nu_plugin_to_sqlite/src/nu/mod.rs index 08288db45..22670e437 100644 --- a/crates/old/nu_plugin_to_sqlite/src/nu/mod.rs +++ b/crates/old/nu_plugin_to_sqlite/src/nu/mod.rs @@ -10,7 +10,7 @@ use nu_source::Tag; impl Plugin for ToSqlite { fn config(&mut self) -> Result { Ok(Signature::build("to sqlite") - .desc("Convert table into sqlite binary") + .usage("Convert table into sqlite binary") .filter()) } diff --git a/crates/old/nu_plugin_tree/src/nu/mod.rs b/crates/old/nu_plugin_tree/src/nu/mod.rs index fcec4e9bd..3dda83789 100644 --- a/crates/old/nu_plugin_tree/src/nu/mod.rs +++ b/crates/old/nu_plugin_tree/src/nu/mod.rs @@ -7,7 +7,7 @@ use crate::TreeViewer; impl Plugin for TreeViewer { fn config(&mut self) -> Result { - Ok(Signature::build("tree").desc("View the contents of the pipeline as a tree.")) + Ok(Signature::build("tree").usage("View the contents of the pipeline as a tree.")) } fn sink(&mut self, _call_info: CallInfo, input: Vec) { diff --git a/src/main.rs b/src/main.rs index 63b56412c..041269040 100644 --- a/src/main.rs +++ b/src/main.rs @@ -415,7 +415,7 @@ impl Command for Nu { fn signature(&self) -> Signature { Signature::build("nu") - .desc("The nushell language and shell.") + .usage("The nushell language and shell.") .switch("stdin", "redirect the stdin", None) .switch("login", "start as a login shell", Some('l')) .switch("interactive", "start as an interactive shell", Some('i'))