From ff6933e863e9854b412f523cfaeb67fab5914d91 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Wed, 13 Dec 2023 12:17:56 +0100 Subject: [PATCH] nu completion: support value options --- complete/src/nu.rs | 82 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 58 insertions(+), 24 deletions(-) diff --git a/complete/src/nu.rs b/complete/src/nu.rs index 95310aa..fb9016c 100644 --- a/complete/src/nu.rs +++ b/complete/src/nu.rs @@ -1,36 +1,39 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::{Arg, Command, Flag, Value}; +use crate::{Arg, Command, Flag, Value, ValueHint}; use std::fmt::Write; /// Create completion script for `nushell` pub fn render(c: &Command) -> String { let mut args = Vec::new(); + let command_name = c.name; + let mut complete_commands = Vec::new(); let indent = " ".repeat(4); - for Arg { - short, - long, - help, - value: _value, - } in &c.args - { - for Flag { flag, value } in short { + for arg in &c.args { + let hint = if let Some((cmd, hint_name)) = render_completion_command(command_name, arg) { + complete_commands.push(cmd); + hint_name + } else { + "".into() + }; + + for Flag { flag, value } in &arg.short { let value = if let Value::Required(_) | Value::Optional(_) = value { - ": string" + format!(": string{hint}") } else { - "" + "".into() }; - args.push((format!("-{flag}{value}"), help)); + args.push((format!("-{flag}{value}"), arg.help)); } - for Flag { flag, value } in long { + for Flag { flag, value } in &arg.long { let value = if let Value::Required(_) | Value::Optional(_) = value { - ": string" + format!(": string{hint}") } else { - "" + "".into() }; - args.push((format!("--{flag}{value}"), help)); + args.push((format!("--{flag}{value}"), arg.help)); } } let longest_arg = args.iter().map(|a| a.0.len()).max().unwrap_or_default(); @@ -38,14 +41,45 @@ pub fn render(c: &Command) -> String { for (a, h) in args { writeln!(arg_str, "{indent}{a: Option<(String, String)> { + let val = arg.value.as_ref()?; + + // It could be that there is only a `dd` style argument. In that case, nu won't support it; + let arg_name = arg.long.first().or(arg.short.first())?.flag; + + render_value_hint(val).map(|hint| { + let name = format!("nu-complete {command_name} {arg_name}"); + let cmd = format!("def \"{name}\" [] {{\n {hint}\n}}"); + let hint_str = format!("@\"{name}\""); + (cmd, hint_str) + }) +} + +fn render_value_hint(value: &ValueHint) -> Option { + match value { + ValueHint::Strings(s) => { + let vals = s + .iter() + .map(|s| format!("\"{s}\"")) + .collect::>() + .join(", "); + Some(format!("[{vals}]")) + } + // The path arguments could be improved, but nu currently does not give + // us enough context to improve the default completions. + ValueHint::Unknown + | ValueHint::AnyPath + | ValueHint::FilePath + | ValueHint::ExecutablePath + | ValueHint::DirPath + | ValueHint::Username + | ValueHint::Hostname => None, + } } -fn template(name: &str, args: &str) -> String { - format!( - "\ - export extern {name} [\n{args}\ - ]\n\ - " - ) +fn template(name: &str, complete_commands: &str, args: &str) -> String { + format!("{complete_commands}\n\nexport extern \"{name}\" [\n{args}]\n") }