From d89b0212fcf58794bf0584f55a59e84db9b29d6e Mon Sep 17 00:00:00 2001 From: ysthakur <45539777+ysthakur@users.noreply.github.com> Date: Thu, 10 Aug 2023 14:58:10 -0400 Subject: [PATCH] feat: Detect subcommands with hyphens --- src/gen/json.rs | 6 +++--- src/gen/zsh.rs | 10 +++------- src/parse/mod.rs | 47 +++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/gen/json.rs b/src/gen/json.rs index 9c766de..cd63d0a 100644 --- a/src/gen/json.rs +++ b/src/gen/json.rs @@ -20,7 +20,7 @@ impl Completions for JsonCompletions { let mut res = Output::new(String::from(" ")); res.writeln("{"); res.indent(); - generate_cmd(&cmd_name, cmd_info, true, &mut res); + generate_cmd(cmd_name, cmd_info, true, &mut res); res.dedent(); res.writeln("}"); fs::write( @@ -86,11 +86,11 @@ fn generate_cmd(cmd: &str, cmd_info: &CommandInfo, last: bool, out: &mut Output) out.indent(); loop { if let Some(next) = subcmds.next() { - generate_cmd(&name, &info, false, out); + generate_cmd(name, info, false, out); name = next.0; info = next.1; } else { - generate_cmd(&name, &info, true, out); + generate_cmd(name, info, true, out); break; } } diff --git a/src/gen/zsh.rs b/src/gen/zsh.rs index cb769a0..db8472b 100644 --- a/src/gen/zsh.rs +++ b/src/gen/zsh.rs @@ -50,7 +50,7 @@ impl Completions for ZshCompletions { let comp_name = format!("_{}", cmd_name); let mut res = Output::new(String::from("\t")); res.writeln(format!("#compdef {} {}", comp_name, cmd_name)); - generate_fn(&cmd_name, cmd_info, &mut res, 0, &comp_name); + generate_fn(cmd_name, cmd_info, &mut res, 0, &comp_name); fs::write( out_dir.as_ref().join(format!("{}.zsh", comp_name)), res.text(), @@ -89,11 +89,7 @@ fn generate_fn( out.indent(); for opt in cmd_info.args.iter() { - let desc = if let Some(desc) = &opt.desc { - &*desc - } else { - "" - }; + let desc = if let Some(desc) = &opt.desc { desc } else { "" }; for form in opt.forms.iter() { let text = util::quote_bash(format!("{}[{}]", form, desc)); out.writeln(" \\"); @@ -129,7 +125,7 @@ fn generate_fn( for (sub_cmd, sub_cmd_info) in cmd_info.subcommands.iter() { generate_fn( - &sub_cmd, + sub_cmd, sub_cmd_info, out, pos + 1, diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 6710d9a..dd6ef59 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -326,17 +326,52 @@ fn get_cmd_name(manpage_path: &Path) -> String { /// /// Given command `git-log`, the result would be `Some(vec!["git", "log"])` fn detect_subcommand(cmd_name: &str, text: &str) -> Option> { - let parts = cmd_name.split('-').collect::>(); - let as_sub_cmd = parts.join(" "); - if parts.len() > 1 && parts.iter().all(|s| !s.is_empty()) && text.contains(&as_sub_cmd) - { - debug!("Detected {} as subcommand", cmd_name); - Some(parts.iter().map(|s| s.to_string()).collect()) + let mut chars = cmd_name.chars(); + let mut hyphens = vec![0]; + for i in 0..cmd_name.len() { + if chars.next().unwrap() == '-' { + hyphens.push(i + 1); + } + } + hyphens.push(cmd_name.len() + 1); + if hyphens.len() == 2 { + None } else { + for poss in all_possible_subcommands(&hyphens, cmd_name) { + let as_sub_cmd = poss.join(" ").replace('-', r"\-"); + if text.contains(&as_sub_cmd) { + debug!("Detected {} as subcommand {}", cmd_name, as_sub_cmd); + return Some(poss.into_iter().map(String::from).collect()); + } + } None } } +fn all_possible_subcommands<'a>(hyphens: &[usize], cmd: &'a str) -> Vec> { + if hyphens.len() == 2 { + Vec::new() + } else { + let mut res = Vec::new(); + + for i in 1..hyphens.len() - 1 { + let mid = hyphens[i]; + let mut all_right = all_possible_subcommands(&hyphens[i..], cmd); + all_right.push(vec![&cmd[mid..hyphens[hyphens.len() - 1] - 1]]); + for right in all_right { + let mut all_left = all_possible_subcommands(&hyphens[..i + 1], cmd); + all_left.push(vec![&cmd[hyphens[0]..mid - 1]]); + for mut left in all_left { + left.extend_from_slice(&right); + res.push(left); + } + } + } + + res + } +} + /// Find the search path for man /// /// Looks at `$MANPATH` first, then tries running `manpath`, then `man --path`.