mirror of
https://github.com/go-task/task.git
synced 2026-07-10 04:22:03 +02:00
Add completion/tests/ harnesses that exercise the engine protocol and every shell wrapper without a TTY: the engine via `task __complete`, bash/zsh by stubbing the completion-system helpers, fish via `complete -C`, and PowerShell via the completion API. A `test:completion` task and a matching CI job (with a strict mode that fails when an expected shell is missing) run them all. Writing the suite surfaced and fixed real wrapper bugs: - fish: `math` has no bitwise `&`, so every directive check errored; test bits with integer division + modulo instead. Also filter FilterFileExt results ourselves, as __fish_complete_suffix only prioritizes the extension. - powershell: `Get-ChildItem -Include` is ignored without -Recurse, so file extension filtering returned nothing; filter with Where-Object instead. - bash: guard empty-array expansion so completion with zero candidates does not trip `set -u` on bash 3.2. Also name the completion directive bits (NO_SPACE, FILTER_FILE_EXT, …) in every wrapper instead of using raw numbers.
82 lines
2.0 KiB
Bash
82 lines
2.0 KiB
Bash
# vim: set tabstop=2 shiftwidth=2 expandtab:
|
|
#
|
|
# 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 cur prev words cword
|
|
|
|
# Completion directives, mirroring internal/complete/complete.go.
|
|
local -ri NO_SPACE=2 NO_FILE_COMP=4 FILTER_FILE_EXT=8 FILTER_DIRS=16
|
|
|
|
# Exclude both `=` and `:` from the word breaks so `--output=` and
|
|
# `docs:serve` reach the engine as single tokens.
|
|
_init_completion -n =: || return
|
|
|
|
local -a args=()
|
|
if (( cword > 0 )); then
|
|
args=( "${words[@]:1:cword}" )
|
|
fi
|
|
if (( ${#args[@]} == 0 )); then
|
|
args=( "" )
|
|
fi
|
|
|
|
local output
|
|
output=$("$TASK_CMD" __complete "${args[@]}" 2>/dev/null)
|
|
if [[ -z "$output" ]]; then
|
|
_filedir
|
|
return
|
|
fi
|
|
|
|
local -a lines=()
|
|
local line
|
|
while IFS= read -r line; do
|
|
lines+=( "$line" )
|
|
done <<< "$output"
|
|
|
|
local last_idx=$(( ${#lines[@]} - 1 ))
|
|
local directive="${lines[$last_idx]#:}"
|
|
unset 'lines[$last_idx]'
|
|
|
|
if (( directive & FILTER_FILE_EXT )); then
|
|
local exts=""
|
|
# ${arr[@]+…} guards against "unbound variable" on an empty array under
|
|
# `set -u` in bash 3.2 (macOS).
|
|
for line in ${lines[@]+"${lines[@]}"}; do
|
|
exts+="${exts:+|}$line"
|
|
done
|
|
_filedir "@($exts)"
|
|
return
|
|
fi
|
|
|
|
if (( directive & FILTER_DIRS )); then
|
|
_filedir -d
|
|
return
|
|
fi
|
|
|
|
# Prefix-filter by hand instead of `compgen -W`: the latter joins/splits the
|
|
# word list on IFS, which mangles any suggestion value containing a space.
|
|
local value
|
|
COMPREPLY=()
|
|
for line in ${lines[@]+"${lines[@]}"}; do
|
|
value="${line%%$'\t'*}"
|
|
if [[ -z "$cur" || "$value" == "$cur"* ]]; then
|
|
COMPREPLY+=( "$value" )
|
|
fi
|
|
done
|
|
|
|
if (( directive & NO_SPACE )); then
|
|
compopt -o nospace 2>/dev/null
|
|
fi
|
|
|
|
__ltrim_colon_completions "$cur"
|
|
|
|
if (( ${#COMPREPLY[@]} == 0 )) && ! (( directive & NO_FILE_COMP )); then
|
|
_filedir
|
|
fi
|
|
}
|
|
|
|
complete -F _task "$TASK_CMD"
|