From 020b714faaa5cd536f093454738e2a48d2a5f164 Mon Sep 17 00:00:00 2001 From: Armin Richard Veres Date: Thu, 11 Jun 2026 16:35:03 +0200 Subject: [PATCH] feat: add support for build-presets When running `cmake --build --preset=*` the preset would not complete. Additionally fix `cmake --build --preset=* --target=*` target completion too, by looking for the first CMakeCache.txt in five levels of directories. --- src/_cmake | 53 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/src/_cmake b/src/_cmake index 4284b17..b8dba4e 100644 --- a/src/_cmake +++ b/src/_cmake @@ -144,6 +144,29 @@ _cmake_generator_options() { fi } +# ---------------------- +# _cmake_build_presets +# ---------------------- +(( $+functions[_cmake_build_presets] )) || +_cmake_build_presets() { + local list_presets=(${(f)"$(cmake --list-presets=build 2>/dev/null | + sed -n -e 's,^[[:space:]]*"\([^"]*\)"[[:space:]]*-[[:space:]]*\(.*\),\1:\2,p' \ + -e 's,^[[:space:]]*"\([^"]*\)"[[:space:]]*$,\1,p')"}) + + _describe 'build presets' list_presets +} + +# -------------------------- +# _cmake_preset_build_dir +# +# Finds the build directory by locating the nearest CMakeCache.txt. +# -------------------------- +(( $+functions[_cmake_preset_build_dir] )) || +_cmake_preset_build_dir() { + find . -maxdepth 5 -name CMakeCache.txt -print -quit | xargs -I{} dirname {} +} + + # -------------- # _cmake_presets # -------------- @@ -194,6 +217,8 @@ _cmake_on_build() { '--config[For multi-configuration tools]' '--parallel[maximum number of build processes]' '--use-stderr' + '--preset[Specify a build preset]:preset:_cmake_build_presets' + '--list-presets[List available build presets]' ) local -a undescribed_build_extras local i=1 @@ -226,23 +251,41 @@ _cmake_on_build() { if [[ $words[(($i - 1))] == --target ]]; then continue ; fi if [[ $words[(($i - 1))] == --config ]]; then continue ; fi if [[ $words[(($i - 1))] == --parallel ]] ; then continue ; fi + if [[ $words[(($i - 1))] == --preset ]] ; then continue ; fi out_of_build=true done if (( $dash_dash_position > 0 )) ; then - _cmake_generator_options $words[(($build_at + 1))] $dash_dash_position && return 0 + local _build_first=$words[(($build_at + 1))] + [[ $_build_first != --* ]] && _cmake_generator_options $_build_first $dash_dash_position && return 0 fi - if [[ "$in_build" == false || "$difference" -eq 1 ]] ; then - # either there is no --build or completing the directory after --build + if [[ "$in_build" == false ]] ; then + # no --build seen, complete normally _arguments -s \ - build_opts \ "$cmake_build_options[@]" \ - build_cmds \ "$cmake_suggest_build[@]" && return 0 + elif [[ "$difference" -eq 1 ]] ; then + # completing first arg after --build: dir, --preset, or --list-presets + _alternative \ + ':current directory:(.)' \ + 'directory::_directories' \ + 'preset-flags:flag:((--preset\:"Specify a build preset" --list-presets\:"List available build presets"))' && return 0 + elif [[ $words[(($CURRENT - 1))] == --preset ]] ; then + # after --build --preset, complete build presets + _cmake_build_presets && return 0 elif [[ $words[(($CURRENT - 1))] == --target ]] ; then - # after --build --target, suggest targets - _cmake_targets $words[(($build_at + 1))] && return 0 + # after --build --target, suggest targets + local _tgt_first=$words[(($build_at + 1))] + if [[ $_tgt_first == --preset ]]; then + local _tgt_dir=$(_cmake_preset_build_dir "$words[(($build_at + 2))]") + [[ -n "$_tgt_dir" ]] && _cmake_targets "$_tgt_dir" + elif [[ $_tgt_first != --* ]]; then + _cmake_targets "$_tgt_first" + fi + return 0 elif [[ $words[(($CURRENT - 1))] == --config ]] ; then # after --build --config, no idea return 0