Skip to content

Commit

Permalink
feat: sanitize command name
Browse files Browse the repository at this point in the history
  • Loading branch information
sigoden committed Aug 6, 2023
1 parent 6f0dc57 commit fe1fda3
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 20 deletions.
30 changes: 16 additions & 14 deletions src/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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<String> =
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
Expand Down Expand Up @@ -423,20 +425,16 @@ impl Command {
}

pub(crate) fn list_names(&self) -> Vec<String> {
let mut output = vec![self.name.clone().unwrap_or_default()];
let mut output: Vec<String> = self.name.clone().into_iter().collect();
output.extend(self.aliases.to_vec());
output
}

pub(crate) fn list_subcommand_names(&self) -> Vec<String> {
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> {
Expand Down Expand Up @@ -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<usize>) -> String {
let size = term_width.unwrap_or(999) - name.len();
let empty = " ".repeat(name.len());
Expand Down
7 changes: 1 addition & 6 deletions src/matcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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![]);
}

Expand Down
88 changes: 88 additions & 0 deletions tests/snapshots/integration__validate__cmd_name_sanitize.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
source: tests/validate.rs
expression: data
---
************ RUN ************
prog --help

OUTPUT
command cat >&2 <<-'EOF'
USAGE: prog <COMMAND>

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 <COMMAND>

COMMANDS:
foo
bar

EOF
exit 0

************ RUN ************
prog do

OUTPUT
command cat >&2 <<-'EOF'
USAGE: prog do <COMMAND>

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


42 changes: 42 additions & 0 deletions tests/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
]
);
}

0 comments on commit fe1fda3

Please sign in to comment.