Skip to content

Commit

Permalink
feat: auto-search completion script in ARGC_COMPLETIONS_PATH
Browse files Browse the repository at this point in the history
  • Loading branch information
sigoden committed Nov 11, 2023
1 parent 2179388 commit dded13c
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 4 deletions.
10 changes: 6 additions & 4 deletions src/bin/argc/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,13 @@ fn run_compgen(mut args: Vec<String>) -> Option<()> {
let shell: Shell = args.get(2).and_then(|v| v.parse().ok())?;
if args[3].is_empty() {
if args[4] == "argc" {
if let Some((_, script_file_)) = get_script_path(true) {
args[3] = script_file_.to_string_lossy().to_string();
if let Some((_, script_file)) = get_script_path(true) {
args[3] = script_file.to_string_lossy().to_string();
}
} else if let Ok(script_file_) = which(&args[4]) {
args[3] = script_file_.to_string_lossy().to_string();
} else if let Some(script_file) = search_completion_script(&mut args) {
args[3] = script_file.to_string_lossy().to_string();
} else if let Ok(script_file) = which(&args[4]) {
args[3] = script_file.to_string_lossy().to_string();
} else {
return None;
}
Expand Down
64 changes: 64 additions & 0 deletions src/bin/argc/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,67 @@ pub fn candidate_script_names() -> Vec<String> {
names.extend(ARGC_SCRIPT_NAMES.into_iter().map(|v| v.to_string()));
names
}

pub fn search_completion_script(args: &mut Vec<String>) -> Option<PathBuf> {
let search_paths = std::env::var("ARGC_COMPLETIONS_PATH").ok()?;
let cmd = Path::new(&args[4])
.file_stem()
.and_then(|v| v.to_str())?
.to_string();
let subcmd = if args.len() >= 7
&& args[5]
.chars()
.all(|c| c.is_ascii_alphanumeric() || matches!(c, '_' | '-'))
{
Some(args[5].clone())
} else {
None
};
let mut handlers = vec![];
for path in search_paths
.split(':')
.filter(|v| !v.is_empty() && *v != ":")
{
let path = path.to_string();
let cmd = cmd.to_string();
let subcmd = subcmd.clone();
let handler = std::thread::spawn(move || {
if let Some(subcmd) = subcmd {
let mut search_path = PathBuf::from(path.clone());
search_path.push(cmd.clone());
search_path.push(format!("{subcmd}.sh"));
if search_path.exists() {
return Some((search_path, true));
}
}
let mut search_path = PathBuf::from(path);
search_path.push(format!("{cmd}.sh"));
if search_path.exists() {
return Some((search_path, false));
}
None
});
handlers.push(handler);
}
let mut subcmd_script_path = None;
let mut cmd_script_path = None;
for handler in handlers {
if let Ok(Some((path, is_subcmd))) = handler.join() {
if is_subcmd {
subcmd_script_path = Some(path);
break;
} else if cmd_script_path.is_none() {
cmd_script_path = Some(path);
}
}
}
if let (Some(path), Some(subcmd)) = (subcmd_script_path, subcmd) {
args.remove(4);
args[4] = format!("{cmd}-{subcmd}");
return Some(path);
}
if let Some(path) = cmd_script_path {
return Some(path);
}
None
}

0 comments on commit dded13c

Please sign in to comment.