use shell_escape::escape;
use std::borrow::Cow;
use std::path::Path;
pub fn suggest_command(subcommand: &str, args: &[&str], flags: &[&str]) -> String {
format_command(None, subcommand, args, flags)
}
pub fn suggest_command_in_dir(
working_dir: &Path,
subcommand: &str,
args: &[&str],
flags: &[&str],
) -> String {
format_command(Some(working_dir), subcommand, args, flags)
}
fn format_command(
working_dir: Option<&Path>,
subcommand: &str,
args: &[&str],
flags: &[&str],
) -> String {
let mut parts = vec!["wt".to_string()];
if let Some(dir) = working_dir {
parts.push("-C".to_string());
parts.push(crate::path::format_path_for_display(dir));
}
parts.push(subcommand.to_string());
parts.extend(flags.iter().map(|s| s.to_string()));
let needs_separator = args.iter().any(|arg| arg.starts_with('-'));
let mut separator_inserted = false;
for arg in args {
if needs_separator && arg.starts_with('-') && !separator_inserted {
parts.push("--".to_string());
separator_inserted = true;
}
parts.push(escape(Cow::Borrowed(*arg)).into_owned());
}
parts.join(" ")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_simple_command() {
assert_eq!(
suggest_command("remove", &["feature"], &[]),
"wt remove feature"
);
}
#[test]
fn test_command_with_flag() {
assert_eq!(
suggest_command("remove", &["feature"], &["--force"]),
"wt remove --force feature"
);
}
#[test]
fn test_command_with_multiple_flags() {
assert_eq!(
suggest_command("remove", &["feature"], &["--force", "--no-delete-branch"]),
"wt remove --force --no-delete-branch feature"
);
}
#[test]
fn test_branch_with_spaces() {
assert_eq!(
suggest_command("remove", &["my feature"], &[]),
"wt remove 'my feature'"
);
}
#[test]
fn test_branch_with_special_chars() {
assert_eq!(
suggest_command("remove", &["feature$1"], &[]),
"wt remove 'feature$1'"
);
}
#[test]
fn test_branch_starting_with_dash() {
assert_eq!(
suggest_command("remove", &["-bugfix"], &[]),
"wt remove -- -bugfix"
);
}
#[test]
fn test_branch_starting_with_dash_and_flag() {
assert_eq!(
suggest_command("remove", &["-bugfix"], &["--force"]),
"wt remove --force -- -bugfix"
);
}
#[test]
fn test_multiple_args() {
assert_eq!(
suggest_command("remove", &["feature", "bugfix"], &[]),
"wt remove feature bugfix"
);
}
#[test]
fn test_mixed_args_one_starting_with_dash() {
assert_eq!(
suggest_command("remove", &["feature", "-bugfix"], &[]),
"wt remove feature -- -bugfix"
);
}
#[test]
fn test_multiple_dash_prefixed_args() {
assert_eq!(
suggest_command("remove", &["-bugfix", "-feature"], &[]),
"wt remove -- -bugfix -feature"
);
}
#[test]
fn test_branch_with_single_quote() {
assert_eq!(
suggest_command("remove", &["it's-a-branch"], &[]),
"wt remove 'it'\\''s-a-branch'"
);
}
#[test]
fn test_no_args() {
assert_eq!(suggest_command("list", &[], &[]), "wt list");
}
#[test]
fn test_flag_only() {
assert_eq!(suggest_command("list", &[], &["--full"]), "wt list --full");
}
#[test]
fn test_in_dir_simple_path() {
assert_eq!(
suggest_command_in_dir(Path::new("/tmp/repo"), "config", &["update"], &[]),
"wt -C /tmp/repo config update"
);
}
#[test]
fn test_in_dir_path_with_spaces() {
assert_eq!(
suggest_command_in_dir(Path::new("/tmp/my repo"), "config", &["update"], &[]),
"wt -C '/tmp/my repo' config update"
);
}
#[test]
fn test_in_dir_with_flags_and_args() {
assert_eq!(
suggest_command_in_dir(Path::new("/tmp/repo"), "remove", &["feature"], &["--force"]),
"wt -C /tmp/repo remove --force feature"
);
}
}