Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ title: Changelog
* `[Refactoring]` Use Go 1.26 `errors.AsType` for type-safe error unwrapping.
* `[Testing]` Add golden-file tests for help and error rendering in `internal/cmd`, replacing bats format checks with snapshot comparisons.
* `[Added]` Add a `theme` user setting with `default`, `ansi`, and `synthwave` themes for lets help and styled error output.
* `[Fixed]` zsh completion now handles root flags before command names, including `-c/--config`, and no longer emits `command -c not declared in config` while completing commands.

## [0.0.61](https://github.com/lets-cli/lets/releases/tag/v0.0.61)

Expand Down
96 changes: 87 additions & 9 deletions internal/cmd/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,17 @@ const zshCompletionText = `#compdef lets
LETS_EXECUTABLE=lets

function _lets {
local state
local state

_arguments -C -s \
"(-c --config)"{-c,--config}"[config file (default is lets.yaml)]:config file:_files" \
"(-E --env)"{-E,--env}"[set env variable KEY=VALUE]:env var:" \
"--only[run only specified command(s)]:command:" \
"--exclude[run all but excluded command(s)]:command:" \
"(-d --debug -dd)"{-d,--debug}"[show debug logs]" \
"-dd[show very verbose debug logs]" \
"--all[show all commands]" \
"--init[create lets.yaml in current folder]" \
"1: :->cmds" \
'*::arg:->args'

Expand All @@ -29,22 +37,86 @@ function _lets {
_lets_commands
;;
args)
_lets_command_options "${words[1]}"
local cmd=$(_lets_active_command)
_lets_command_options "${cmd}"
;;
esac
}

# Check if in folder with correct lets.yaml file
_check_lets_config() {
${LETS_EXECUTABLE} 1>/dev/null 2>/dev/null
${LETS_EXECUTABLE} "$@" 1>/dev/null 2>/dev/null
echo $?
}

_lets_root_flags_before_command() {
local idx=1
local -a prefix=()

while [ $idx -lt $CURRENT ]; do
local token="${words[$idx]}"

case "$token" in
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
Outdated
-c|--config|-E|--env|--only|--exclude)
prefix+=("$token")
((idx++))
if [ $idx -lt $CURRENT ]; then
prefix+=("${words[$idx]}")
fi
;;
--config=*|--env=*|--only=*|--exclude=*|-E*)
prefix+=("$token")
;;
-d|-dd|--debug|--all|--init)
prefix+=("$token")
;;
--)
break
;;
-*)
prefix+=("$token")
;;
*)
break
;;
esac

((idx++))
done

reply=("${prefix[@]}")
}

_lets_active_command() {
local idx=1

while [ $idx -le $#words ]; do
local token="${words[$idx]}"

case "$token" in
-c|--config|-E|--env|--only|--exclude)
((idx++))
;;
--config=*|--env=*|--only=*|--exclude=*|-E*|-d|-dd|--debug|--all|--init|--)
;;
-*)
;;
*)
echo "$token"
return
;;
esac

((idx++))
done
}

_lets_commands () {
local cmds
_lets_root_flags_before_command
local -a root_flags=("${reply[@]}")

if [ $(_check_lets_config) -eq 0 ]; then
IFS=$'\n' cmds=($(${LETS_EXECUTABLE} completion --commands --verbose))
if [ $(_check_lets_config "${root_flags[@]}") -eq 0 ]; then
IFS=$'\n' cmds=($(${LETS_EXECUTABLE} "${root_flags[@]}" completion --commands --verbose 2>/dev/null))
else
cmds=()
fi
Expand All @@ -53,15 +125,21 @@ _lets_commands () {

_lets_command_options () {
local cmd=$1
_lets_root_flags_before_command
local -a root_flags=("${reply[@]}")

if [[ -z "$cmd" || "$cmd" == -* ]]; then
return 0
fi

if [ $(_check_lets_config) -eq 0 ]; then
if [ $(_check_lets_config "${root_flags[@]}") -eq 0 ]; then
IFS=$'\n'
_arguments -s $(${LETS_EXECUTABLE} completion --options=${cmd} --verbose)
_arguments -s $(${LETS_EXECUTABLE} "${root_flags[@]}" completion --options=${cmd} --verbose 2>/dev/null)
fi
}

if ! command -v compinit >/dev/null; then
autoload -U compinit && compinit
autoload -U compinit && compinit
fi

compdef _lets lets
Expand Down
Loading