From 405a4e58c74b0ec01da486a5e28d7e36244bdc9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=BD=C3=A1dn=C3=ADk?= Date: Fri, 3 Dec 2021 20:45:29 +0200 Subject: [PATCH] Fix 'help commands'; Add 'is_custom' column (#420) * Fix fetching commands; Add is_custom column * Remove old comment --- crates/nu-command/src/core_commands/help.rs | 42 +++++++---- crates/nu-engine/src/documentation.rs | 4 +- crates/nu-engine/src/eval.rs | 6 ++ crates/nu-protocol/src/engine/engine_state.rs | 74 ++++++++++++++----- 4 files changed, 89 insertions(+), 37 deletions(-) diff --git a/crates/nu-command/src/core_commands/help.rs b/crates/nu-command/src/core_commands/help.rs index c03dfa2323..c52e2c9f31 100644 --- a/crates/nu-command/src/core_commands/help.rs +++ b/crates/nu-command/src/core_commands/help.rs @@ -85,19 +85,19 @@ fn help( let find: Option> = call.get_flag(engine_state, stack, "find")?; let rest: Vec> = call.rest(engine_state, stack, 0)?; - let full_commands = engine_state.get_signatures_with_examples(); + let full_commands = engine_state.get_signatures_with_examples(false); if let Some(f) = find { let search_string = f.item; let mut found_cmds_vec = Vec::new(); - for cmd in full_commands { + for (sig, _, is_plugin, is_custom) in full_commands { let mut cols = vec![]; let mut vals = vec![]; - let key = cmd.0.name.clone(); - let c = cmd.0.usage.clone(); - let e = cmd.0.extra_usage.clone(); + 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) @@ -110,13 +110,19 @@ fn help( cols.push("category".into()); vals.push(Value::String { - val: cmd.0.category.to_string(), + val: sig.category.to_string(), span: head, }); cols.push("is_plugin".into()); vals.push(Value::Bool { - val: cmd.2, + val: is_plugin, + span: head, + }); + + cols.push("is_custom".into()); + vals.push(Value::Bool { + val: is_custom, span: head, }); @@ -143,13 +149,13 @@ fn help( let mut found_cmds_vec = Vec::new(); if rest[0].item == "commands" { - for cmd in full_commands { + for (sig, _, is_plugin, is_custom) in full_commands { let mut cols = vec![]; let mut vals = vec![]; - let key = cmd.0.name.clone(); - let c = cmd.0.usage.clone(); - let e = cmd.0.extra_usage.clone(); + let key = sig.name.clone(); + let c = sig.usage.clone(); + let e = sig.extra_usage.clone(); cols.push("name".into()); vals.push(Value::String { @@ -159,13 +165,19 @@ fn help( cols.push("category".into()); vals.push(Value::String { - val: cmd.0.category.to_string(), + val: sig.category.to_string(), span: head, }); cols.push("is_plugin".into()); vals.push(Value::Bool { - val: cmd.2, + val: is_plugin, + span: head, + }); + + cols.push("is_custom".into()); + vals.push(Value::Bool { + val: is_custom, span: head, }); @@ -197,8 +209,8 @@ fn help( let output = full_commands .iter() - .filter(|(signature, _, _)| signature.name == name) - .map(|(signature, examples, _)| get_full_help(signature, examples, engine_state)) + .filter(|(signature, _, _, _)| signature.name == name) + .map(|(signature, examples, _, _)| get_full_help(signature, examples, engine_state)) .collect::>(); if !output.is_empty() { diff --git a/crates/nu-engine/src/documentation.rs b/crates/nu-engine/src/documentation.rs index a921f351ac..4214340aa7 100644 --- a/crates/nu-engine/src/documentation.rs +++ b/crates/nu-engine/src/documentation.rs @@ -64,7 +64,7 @@ fn generate_doc(name: &str, engine_state: &EngineState) -> (Vec, Vec Value { - let signatures = engine_state.get_signatures(); + let signatures = engine_state.get_signatures(true); // cmap will map parent commands to it's subcommands e.g. to -> [to csv, to yaml, to bson] let mut cmap: HashMap> = HashMap::new(); @@ -160,7 +160,7 @@ pub fn get_documentation( let mut subcommands = vec![]; if !config.no_subcommands { - let signatures = engine_state.get_signatures(); + let signatures = engine_state.get_signatures(true); for sig in signatures { if sig.name.starts_with(&format!("{} ", cmd_name)) { subcommands.push(format!(" {} - {}", sig.name, sig.usage)); diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index 4333a986af..37c8e9dc71 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -602,6 +602,12 @@ pub fn eval_variable( span, }); + cols.push("is_custom".to_string()); + vals.push(Value::Bool { + val: decl.get_block_id().is_some(), + span, + }); + cols.push("creates_scope".to_string()); vals.push(Value::Bool { val: signature.creates_scope, diff --git a/crates/nu-protocol/src/engine/engine_state.rs b/crates/nu-protocol/src/engine/engine_state.rs index 5c89986cd4..2429671af4 100644 --- a/crates/nu-protocol/src/engine/engine_state.rs +++ b/crates/nu-protocol/src/engine/engine_state.rs @@ -440,37 +440,71 @@ impl EngineState { } } - pub fn get_signatures(&self) -> Vec { - let mut output = vec![]; - for decl in self.decls.iter() { - if decl.get_block_id().is_none() { - let mut signature = (*decl).signature(); - signature.usage = decl.usage().to_string(); - signature.extra_usage = decl.extra_usage().to_string(); + /// Get all IDs of all commands within scope, sorted by the commads' names + pub fn get_decl_ids_sorted(&self, include_hidden: bool) -> impl Iterator { + let mut decls_map = HashMap::new(); - output.push(signature); - } + for frame in &self.scope { + let frame_decls = if include_hidden { + frame.decls.clone() + } else { + frame + .decls + .clone() + .into_iter() + .filter(|(_, id)| frame.visibility.is_decl_id_visible(id)) + .collect() + }; + + decls_map.extend(frame_decls); } - output + let mut decls: Vec<(Vec, DeclId)> = decls_map.into_iter().collect(); + + decls.sort_by(|a, b| a.0.cmp(&b.0)); + decls.into_iter().map(|(_, id)| id) } - pub fn get_signatures_with_examples(&self) -> Vec<(Signature, Vec, bool)> { - let mut output = vec![]; - for decl in self.decls.iter() { - if decl.get_block_id().is_none() { + /// Get signatures of all commands within scope. + pub fn get_signatures(&self, include_hidden: bool) -> Vec { + self.get_decl_ids_sorted(include_hidden) + .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(); - output.push((signature, decl.examples(), decl.is_plugin().is_some())); - } - } + signature + }) + .collect() + } - output.sort_by(|a, b| a.0.name.cmp(&b.0.name)); - output.dedup_by(|a, b| a.0.name.cmp(&b.0.name).is_eq()); + /// Get signatures of all commands within scope. + /// + /// In addition to signatures, it returns whether each command is: + /// a) a plugin + /// b) custom + pub fn get_signatures_with_examples( + &self, + include_hidden: bool, + ) -> Vec<(Signature, Vec, bool, bool)> { + self.get_decl_ids_sorted(include_hidden) + .map(|id| { + let decl = self.get_decl(id); - output + let mut signature = (*decl).signature(); + signature.usage = decl.usage().to_string(); + signature.extra_usage = decl.extra_usage().to_string(); + + ( + signature, + decl.examples(), + decl.is_plugin().is_some(), + decl.get_block_id().is_some(), + ) + }) + .collect() } pub fn get_block(&self, block_id: BlockId) -> &Block {