diff --git a/src/command/mod.rs b/src/command/mod.rs index 0980f8f1..c3297dfe 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -193,7 +193,7 @@ impl Command { bail!("{}(line {}) invalid command name", name, position); } else if parts_len == 1 { let cmd = root_cmd.subcommands.last_mut().unwrap(); - cmd.name = Some(parts[0].to_string()); + cmd.name = Some(sanitize_cmd_name(&name)); cmd.fn_name = Some(name.to_string()); for name in &cmd.aliases { if let Some(pos) = root_data.borrow().cmd_fns.get(name) { @@ -211,9 +211,11 @@ impl Command { } else { let mut cmd = root_cmd.subcommands.pop().unwrap(); let (child, parents) = parts.split_last().unwrap(); - cmd.name = Some(child.to_string()); + let parents: Vec = + parents.iter().map(|v| sanitize_cmd_name(v)).collect(); + cmd.name = Some(sanitize_cmd_name(child)); cmd.fn_name = Some(name.to_string()); - match retrive_cmd(&mut root_cmd, parents) { + match retrive_cmd(&mut root_cmd, &parents) { Some(parent_cmd) => { parent_cmd .subcommand_fns @@ -423,20 +425,16 @@ impl Command { } pub(crate) fn list_names(&self) -> Vec { - let mut output = vec![self.name.clone().unwrap_or_default()]; + let mut output: Vec = self.name.clone().into_iter().collect(); output.extend(self.aliases.to_vec()); output } pub(crate) fn list_subcommand_names(&self) -> Vec { - let mut output = vec![]; - for subcmd in self.subcommands.iter() { - if let Some(name) = subcmd.name.clone() { - output.push(name); - } - output.extend(subcmd.aliases.to_vec()); - } - output + self.subcommands + .iter() + .flat_map(|v| v.list_names()) + .collect() } pub(crate) fn find_subcommand(&self, name: &str) -> Option<&Self> { @@ -608,17 +606,21 @@ impl Command { } } -fn retrive_cmd<'a>(cmd: &'a mut Command, cmd_paths: &[&str]) -> Option<&'a mut Command> { +fn retrive_cmd<'a>(cmd: &'a mut Command, cmd_paths: &[String]) -> Option<&'a mut Command> { if cmd_paths.is_empty() { return Some(cmd); } let child = cmd .subcommands .iter_mut() - .find(|v| v.name.as_deref() == Some(cmd_paths[0]))?; + .find(|v| v.name.as_deref() == Some(cmd_paths[0].as_str()))?; retrive_cmd(child, &cmd_paths[1..]) } +fn sanitize_cmd_name(name: &str) -> String { + name.trim_end_matches('_').replace('_', "-") +} + fn wrap_render_block(name: &str, describe: &str, term_width: Option) -> String { let size = term_width.unwrap_or(999) - name.len(); let empty = " ".repeat(name.len()); diff --git a/src/matcher.rs b/src/matcher.rs index e77d20d4..5d35b17d 100644 --- a/src/matcher.rs +++ b/src/matcher.rs @@ -942,12 +942,7 @@ fn match_command<'a, 'b>( arg_index: usize, ) { *cmd_level += 1; - cmds.push(( - arg, - subcmd, - subcmd.name.clone().unwrap_or_else(|| arg.to_string()), - arg_index, - )); + cmds.push((arg, subcmd, arg.to_string(), arg_index)); flag_option_args.push(vec![]); } diff --git a/tests/snapshots/integration__validate__cmd_name_sanitize.snap b/tests/snapshots/integration__validate__cmd_name_sanitize.snap new file mode 100644 index 00000000..412fc2e1 --- /dev/null +++ b/tests/snapshots/integration__validate__cmd_name_sanitize.snap @@ -0,0 +1,88 @@ +--- +source: tests/validate.rs +expression: data +--- +************ RUN ************ +prog --help + +OUTPUT +command cat >&2 <<-'EOF' +USAGE: prog + +COMMANDS: + cat + do + foo-bar + +EOF +exit 0 + +************ RUN ************ +prog cat --help + +OUTPUT +command cat >&2 <<-'EOF' +USAGE: prog cat + +EOF +exit 0 + +************ RUN ************ +prog cat + +OUTPUT +argc__args=( prog cat ) +argc__index=1 +argc__fn=cat_ +argc__positionals=( ) +cat_ + +************ RUN ************ +prog do --help + +OUTPUT +command cat >&2 <<-'EOF' +USAGE: prog do + +COMMANDS: + foo + bar + +EOF +exit 0 + +************ RUN ************ +prog do + +OUTPUT +command cat >&2 <<-'EOF' +USAGE: prog do + +COMMANDS: + foo + bar + +EOF +exit 0 + +************ RUN ************ +prog do foo + +OUTPUT +argc__args=( prog do foo ) +argc__index=2 +argc__fn=do_::foo +argc__positionals=( ) +do_::foo + +************ RUN ************ +prog foo-bar + +OUTPUT +argc__args=( prog foo-bar ) +argc__index=1 +argc__fn=foo_bar +argc__positionals=( ) +foo_bar + + diff --git a/tests/validate.rs b/tests/validate.rs index 975d12a9..b2432b7a 100644 --- a/tests/validate.rs +++ b/tests/validate.rs @@ -212,3 +212,45 @@ _choice_fn() { "###; snapshot_multi!(script, vec![vec!["prog", "cmd", "a\\b", "a\\b"],]); } + +#[test] +fn cmd_name_sanitize() { + let script = r###" +# @cmd +cat_() { + echo run cat_ +} + +# @cmd +do_() { + echo run do_ +} + +# @cmd +do_::foo() { + echo run do_::foo +} + +# @cmd +do_::bar() { + echo run do_::bar +} + +# @cmd +foo_bar() { + echo run foo_bar +} +"###; + snapshot_multi!( + script, + vec![ + vec!["prog", "--help"], + vec!["prog", "cat", "--help"], + vec!["prog", "cat"], + vec!["prog", "do", "--help"], + vec!["prog", "do"], + vec!["prog", "do", "foo"], + vec!["prog", "foo-bar"], + ] + ); +}