Skip to content

Commit

Permalink
feat: Detect subcommands with hyphens
Browse files Browse the repository at this point in the history
  • Loading branch information
ysthakur committed Aug 10, 2023
1 parent e1e8d22 commit d89b021
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 16 deletions.
6 changes: 3 additions & 3 deletions src/gen/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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;
}
}
Expand Down
10 changes: 3 additions & 7 deletions src/gen/zsh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down Expand Up @@ -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(" \\");
Expand Down Expand Up @@ -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,
Expand Down
47 changes: 41 additions & 6 deletions src/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<String>> {
let parts = cmd_name.split('-').collect::<Vec<_>>();
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<Vec<&'a str>> {
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`.
Expand Down

0 comments on commit d89b021

Please sign in to comment.