diff --git a/meson.build b/meson.build index 7c3915a..636fdee 100644 --- a/meson.build +++ b/meson.build @@ -105,8 +105,14 @@ if uenv_cli 'src/cli/completion.cpp', ] + completion_bash_dep = custom_target( + 'completion-bash-dep', + input: 'src/cli/completion.bash', + output: 'completion.bash.h', + command: ['xxd', '-i', '-n', 'completion_bash_main', '@INPUT@', '@OUTPUT@']) + cli = executable('uenv', - sources: cli_src, + sources: cli_src + completion_bash_dep, dependencies: [uenv_dep, sqlite3_dep, fmt_dep, spdlog_dep, cli11_dep, barkeep_dep], c_args: [ '-DVERSION="@0@"'.format(version), diff --git a/src/cli/completion.bash b/src/cli/completion.bash new file mode 100644 index 0000000..6f097e2 --- /dev/null +++ b/src/cli/completion.bash @@ -0,0 +1,55 @@ +_uenv_completions() +{ + local cur prefix func_name UENV_OPTS + + local -a COMP_WORDS_NO_FLAGS + local index=0 + while [[ "$index" -lt "$COMP_CWORD" ]] + do + if [[ "${COMP_WORDS[$index]}" == [a-z]* ]] + then + COMP_WORDS_NO_FLAGS+=("${COMP_WORDS[$index]}") + fi + let index++ + done + COMP_WORDS_NO_FLAGS+=("${COMP_WORDS[$COMP_CWORD]}") + local COMP_CWORD_NO_FLAGS=$((${#COMP_WORDS_NO_FLAGS[@]} - 1)) + + cur="${COMP_WORDS_NO_FLAGS[COMP_CWORD_NO_FLAGS]}" + prefix="_${COMP_WORDS_NO_FLAGS[*]:0:COMP_CWORD_NO_FLAGS}" + func_name="${prefix// /_}" + func_name="${func_name//-/_}" + + local UENV_OPTS="" + local FILE_COMPLETION="false" + if typeset -f $func_name >/dev/null + then + $func_name + fi + + local SUBCOMMAND_OPTS=$(compgen -W "${UENV_OPTS}" -- "${cur}") + local FILE_OPTS="" + local FILE_OPTS_FORMATED="" + if [ "${FILE_COMPLETION}" = "true" ]; then + FILE_OPTS=$(compgen -f -- "${cur}") + for item in $FILE_OPTS; do + if [[ -d "${item}" ]]; then + FILE_OPTS_FORMATED+="${item}/ " + else + FILE_OPTS_FORMATED+="${item} " + fi + done + fi + + # Do not add space after suggestion if completing a directory + local DIRS=$(compgen -d -- "${cur}") + if [[ -n "${DIRS}" ]]; then + compopt -o nospace + else + compopt +o nospace + fi + + COMPREPLY=(${SUBCOMMAND_OPTS} ${FILE_OPTS_FORMATED}) +} + +complete -F _uenv_completions uenv diff --git a/src/cli/completion.cpp b/src/cli/completion.cpp index 5291888..df921c7 100644 --- a/src/cli/completion.cpp +++ b/src/cli/completion.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -124,67 +125,12 @@ std::string bash_completion(CLI::App* cli, const std::string& name) { item.file_completion ? "true" : "false"); }; - std::string main_functions = R"( -_uenv_completions() -{ - local cur prefix func_name UENV_OPTS - - local -a COMP_WORDS_NO_FLAGS - local index=0 - while [[ "$index" -lt "$COMP_CWORD" ]] - do - if [[ "${COMP_WORDS[$index]}" == [a-z]* ]] - then - COMP_WORDS_NO_FLAGS+=("${COMP_WORDS[$index]}") - fi - let index++ - done - COMP_WORDS_NO_FLAGS+=("${COMP_WORDS[$COMP_CWORD]}") - local COMP_CWORD_NO_FLAGS=$((${#COMP_WORDS_NO_FLAGS[@]} - 1)) - - cur="${COMP_WORDS_NO_FLAGS[COMP_CWORD_NO_FLAGS]}" - prefix="_${COMP_WORDS_NO_FLAGS[*]:0:COMP_CWORD_NO_FLAGS}" - func_name="${prefix// /_}" - func_name="${func_name//-/_}" - - local UENV_OPTS="" - local FILE_COMPLETION="false" - if typeset -f $func_name >/dev/null - then - $func_name - fi - - local SUBCOMMAND_OPTS=$(compgen -W "${UENV_OPTS}" -- "${cur}") - local FILE_OPTS="" - local FILE_OPTS_FORMATED="" - if [ "${FILE_COMPLETION}" = "true" ]; then - FILE_OPTS=$(compgen -f -- "${cur}") - for item in $FILE_OPTS; do - if [[ -d "${item}" ]]; then - FILE_OPTS_FORMATED+="${item}/ " - else - FILE_OPTS_FORMATED+="${item} " - fi - done - fi - - # Do not add space after suggestion if completing a directory - local DIRS=$(compgen -d -- "${cur}") - if [[ -n "${DIRS}" ]]; then - compopt -o nospace - else - compopt +o nospace - fi - - COMPREPLY=(${SUBCOMMAND_OPTS} ${FILE_OPTS_FORMATED}) -} - -complete -F _uenv_completions uenv -)"; +#include "completion.bash.h" return fmt::format( "{}{}", fmt::join(std::views::transform(cl, gen_bash_function), ""), - main_functions); + std::string_view(reinterpret_cast(completion_bash_main), + completion_bash_main_len)); } } // namespace impl