diff --git a/command-signatures/json/pkill.json b/command-signatures/json/pkill.json new file mode 100644 index 00000000..cf230fdc --- /dev/null +++ b/command-signatures/json/pkill.json @@ -0,0 +1,104 @@ +{ + "name": "pkill", + "description": "Find or signal processes by name", + "args": { + "name": "pattern", + "description": "Extended regular expression matched against process names, or full argument lists when -f is used", + "isVariadic": true, + "generatorName": "process_name" + }, + "options": [ + { + "name": "-F", + "description": "Restrict matches to a process whose PID is stored in the pidfile", + "args": { + "name": "pidfile", + "template": "filepaths" + } + }, + { + "name": "-G", + "description": "Restrict matches to processes with a real group ID in the comma-separated list", + "args": { + "name": "gid" + } + }, + { + "name": "-I", + "description": "Request confirmation before attempting to signal each process" + }, + { + "name": "-L", + "description": "Require the pidfile given with -F to be locked" + }, + { + "name": "-P", + "description": "Restrict matches to processes with a parent process ID in the comma-separated list", + "args": { + "name": "ppid" + } + }, + { + "name": "-U", + "description": "Restrict matches to processes with a real user ID in the comma-separated list", + "args": { + "name": "uid", + "generatorName": "user_name" + } + }, + { + "name": "-a", + "description": "Include process ancestors in the match list" + }, + { + "name": "-f", + "description": "Match against full argument lists instead of process names" + }, + { + "name": "-g", + "description": "Restrict matches to processes with a process group ID in the comma-separated list", + "args": { + "name": "pgrp" + } + }, + { + "name": "-i", + "description": "Ignore case distinctions" + }, + { + "name": "-l", + "description": "Display the kill command used for each process killed" + }, + { + "name": "-n", + "description": "Select only the newest matching process" + }, + { + "name": "-o", + "description": "Select only the oldest matching process" + }, + { + "name": "-t", + "description": "Restrict matches to processes associated with terminals in the comma-separated list", + "args": { + "name": "tty" + } + }, + { + "name": "-u", + "description": "Restrict matches to processes with an effective user ID in the comma-separated list", + "args": { + "name": "euid", + "generatorName": "user_name" + } + }, + { + "name": "-v", + "description": "Reverse the sense of the matching" + }, + { + "name": "-x", + "description": "Require an exact match" + } + ] +} diff --git a/command-signatures/src/generators/mod.rs b/command-signatures/src/generators/mod.rs index c4874e0b..3397da11 100644 --- a/command-signatures/src/generators/mod.rs +++ b/command-signatures/src/generators/mod.rs @@ -51,6 +51,7 @@ mod pacman; mod pass; mod phpunit_watcher; mod pip; +mod pkill; mod powershell; mod pprof; mod pyenv; @@ -109,6 +110,7 @@ pub fn dynamic_command_signature_data() -> HashMap CommandSignatureGenerators { + CommandSignatureGenerators::new("pkill") + .add_generator("user_name", common::users_generator()) + .add_generator( + "process_name", + Generator::script( + CommandBuilder::pipe( + CommandBuilder::single_command("ps -A -o comm"), + CommandBuilder::single_command("sort -u"), + ), + process_names, + ), + ) +} + +fn process_names(output: &str) -> warp_completion_metadata::GeneratorResults { + output + .trim() + .lines() + .filter_map(|path| { + let name = path.rsplit('/').next()?; + if !name.is_empty() && name != "COMMAND" { + Some(Suggestion::with_description(name, path)) + } else { + None + } + }) + .collect_unordered_results() +} + +#[cfg(test)] +mod tests { + use super::process_names; + + #[test] + fn test_process_names_handles_paths_and_plain_names() { + let suggestions = process_names("COMMAND\n/usr/bin/python3\nbash\n/System/Library/foo\n"); + let names = suggestions + .suggestions + .into_iter() + .map(|suggestion| suggestion.exact_string) + .collect::>(); + + assert!(names.contains(&"python3".into())); + assert!(names.contains(&"bash".into())); + assert!(names.contains(&"foo".into())); + assert!(!names.contains(&"COMMAND".into())); + } +}