use super::super::{
cli::InitArgs,
constants::SCRIPT_ROOT_ENVIRONMENT_VARIABLE,
shell_type::{get_shell_type, ShellType},
};
macro_rules! bash_zsh_init_body {
() => {
r#"
if [[ -n ${{ZSH_VERSION-}} ]]; then
# bash completion emulation requires that zsh's completion has
# already been initialized. In addition, running the autoload
# expression with the ampersands seems to always result in
# compinit being executed, which clear completions that were
# previously bound by tome, resulting in the inability to
# instantiate multiple tome command sets.
if ! type complete > /dev/null; then
# add -C "" to skip compaudit, which forces
# an interactive dialog for compinit which doesn't
# work for interactive shells.
autoload +X compinit && compinit -C ""
fi
autoload +X bashcompinit && bashcompinit
fi
# completion is accomplished by three parts:
# 1. passing all possible completions to {tome_executable}
# 2. filtering for valid options using compgen
# 3. appending to the valid option environment variable.
function {function_name} {{
export {script_root_environment_variable}="{script_root}"
# capturing the results as a variable led to the command
# being to long for zsh to execute. (literally raising
# "command too long" )
eval `{tome_executable} command-execute {script_root} -s {shell} -- "$@"`
}}
function _{function_name}_completions {{
export {script_root_environment_variable}="{script_root}"
local token_to_complete tome_args
token_to_complete="${{COMP_WORDS[COMP_CWORD]}}";
tome_args="${{COMP_WORDS[@]:1}}"; # strip the first argument prefix, which is the function name
# strip the partial token_to_complete, if there is one
tome_args="${{tome_args%$token_to_complete}}";
all_options=`{tome_executable} command-complete {script_root} -s {shell} -- $tome_args`
valid_options=$(compgen -W "$all_options" -- "$token_to_complete")
COMPREPLY=($valid_options)
}}
complete -F _{function_name}_completions {function_name}
"#
};
}
macro_rules! fish_init_body {
() => {
r#"
# Note: to perform debugging when interface for tome changes
# set set -l fish_trace on before the buggy part of fish script
function __fish_tome_help_message
echo -e "--help\tPrint help\n"
end
function __fish_tome_complete_subcommands
# Arguments: tome command-complete ./example -s fish -- ARGS
$argv[1] $argv[2] $argv[3] $argv[4] $argv[5] $argv[6..-1] | tr " " "\n"
return 0
end
function __fish_tome_completion_inner
set -l help_msg
set -l tokens $argv
switch (count $tokens)
case 0
# Being used as function in fish
__fish_tome_complete_subcommands $tokens
case '*'
__fish_tome_complete_subcommands $tokens
end
end
function __fish_tome_completion_binary
set -l help_msg
set -l tokens $argv
switch (count $tokens)
case 0
echo "Bad codepath"
exit 1
case 1
# > tome
# needs commands
__fish_tome_help_message
echo -e "command-complete\tCompletions\n"
echo -e "command-execute\tExecute\n"
echo -e "help\tHelp\n"
echo -e "init\tInitialize Tome\n"
case 2
# > tome CMD
# return all current directories
ls -d -1 */
__fish_tome_help_message
case 3
echo -e "--shell\tShell\n"
case 4
echo -e "bash\tBash\n"
echo -e "zsh\tZsh\n"
echo -e "fish\tFish\n"
case 5
echo -e "--\tSeparator\n"
case '*'
__fish_tome_complete_subcommands $tokens
end
end
function __fish_tome_completion
set -l args (commandline -co)
set -x {script_root_environment_variable} "{script_root}"
switch $args[1]
case 'tome'
__fish_tome_completion_binary $args
case '*'
echo "Bad codepath"
exit 1
end
end
function __fish_tome_completion_fn
set -l dir $argv[1]
set -l cmdline (commandline -co)
# Drop function name
set -l cmd $cmdline[2..-1]
set -l args "{tome_executable}" command-complete $dir -s "{shell}" -- $cmd
__fish_tome_completion_inner $args
end
complete -c tome -f -a "(__fish_tome_completion)"
# Alias for tome command
function {function_name}
set -x {script_root_environment_variable} "{script_root}"
eval ({tome_executable} command-execute {script_root} -s {shell} -- $argv)
end
complete -c {function_name} -f -a "(__fish_tome_completion_fn {script_root} $argv)"
# End tome alias
"#
};
}
pub fn init(tome_executable: &str, init_args: &InitArgs) -> Result<String, String> {
let shell = get_shell_type(&init_args.shell_type_or_path)?;
match shell {
ShellType::FISH => Ok(format!(
fish_init_body!(),
tome_executable = tome_executable,
shell = &init_args.shell_type_or_path,
script_root = init_args.command_directory_path,
function_name = init_args.command_name,
script_root_environment_variable = SCRIPT_ROOT_ENVIRONMENT_VARIABLE,
)),
ShellType::BASH | ShellType::ZSH => Ok(format!(
bash_zsh_init_body!(),
tome_executable = tome_executable,
shell = &init_args.shell_type_or_path,
script_root = init_args.command_directory_path,
function_name = init_args.command_name,
script_root_environment_variable = SCRIPT_ROOT_ENVIRONMENT_VARIABLE,
)),
ShellType::UNKNOWN => Err(format!(
"could not determine shell from {}. Unable to init.",
&init_args.shell_type_or_path
)),
}
}