tidy up extractions and dynamic completion placement

This commit is contained in:
atagen 2026-05-21 21:02:59 +10:00
parent 2dab68fe03
commit aed5e5c8bc
7 changed files with 600 additions and 104 deletions

View file

@ -814,6 +814,23 @@ fn nushell_module() {
assert!(nu.contains("--verbose(-v)"), "nu = {nu}");
}
#[test]
fn long_switch_rejects_dash_only_separator_lines() {
// less's `--help` (and therefore zstdless/bzless wrappers) is full of
// separator lines like `---------------------------------------------------`.
// the first two chars look like a `--` prefix; the rest is just dashes.
// without an alphanumeric-first guard, the parser would treat the whole
// separator as a flag named `------…`.
let r = parse(" ---------------------------------------------------\n -a, --all show all\n");
assert_eq!(
r.entries.len(),
1,
"separator should not parse as a flag, got {} entries",
r.entries.len()
);
assert!(matches!(&r.entries[0].switch, Switch::Both('a', l) if *l == "all"));
}
#[test]
fn dedup_entries_help() {
let txt = " -v, --verbose verbose output\n --verbose verbose mode\n -v be verbose\n";

View file

@ -241,6 +241,71 @@ fn complete_returns_flags_only_after_hyphen() {
let _ = fs::remove_dir_all(root);
}
#[test]
fn complete_drops_exact_subcommand_match() {
// when the typed token exactly equals a cached subcommand, the binary
// returns null so a downstream dynamic completer (systemctl unit names,
// git remote names, etc.) can take over instead of echoing the
// already-typed word back.
let root = unique_temp_dir("inshellah-exact-subcommand-drop");
let cache_dir = root.join("cache");
fs::create_dir_all(&cache_dir).expect("cache dir");
let result = ManpageResult {
entries: Vec::new(),
subcommands: vec![
ManpageSubcommand {
name: "status".to_string(),
desc: "show status".to_string(),
},
ManpageSubcommand {
name: "start".to_string(),
desc: "start unit".to_string(),
},
],
positionals: Vec::new(),
description: String::new(),
};
write_result(&cache_dir, "demo", "manpage", &result).expect("cache");
let exact = Command::new(env!("CARGO_BIN_EXE_inshellah"))
.arg("complete")
.arg("--dir")
.arg(&cache_dir)
.arg("demo")
.arg("status")
.output()
.expect("run inshellah complete");
assert!(
exact.status.success(),
"stderr = {}",
String::from_utf8_lossy(&exact.stderr)
);
let exact_stdout = String::from_utf8(exact.stdout).expect("stdout");
assert_eq!(
exact_stdout.trim(),
"null",
"exact match should hand off; stdout = {exact_stdout}"
);
let partial = Command::new(env!("CARGO_BIN_EXE_inshellah"))
.arg("complete")
.arg("--dir")
.arg(&cache_dir)
.arg("demo")
.arg("sta")
.output()
.expect("run inshellah complete");
let partial_stdout = String::from_utf8(partial.stdout).expect("stdout");
assert!(
partial_stdout.contains(r#""value":"status""#)
&& partial_stdout.contains(r#""value":"start""#),
"partial should still match both; stdout = {partial_stdout}"
);
let _ = fs::remove_dir_all(root);
}
#[test]
fn complete_resolves_absolute_path_after_elevation_wrapper() {
let root = unique_temp_dir("inshellah-absolute-elevation-complete");