diff --git a/src/_cmake b/src/_cmake index 8822589..72ed6eb 100644 --- a/src/_cmake +++ b/src/_cmake @@ -79,7 +79,7 @@ local -a cmake_build_options=( '--list-presets[List available presets]' '--workflow[Run a workflow preset]' - '-E[CMake command mode]:command:_cmake_command_help' + '-E[CMake command mode]:command:_cmake_commands' '-L-[List cache variables]::_values "options" "[non-advanced cache variables]" "A[advanced cache variables]" "H[non-advanced cached variables with help]" "AH[advanced cache variables with help]"' '--fresh[Configure a fresh build tree, removing any existing cache file]' @@ -149,11 +149,11 @@ _cmake_generator_options() { # -------------- (( $+functions[_cmake_presets] )) || _cmake_presets() { - local invoke; invoke=(${(Q)words}) + local invoke=(${(Q)words}) invoke[$CURRENT]=() # TODO: remove all arguments -* except -S - local list_presets; list_presets=(${(f)"$(${invoke} --list-presets 2>/dev/null | + local list_presets=(${(f)"$(${invoke} --list-presets 2>/dev/null | sed -n -e 's,^[[:space:]]*"\([^"]*\)"[[:space:]]*-[[:space:]]*\(.*\),\1:\2,p' \ -e 's,^[[:space:]]*"\([^"]*\)"[[:space:]]*$,\1,p')"}) @@ -165,24 +165,16 @@ _cmake_presets() { # -------------- (( $+functions[_cmake_targets] )) || _cmake_targets() { - local -a targets - if [ -f $1/Makefile ] - then + local dir="$1" + local -a targets=() + if [[ -f "${dir}/Makefile" && $+commands[make] ]]; then # `make help` doesn't work for Makefiles in general, but for CMake generated Makefiles it does. - i=1 - for target in $(make -f $1/Makefile help | \grep -e "\.\.\." | sed "s/\.\.\. //" | sed "s/ (the default.*//") ; do - targets[$i]=$target - (( i = $i + 1 )) - done - elif [ -f $1/build.ninja ] - then + targets=(${(f)"$(make -f $dir/Makefile help 2>/dev/null | awk '/^\.\.\./ { print $2 }')"}) + elif [[ -f "${dir}/build.ninja" && $+commands[ninja] ]]; then # `ninja help` doesn't seem to be the list of targets we're interested in - i=1 - for target in $(ninja -C $1 -t targets all 2&>/dev/null | awk -F: '{print $1}') ; do - targets[$i]="$target" - (( i++ )) - done + targets=(${(f)"$(ninja -C $dir -t targets all 2>/dev/null | awk -F: '{print $1}' )"}) fi + _describe 'build targets' targets } @@ -195,44 +187,53 @@ _cmake_suggest_installdirs() { } _cmake_on_build() { - local build_extras;build_extras=( + local build_extras=( '--[Native build tool options]' '--target[specify build target]' '--clean-first[build target clean first]' '--config[For multi-configuration tools]' '--parallel[maximum number of build processes]' - '--use-stderr') + '--use-stderr' + ) local -a undescribed_build_extras - i=1 + local i=1 for be in $build_extras ; do undescribed_build_extras[$i]=$(echo $be | sed "s/\[.*//") (( i++ )) done - inbuild=false - dashdashposition=-1 + + local in_build=false + local dash_dash_position=-1 + local build_at=$CURRENT for ((i = (($CURRENT - 1)); i > 1 ; i--)); do - if [[ $words[$i] == --build ]] ; then - inbuild=true - buildat=$i + if [[ $words[$i] == --build ]]; then + in_build=true + build_at=$i (( difference = $CURRENT - $i )) - elif [[ $words[$i] == -- ]] ; then - dashdashposition=$i + elif [[ $words[$i] == -- ]]; then + dash_dash_position=$i fi done + # check if build mode has been left - outofbuild=false - for ((i = (($CURRENT - 1)); i > (($buildat + 1)); i--)); do + local out_of_build=false + for ((i = (($CURRENT - 1)); i > (($build_at + 1)); i--)); do # don't check the word after --build (should be a directory) - if [[ ${undescribed_build_extras[(r)$words[$i]]} == $words[$i] ]] ; then continue ; fi - if [[ $words[(($i - 1))] == --target ]] ; then continue ; fi - if [[ $words[(($i - 1))] == --config ]] ; then continue ; fi + if [[ ${undescribed_build_extras[(r)$words[$i]]} == $words[$i] ]]; then + continue + fi + + if [[ $words[(($i - 1))] == --target ]]; then continue ; fi + if [[ $words[(($i - 1))] == --config ]]; then continue ; fi if [[ $words[(($i - 1))] == --parallel ]] ; then continue ; fi - outofbuild=true + out_of_build=true done - if (( $dashdashposition > 0 )) ; then - _cmake_generator_options $words[(($buildat + 1))] $dashdashposition && return 0 + + if (( $dash_dash_position > 0 )) ; then + _cmake_generator_options $words[(($build_at + 1))] $dash_dash_position && return 0 fi - if [[ "$inbuild" == false || "$difference" -eq 1 ]] ; then + + if [[ "$in_build" == false || "$difference" -eq 1 ]] ; then # either there is no --build or completing the directory after --build _arguments -C -s \ - build_opts \ @@ -241,14 +242,14 @@ _cmake_on_build() { "$cmake_suggest_build[@]" && return 0 elif [[ $words[(($CURRENT - 1))] == --target ]] ; then # after --build --target, suggest targets - _cmake_targets $words[(($buildat + 1))] && return 0 + _cmake_targets $words[(($build_at + 1))] && return 0 elif [[ $words[(($CURRENT - 1))] == --config ]] ; then # after --build --config, no idea return 0 elif [[ $words[(($CURRENT - 1))] == --parallel ]] ; then # after --build --parallel return 0 - elif [ "$outofbuild" = true ] ; then + elif [ "$out_of_build" = true ] ; then # after --build --, suggest other cmake_build_options (like -Wno-dev) _arguments "$cmake_build_options[@]" && return 0 else @@ -258,43 +259,49 @@ _cmake_on_build() { } _cmake_on_install() { - local build_extras;build_extras=( + local build_extras=( '--[Native build tool options]' '--prefix[Override the installation prefix, CMAKE_INSTALL_PREFIX]' '--config[For multi-configuration generators(e.g. Visual Studio)]' '--component[Component-based install]' '--strip[Strip before installing.]' - ) + ) + local -a undescribed_build_extras - i=1 + local i=1 for be in $build_extras ; do undescribed_build_extras[$i]=$(echo $be | sed "s/\[.*//") (( i++ )) done - inbuild=false - dashdashposition=-1 + + local in_build=false + local dash_dash_position=-1 + local build_at=$CURRENT for ((i = (($CURRENT - 1)); i > 1 ; i--)); do - if [[ $words[$i] == --install ]] ; then - inbuild=true - buildat=$i + if [[ $words[$i] == --install ]]; then + in_build=true + build_at=$i (( difference = $CURRENT - $i )) - elif [[ $words[$i] == -- ]] ; then - dashdashposition=$i + elif [[ $words[$i] == -- ]]; then + dash_dash_position=$i fi done - outofbuild=false - for ((i = (($CURRENT - 1)); i > (($buildat + 1)); i--)); do + + local out_of_build=false + for ((i = (($CURRENT - 1)); i > (($build_at + 1)); i--)); do # don't check the word after --install (should be a directory) if [[ ${undescribed_build_extras[(r)$words[$i]]} == $words[$i] ]] ; then continue ; fi - if [[ $words[(($i - 1))] == --prefix ]] ; then continue ; fi - if [[ $words[(($i - 1))] == --config ]] ; then continue ; fi - if [[ $words[(($i - 1))] == --component ]] ; then continue ; fi - outofbuild=true + if [[ $words[(($i - 1))] == --prefix ]]; then continue ; fi + if [[ $words[(($i - 1))] == --config ]]; then continue ; fi + if [[ $words[(($i - 1))] == --component ]]; then continue ; fi + out_of_build=true done - if (( $dashdashposition > 0 )) ; then - _cmake_generator_options $words[(($buildat + 1))] $dashdashposition && return 0 + + if (( $dash_dash_position > 0 )) ; then + _cmake_generator_options $words[(($build_at + 1))] $dash_dash_position && return 0 fi - if [[ "$inbuild" == false || "$difference" -eq 1 ]] ; then + + if [[ "$in_build" == false || "$difference" -eq 1 ]] ; then # either there is no --install or completing the directory after --install _arguments -C -s \ - build_opts \ @@ -310,7 +317,7 @@ _cmake_on_install() { elif [[ $words[(($CURRENT - 1))] == --component ]] ; then # after --build --component, no idea return 0 - elif [ "$outofbuild" = true ] ; then + elif [ "$out_of_build" = true ] ; then # after --build --, suggest other cmake_build_options (like -Wno-dev) _arguments "$cmake_build_options[@]" && return 0 else @@ -341,19 +348,16 @@ local -a cmake_help_actions=( '(- 1)--help-variable-list[List variables with help available and exit]' '(- 1)--help-variables[Print cmake-variables manual and exit]' ) -_cmake_help() { - _arguments -C -s - help "$cmake_help_actions[@]" -} # ----------------- # _cmake_list_names # ----------------- (( $+functions[_cmake_list_names] )) || _cmake_list_names() { - local command; command="$@[1]" - local desc; desc="$@[2]" - local opts; opts=($@[3]) - local list_names; list_names=(${(f)"$($service $command 2> /dev/null)"}) + local command="$@[1]" + local desc="$@[2]" + local opts=($@[3]) + local list_names=(${(f)"$($service $command 2> /dev/null)"}) # Older CMake (< 3.0) writes out the version list_names=(${^list_names##cmake version*}) @@ -382,7 +386,7 @@ _cmake_define_property() { # ---------------------------- (( $+functions[_cmake_define_property_names] )) || _cmake_define_property_names() { - local alternatives; alternatives=( + local alternatives=( 'common-property-names:common property name:_cmake_define_common_property_names -qS=' ) local -A cmake_langs @@ -402,8 +406,9 @@ _cmake_define_property_names() { # --------------------------------- (( $+functions[_cmake_define_lang_property_names] )) || _cmake_define_lang_property_names() { - local cmake_lang="$@[-2]" cmake_lang_desc="$@[-1]" - local properties; properties=( + local cmake_lang="$@[-2]" + local cmake_lang_desc="$@[-1]" + local -a properties=( "CMAKE_${cmake_lang}_COMPILER:${cmake_lang_desc} compiler" "CMAKE_${cmake_lang}_COMPILER_LAUNCHER:${cmake_lang_desc} compiler launcher (e.g. ccache)" "CMAKE_${cmake_lang}_FLAGS:${cmake_lang_desc} compiler flags for all builds" @@ -424,7 +429,7 @@ _cmake_define_lang_property_names() { # ----------------------------------- (( $+functions[_cmake_define_common_property_names] )) || _cmake_define_common_property_names() { - local properties; properties=( + local -a properties=( 'CMAKE_MODULE_PATH:Search path for CMake modules (FindPROJECT.cmake)' 'CMAKE_PREFIX_PATH:Search path for installations (PROJECTConfig.cmake)' 'CMAKE_BUILD_TYPE:Specifies the build type for make based generators' @@ -438,51 +443,87 @@ _cmake_define_common_property_names() { 'CMAKE_UNITY_BUILD:Batch include source files' ) - _describe -t 'common-property-names' 'common property name' properties $@ + _describe -t 'common-property-names' 'common property name' properties "$@" } -local _cmake_build_types=('Debug' 'Release' 'RelWithDebInfo' 'MinSizeRel') -local _cmake_c_standards=(90 99 11) -local _cmake_cxx_standards=(98 11 14 17 20) - # ---------------------------- # _cmake_define_property_values # ---------------------------- (( $+functions[_cmake_define_property_values] )) || _cmake_define_property_values() { local ret=1 + local build_types=('Debug' 'Release' 'RelWithDebInfo' 'MinSizeRel') + local c_standards=(90 99 11 17 23) + local cxx_standards=(98 11 14 17 20 23) + setopt localoptions extendedglob case $@[-1] in - (CMAKE_BUILD_TYPE) _wanted build-types expl 'build type' _values 'build type' ${_cmake_build_types[@]} && ret=0;; - (BUILD_SHARED_LIBS) _wanted booleans expl 'boolean' _cmake_booleans && ret=0;; - (CMAKE_CXX_STANDARD) _wanted cxx-standards expl 'cxx standard' _values 'cxx standard' ${_cmake_cxx_standards[@]} && ret=0;; - (CMAKE_C_STANDARD) _wanted c-standards expl 'c standard' _values 'c standard' ${_cmake_c_standards[@]} && ret=0;; - (CMAKE_TOOLCHAIN_FILE) _wanted toolchain-files expl 'file' _cmake_toolchain_files && ret=0;; - (CMAKE_COLOR_MAKEFILE) _wanted booleans expl 'boolean' _cmake_booleans && ret=0;; - (CMAKE_RULE_MESSAGES) _wanted booleans expl 'boolean' _cmake_booleans && ret=0;; - (CMAKE_VERBOSE_MAKEFILE) _wanted booleans expl 'boolean' _cmake_booleans && ret=0;; - (CMAKE_UNITY_BUILD) _wanted booleans expl 'boolean' _cmake_booleans && ret=0;; - (CMAKE_INSTALL_PREFIX) _files -/ && ret=0;; - (CMAKE_EXPORT_COMPILE_COMMANDS) _wanted booleans expl 'boolean' _cmake_booleans && ret=0;; - (CMAKE_*_COMPILER) _wanted compilers expl 'compiler' _cmake_compilers && ret=0;; - (CMAKE_*_COMPILER_LAUNCHER) _wanted compilers expl 'compiler launcher' _cmake_launchers && ret=0;; - (CMAKE_*_FLAGS(|_?*)) _message -e compiler-flags 'compiler flags' && _dispatch $service -value-,CPPFLAGS,-default- && ret=0;; - (CMAKE_*_STANDARD_REQUIRED) _wanted booleans expl 'boolean' _cmake_booleans && ret=0;; - (CMAKE_*_EXTENSIONS) _wanted booleans expl 'boolean' _cmake_booleans && ret=0;; - (*) _files && ret=0;; + (CMAKE_BUILD_TYPE) + _wanted build-types expl 'build type' _values 'build type' ${build_types[@]} && ret=0 + ;; + (BUILD_SHARED_LIBS) + _wanted booleans expl 'boolean' _cmake_booleans && ret=0 + ;; + (CMAKE_CXX_STANDARD) + _wanted cxx-standards expl 'cxx standard' _values 'cxx standard' ${cxx_standards[@]} && ret=0 + ;; + (CMAKE_C_STANDARD) + _wanted c-standards expl 'c standard' _values 'c standard' ${c_standards[@]} && ret=0 + ;; + (CMAKE_TOOLCHAIN_FILE) + _wanted toolchain-files expl 'file' _cmake_toolchain_files && ret=0 + ;; + (CMAKE_COLOR_MAKEFILE) + _wanted booleans expl 'boolean' _cmake_booleans && ret=0 + ;; + (CMAKE_RULE_MESSAGES) + _wanted booleans expl 'boolean' _cmake_booleans && ret=0 + ;; + (CMAKE_VERBOSE_MAKEFILE) + _wanted booleans expl 'boolean' _cmake_booleans && ret=0 + ;; + (CMAKE_UNITY_BUILD) + _wanted booleans expl 'boolean' _cmake_booleans && ret=0 + ;; + (CMAKE_INSTALL_PREFIX) + _files -/ && ret=0 + ;; + (CMAKE_EXPORT_COMPILE_COMMANDS) + _wanted booleans expl 'boolean' _cmake_booleans && ret=0 + ;; + (CMAKE_*_COMPILER) + _wanted compilers expl 'compiler' _cmake_compilers && ret=0 + ;; + (CMAKE_*_COMPILER_LAUNCHER) + _wanted compilers expl 'compiler launcher' _cmake_launchers && ret=0 + ;; + (CMAKE_*_FLAGS(|_?*)) + _message -e compiler-flags 'compiler flags' && _dispatch $service -value-,CPPFLAGS,-default- && ret=0 + ;; + (CMAKE_*_STANDARD_REQUIRED) + _wanted booleans expl 'boolean' _cmake_booleans && ret=0 + ;; + (CMAKE_*_EXTENSIONS) + _wanted booleans expl 'boolean' _cmake_booleans && ret=0 + ;; + (*) + _files && ret=0 + ;; esac return ret } -local -a _cmake_generator_list=(${(f)"$(cmake --help | awk '/^Generators/{flag=1} flag && /^[* ] [^ ]/ {sub(/^[* ] /, ""); sub(/=.*$/, ""); sub(/\[arch\]/, ""); sub(/ *$/, ""); print}')"}) - # ----------------- # _cmake_generators # ----------------- (( $+functions[_cmake_generators] )) || _cmake_generators() { - _describe -t generators 'generator' _cmake_generator_list + local -a generators=( + ${(f)"$(cmake --help | awk '/^Generators/{flag=1} flag && /^[* ] [^ ]/ {sub(/^[* ] /, ""); sub(/=.*$/, ""); sub(/\[arch\]/, ""); sub(/ *$/, ""); print}')"} + ) + + _describe -t generators 'generator' generators } # ---------------------- @@ -519,45 +560,46 @@ _cmake_launchers() { _command_names -e } -local -a _cmake_commands=( - 'capabilities:Report capabilities built into cmake in JSON format' \ - 'cat:concat the files and print them to the standard output' \ - 'chdir:run command in a given directory' \ - 'compare_files:check if file1 is same as file2' \ - 'copy:copy files to destination (either file or directory)' \ - 'copy_directory:copy content of ... directories to destination directory' \ - 'copy_if_different:copy files if it has changed' \ - 'echo:displays arguments as text' \ - 'echo_append:displays arguments as text but no new line' \ - 'env:run command in a modified environment' \ - 'environment:display the current environment' \ - 'make_directory:create parent and directories' \ - 'md5sum:create MD5 checksum of files' \ - 'sha1sum:create SHA1 checksum of files' \ - 'sha224sum:create SHA224 checksum of files' \ - 'sha256sum:create SHA256 checksum of files' \ - 'sha384sum:create SHA384 checksum of files' \ - 'sha512sum:create SHA512 checksum of files' \ - 'remove:remove the file(s), use -f to force it' \ - 'remove_directory:remove directories and their contents' \ - 'rename:rename a file or directory (on one volume)' \ - 'rm:remove files or directories' \ - 'server:start cmake in server mode' \ - 'sleep:sleep for given number of seconds' \ - 'tar:create or extract a tar or zip archive' \ - 'time:run command and display elapsed time' \ - 'touch:touch a ' \ - 'touch_nocreate:touch a but do not create it' \ - 'create_symlink:create a symbolic link new -> old' \ - 'create_hardlink:create a hard link new -> old' \ - 'true:do nothing with an exit code of 0' \ - 'false:do nothing with an exit code of 1' -) -_cmake_command() { - _arguments -C \ - '-E[CMake command mode]:command:(("${_cmake_commands[@]}"))' +(( $+functions[_cmake_commands] )) || +_cmake_commands() { + local -a commands=( + 'capabilities:Report capabilities built into cmake in JSON format' + 'cat:concat the files and print them to the standard output' + 'chdir:run command in a given directory' + 'compare_files:check if file1 is same as file2' + 'copy:copy files to destination (either file or directory)' + 'copy_directory:copy content of ... directories to destination directory' + 'copy_if_different:copy files if it has changed' + 'echo:displays arguments as text' + 'echo_append:displays arguments as text but no new line' + 'env:run command in a modified environment' + 'environment:display the current environment' + 'make_directory:create parent and directories' + 'md5sum:create MD5 checksum of files' + 'sha1sum:create SHA1 checksum of files' + 'sha224sum:create SHA224 checksum of files' + 'sha256sum:create SHA256 checksum of files' + 'sha384sum:create SHA384 checksum of files' + 'sha512sum:create SHA512 checksum of files' + 'remove:remove the file(s), use -f to force it' + 'remove_directory:remove directories and their contents' + 'rename:rename a file or directory (on one volume)' + 'rm:remove files or directories' + 'server:start cmake in server mode' + 'sleep:sleep for given number of seconds' + 'tar:create or extract a tar or zip archive' + 'time:run command and display elapsed time' + 'touch:touch a ' + 'touch_nocreate:touch a but do not create it' + 'create_symlink:create a symbolic link new -> old' + 'create_hardlink:create a hard link new -> old' + 'true:do nothing with an exit code of 0' + 'false:do nothing with an exit code of 1' + ) + _describe -t commands 'command' commands } + local cmake_suggest_build;cmake_suggest_build=( '--build[build]:build dir:_cmake_suggest_builddirs' ) @@ -573,21 +615,17 @@ elif [ $CURRENT -eq 2 ] ; then - help \ "$cmake_help_actions[@]" \ - command \ - '-E[CMake command mode]:command:( )' \ + '-E[CMake command mode]:command:_cmake_commands' \ - build_opts \ "$cmake_build_options[@]" \ - build_cmds \ "$cmake_suggest_build[@]" \ - install_cmds \ "$cmake_suggest_install[@]" && return 0 -elif [[ $words[2] = --help* ]] ; then - _cmake_help elif [[ $words[2] == --build ]] ; then _cmake_on_build elif [[ $words[2] == --install ]] ; then _cmake_on_install -elif [[ $words[2] == -E ]]; then - _cmake_command else _arguments "$cmake_build_options[@]" fi