mirror of
https://github.com/go-task/task.git
synced 2026-09-02 04:02:08 +02:00
Bash, Fish, Zsh, Nushell and PowerShell now share a single backend: `task __complete` returns the suggestions plus a directive, and every wrapper is a thin shim around it. All five shells offer the same suggestions — task names, aliases, flags, flag values and per-task CLI variables. The Zsh `show-aliases` and `verbose` zstyles keep working, now backed by the `--no-aliases` and `--no-descriptions` completion flags. The engine is opt-in via `task --new-completion <shell>`, leaving `--completion` and the legacy scripts untouched; it will become the default in a future release. The new wrappers live under `completion/next/`. Completing a keystroke never reaches the network, never blocks on a stdin entrypoint, and honors every flag that decides how the Taskfile is loaded. Ref resolution shared by `requires` and enum completion moved to `internal/refs`. A cross-shell test suite exercises the protocol in Go with thin shell smoke tests, and runs in CI.
71 lines
1.8 KiB
Go
71 lines
1.8 KiB
Go
package complete
|
|
|
|
import (
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/spf13/pflag"
|
|
)
|
|
|
|
// TestCompletionShells keeps this in step with the scripts the root package serves.
|
|
var completionShells = []string{"bash", "zsh", "fish", "powershell", "nu"}
|
|
|
|
// Keep in sync with the help strings in internal/flags/flags.go.
|
|
var flagEnums = map[string][]string{
|
|
"output": {"interleaved", "group", "prefixed"},
|
|
"sort": {"default", "alphanumeric", "none"},
|
|
"completion": completionShells,
|
|
"new-completion": completionShells,
|
|
}
|
|
|
|
// A flag absent here falls back to the shell's default file completion.
|
|
var flagDirective = map[string]Directive{
|
|
"taskfile": DirectiveFilterFileExt,
|
|
"dir": DirectiveFilterDirs,
|
|
"remote-cache-dir": DirectiveFilterDirs,
|
|
}
|
|
|
|
var taskfileExtensions = []string{"yml", "yaml"}
|
|
|
|
func flagTakesValue(f *pflag.Flag) bool {
|
|
return f.NoOptDefVal == ""
|
|
}
|
|
|
|
// Walks fs at call time so experiment-gated flags follow the active experiments.
|
|
func listFlags(fs *pflag.FlagSet) []Suggestion {
|
|
if fs == nil {
|
|
return nil
|
|
}
|
|
out := make([]Suggestion, 0, 64)
|
|
fs.VisitAll(func(f *pflag.Flag) {
|
|
if f.Hidden || f.Deprecated != "" {
|
|
return
|
|
}
|
|
out = append(out, Suggestion{
|
|
Value: "--" + f.Name,
|
|
Description: f.Usage,
|
|
})
|
|
if f.Shorthand != "" {
|
|
out = append(out, Suggestion{
|
|
Value: "-" + f.Shorthand,
|
|
Description: f.Usage,
|
|
})
|
|
}
|
|
})
|
|
slices.SortFunc(out, func(a, b Suggestion) int { return strings.Compare(a.Value, b.Value) })
|
|
return out
|
|
}
|
|
|
|
func matchFlagName(fs *pflag.FlagSet, word string) *pflag.Flag {
|
|
if fs == nil {
|
|
return nil
|
|
}
|
|
switch {
|
|
case strings.HasPrefix(word, "--"):
|
|
return fs.Lookup(strings.TrimPrefix(word, "--"))
|
|
case strings.HasPrefix(word, "-") && len(word) == 2:
|
|
return fs.ShorthandLookup(word[1:])
|
|
}
|
|
return nil
|
|
}
|