mirror of
https://github.com/go-task/task.git
synced 2026-07-09 20:09:14 +02:00
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.
81 lines
1.7 KiB
Go
81 lines
1.7 KiB
Go
package complete
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/spf13/pflag"
|
|
)
|
|
|
|
type completionContext struct {
|
|
toComplete string
|
|
prev string
|
|
afterDash bool
|
|
}
|
|
|
|
// parseContext infers the cursor position from args alone. It deliberately
|
|
// avoids the task list so flag completion never pays to load it; the task word
|
|
// is resolved separately by detectTaskName only once a task context is reached.
|
|
func parseContext(args []string) completionContext {
|
|
ctx := completionContext{}
|
|
if len(args) == 0 {
|
|
return ctx
|
|
}
|
|
|
|
ctx.toComplete = args[len(args)-1]
|
|
if len(args) >= 2 {
|
|
ctx.prev = args[len(args)-2]
|
|
}
|
|
|
|
for _, w := range args[:len(args)-1] {
|
|
if w == "--" {
|
|
ctx.afterDash = true
|
|
return ctx
|
|
}
|
|
}
|
|
|
|
return ctx
|
|
}
|
|
|
|
// detectTaskName scans args for the task word the cursor is completing under
|
|
// (e.g. "deploy" in `task deploy ENV=<tab>`). fs is needed to skip the word
|
|
// following a value-taking flag, otherwise `task --dir deploy` would mistake
|
|
// "deploy" (the directory) for a task name.
|
|
func detectTaskName(args []string, knownTasks []string, fs *pflag.FlagSet) string {
|
|
if len(args) <= 1 {
|
|
return ""
|
|
}
|
|
|
|
known := make(map[string]struct{}, len(knownTasks))
|
|
for _, t := range knownTasks {
|
|
known[t] = struct{}{}
|
|
}
|
|
|
|
taskName := ""
|
|
skipNext := false
|
|
for _, w := range args[:len(args)-1] {
|
|
if skipNext {
|
|
skipNext = false
|
|
continue
|
|
}
|
|
if w == "--" {
|
|
return taskName
|
|
}
|
|
if strings.HasPrefix(w, "-") {
|
|
if !strings.Contains(w, "=") {
|
|
if f := matchFlagName(fs, w); f != nil && flagTakesValue(f) {
|
|
skipNext = true
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
if strings.Contains(w, "=") {
|
|
continue
|
|
}
|
|
if _, ok := known[w]; ok {
|
|
taskName = w
|
|
}
|
|
}
|
|
|
|
return taskName
|
|
}
|