Files
task/completion/zsh/_task
Valentin Maerten 57bc6dd8cb fix(completion): harden the __complete engine and shell wrappers
Engine:
- Emit DirectiveKeepOrder for task variables so the `requires` declaration
  order is preserved instead of being sorted by the shell.
- Return full `--flag=value` candidates for the inline `--output=` form so all
  shells match against the whole current token.
- Add `--no-aliases` / `--no-descriptions` completion flags (via complete.Options)
  parsed from the __complete invocation; the zsh wrapper maps its show-aliases
  and verbose zstyles onto them.
- Skip Taskfile setup when completing flags (NeedsTaskfile) and load the task
  list lazily; drop unused parameters; document exported identifiers.

Shell wrappers:
- zsh: reindent to tabs (.editorconfig), bridge zstyles to engine flags.
- fish: reindent to 2 spaces, handle every file-completion directive in the
  wrapper (--no-files disables the native fallback), drop the duplicated
  yml/yaml extension list now that it lives only in the engine.
- bash: prefix-filter by hand to preserve values containing spaces, exclude `=`
  from word breaks so `--output=` reaches the engine as one token.
- powershell: filter candidates by the current word, fall back to file
  completion for DirectiveDefault.

NoSpace is not representable in fish/PowerShell completion APIs; documented in
the wrappers.
2026-07-03 16:03:33 +02:00

72 lines
1.8 KiB
Plaintext
Executable File

#compdef task
#
# Thin wrapper around `task __complete`. All suggestion logic lives in the
# Go engine — do not add completion logic here.
TASK_CMD="${TASK_EXE:-task}"
_task() {
local -a args lines completions opts ctl
local output directive line
# Map the zsh completion zstyles to engine flags. `-T` is true when the
# style is unset (its default) or explicitly true, so a flag is only passed
# when the user turned the style off.
zstyle -T ":completion:${curcontext}:" show-aliases || ctl+=(--no-aliases)
zstyle -T ":completion:${curcontext}:" verbose || ctl+=(--no-descriptions)
# (@) preserves a trailing empty string, which the engine relies on to
# know the cursor is on a fresh word.
args=("${(@)words[2,CURRENT]}")
(( ${#args} == 0 )) && args=("")
output=$("$TASK_CMD" __complete "${ctl[@]}" "${args[@]}" 2>/dev/null)
if [[ -z "$output" ]]; then
_files
return
fi
lines=("${(f)output}")
directive="${lines[-1]#:}"
lines=("${(@)lines[1,-2]}")
if (( directive & 8 )); then
local -a globs
for line in "${lines[@]}"; do
globs+=("*.${line}")
done
_files -g "(${(j:|:)globs})"
return
fi
if (( directive & 16 )); then
_path_files -/
return
fi
# `:` inside the value must be escaped: _describe splits on the first
# unescaped colon (e.g. "docs:serve" would otherwise become value "docs").
local value desc
for line in "${lines[@]}"; do
if [[ "$line" == *$'\t'* ]]; then
value="${line%%$'\t'*}"
desc="${line#*$'\t'}"
completions+=("${value//:/\\:}:$desc")
else
completions+=("${line//:/\\:}")
fi
done
(( directive & 2 )) && opts+=(-S '')
(( directive & 32 )) && opts+=(-V)
if (( ${#completions} > 0 )); then
_describe -t tasks 'task' completions "${opts[@]}"
fi
(( directive & 4 )) && return
_files
}
compdef _task "$TASK_CMD"