use crate::common::*; #[derive(PartialEq, Clone, Debug)] pub(crate) enum Subcommand { Choose { overrides: BTreeMap, chooser: Option, }, Completions { shell: String, }, Dump, Edit, Evaluate { overrides: BTreeMap, }, Init, List, Run { overrides: BTreeMap, arguments: Vec, }, Show { name: String, }, Summary, Variables, } const FISH_RECIPE_COMPLETIONS: &str = r#"function __fish_just_complete_recipes just --summary 2> /dev/null | tr " " "\n" || echo "" end # don't suggest files right off complete -c just -n "__fish_is_first_arg" --no-files # complete recipes complete -c just -a '(__fish_just_complete_recipes)' # autogenerated completions "#; const ZSH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[ ( r#" _arguments "${_arguments_options[@]}" \"#, r#" local common=("#, ), ( r#"'*--set=[Override with ]' \"#, r#"'*--set[Override with ]: :_just_variables' \"#, ), ( r#"'-s+[Show information about ]' \ '--show=[Show information about ]' \"#, r#"'-s+[Show information about ]: :_just_commands' \ '--show=[Show information about ]: :_just_commands' \"#, ), ( "'::ARGUMENTS -- Overrides and recipe(s) to run, defaulting to the first recipe in the \ justfile:_files' \\ && ret=0 \x20\x20\x20\x20 ", r#") _arguments "${_arguments_options[@]}" $common \ '1: :_just_commands' \ '*: :->args' \ && ret=0 case $state in args) curcontext="${curcontext%:*}-${words[2]}:" local lastarg=${words[${#words}]} if [[ ${lastarg} = */* ]]; then # Arguments contain slash would be recognised as a file _arguments -s -S $common '*:: :_files' else # Show usage message _message "`just --show ${words[2]}`" # Or complete with other commands #_arguments -s -S $common '*:: :_just_commands' fi ;; esac return ret "#, ), ( " local commands; commands=( \x20\x20\x20\x20\x20\x20\x20\x20 )", r#" local commands; commands=( ${${${(M)"${(f)$(_call_program commands just --list)}":# *}/ ##/}/ ##/:Args: } ) "#, ), ( r#"_just "$@""#, r#"(( $+functions[_just_variables] )) || _just_variables() { local variables; variables=( ${(s: :)$(_call_program commands just --variables)} ) _describe -t variables 'variables' variables } _just "$@""#, ), ]; const BASH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[( r#" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi"#, r#" if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 elif [[ ${COMP_CWORD} -eq 1 ]]; then local recipes=$(just --summary --color never 2> /dev/null) if [[ $? -eq 0 ]]; then COMPREPLY=( $(compgen -W "${recipes}" -- "${cur}") ) return 0 fi fi"#, )]; impl Subcommand { pub(crate) fn completions(shell: &str) -> Result<(), i32> { use clap::Shell; fn replace(haystack: &mut String, needle: &str, replacement: &str) -> Result<(), i32> { if let Some(index) = haystack.find(needle) { haystack.replace_range(index..index + needle.len(), replacement); Ok(()) } else { eprintln!("Failed to find text:"); eprintln!("{}", needle); eprintln!("…in completion script:"); eprintln!("{}", haystack); Err(EXIT_FAILURE) } } let shell = shell .parse::() .expect("Invalid value for clap::Shell"); let buffer = Vec::new(); let mut cursor = Cursor::new(buffer); Config::app().gen_completions_to(env!("CARGO_PKG_NAME"), shell, &mut cursor); let buffer = cursor.into_inner(); let mut script = String::from_utf8(buffer).expect("Clap completion not UTF-8"); match shell { Shell::Bash => for (needle, replacement) in BASH_COMPLETION_REPLACEMENTS { replace(&mut script, needle, replacement)?; }, Shell::Fish => { script.insert_str(0, FISH_RECIPE_COMPLETIONS); }, Shell::Zsh => for (needle, replacement) in ZSH_COMPLETION_REPLACEMENTS { replace(&mut script, needle, replacement)?; }, _ => {}, } println!("{}", script.trim()); Ok(()) } }