mirror of
https://github.com/go-task/task.git
synced 2025-12-16 11:47:44 +01:00
refactor: optimize fuzzy matching with lazy initialization (#2523)
This commit is contained in:
@@ -17,6 +17,9 @@
|
|||||||
@vmaerten).
|
@vmaerten).
|
||||||
- Improved shell completion scripts (Zsh, Fish, PowerShell) by adding missing
|
- Improved shell completion scripts (Zsh, Fish, PowerShell) by adding missing
|
||||||
flags and dynamic experimental feature detection (#2532 by @vmaerten).
|
flags and dynamic experimental feature detection (#2532 by @vmaerten).
|
||||||
|
- Improved performance of fuzzy task name matching by implementing lazy
|
||||||
|
initialization. Added `--disable-fuzzy` flag and `disable-fuzzy` taskrc option
|
||||||
|
to allow disabling fuzzy matching entirely (#2521, #2523 by @vmaerten).
|
||||||
- Added LLM-optimized documentation via VitePress plugin, generating `llms.txt`
|
- Added LLM-optimized documentation via VitePress plugin, generating `llms.txt`
|
||||||
and `llms-full.txt` for AI-powered development tools (#2513 by @vmaerten).
|
and `llms-full.txt` for AI-powered development tools (#2513 by @vmaerten).
|
||||||
- Fixed Zsh and Fish completions to stop suggesting task names after `--`
|
- Fixed Zsh and Fish completions to stop suggesting task names after `--`
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ complete -c $GO_TASK_PROGNAME -s c -l color -d 'colored outp
|
|||||||
complete -c $GO_TASK_PROGNAME -s C -l concurrency -d 'limit number of concurrent tasks'
|
complete -c $GO_TASK_PROGNAME -s C -l concurrency -d 'limit number of concurrent tasks'
|
||||||
complete -c $GO_TASK_PROGNAME -l completion -d 'generate shell completion script' -xa "bash zsh fish powershell"
|
complete -c $GO_TASK_PROGNAME -l completion -d 'generate shell completion script' -xa "bash zsh fish powershell"
|
||||||
complete -c $GO_TASK_PROGNAME -s d -l dir -d 'set directory of execution'
|
complete -c $GO_TASK_PROGNAME -s d -l dir -d 'set directory of execution'
|
||||||
|
complete -c $GO_TASK_PROGNAME -l disable-fuzzy -d 'disable fuzzy matching for task names'
|
||||||
complete -c $GO_TASK_PROGNAME -s n -l dry -d 'compile and print tasks without executing'
|
complete -c $GO_TASK_PROGNAME -s n -l dry -d 'compile and print tasks without executing'
|
||||||
complete -c $GO_TASK_PROGNAME -s x -l exit-code -d 'pass-through exit code of task command'
|
complete -c $GO_TASK_PROGNAME -s x -l exit-code -d 'pass-through exit code of task command'
|
||||||
complete -c $GO_TASK_PROGNAME -l experiments -d 'list available experiments'
|
complete -c $GO_TASK_PROGNAME -l experiments -d 'list available experiments'
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ Register-ArgumentCompleter -CommandName task -ScriptBlock {
|
|||||||
[CompletionResult]::new('--completion', '--completion', [CompletionResultType]::ParameterName, 'generate shell completion'),
|
[CompletionResult]::new('--completion', '--completion', [CompletionResultType]::ParameterName, 'generate shell completion'),
|
||||||
[CompletionResult]::new('-d', '-d', [CompletionResultType]::ParameterName, 'set directory'),
|
[CompletionResult]::new('-d', '-d', [CompletionResultType]::ParameterName, 'set directory'),
|
||||||
[CompletionResult]::new('--dir', '--dir', [CompletionResultType]::ParameterName, 'set directory'),
|
[CompletionResult]::new('--dir', '--dir', [CompletionResultType]::ParameterName, 'set directory'),
|
||||||
|
[CompletionResult]::new('--disable-fuzzy', '--disable-fuzzy', [CompletionResultType]::ParameterName, 'disable fuzzy matching'),
|
||||||
[CompletionResult]::new('-n', '-n', [CompletionResultType]::ParameterName, 'dry run'),
|
[CompletionResult]::new('-n', '-n', [CompletionResultType]::ParameterName, 'dry run'),
|
||||||
[CompletionResult]::new('--dry', '--dry', [CompletionResultType]::ParameterName, 'dry run'),
|
[CompletionResult]::new('--dry', '--dry', [CompletionResultType]::ParameterName, 'dry run'),
|
||||||
[CompletionResult]::new('-x', '-x', [CompletionResultType]::ParameterName, 'pass-through exit code'),
|
[CompletionResult]::new('-x', '-x', [CompletionResultType]::ParameterName, 'pass-through exit code'),
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ _task() {
|
|||||||
'(-c --color)'{-c,--color}'[colored output]'
|
'(-c --color)'{-c,--color}'[colored output]'
|
||||||
'(--completion)--completion[generate shell completion script]:shell:(bash zsh fish powershell)'
|
'(--completion)--completion[generate shell completion script]:shell:(bash zsh fish powershell)'
|
||||||
'(-d --dir)'{-d,--dir}'[dir to run in]:execution dir:_dirs'
|
'(-d --dir)'{-d,--dir}'[dir to run in]:execution dir:_dirs'
|
||||||
|
'(--disable-fuzzy)--disable-fuzzy[disable fuzzy matching for task names]'
|
||||||
'(-n --dry)'{-n,--dry}'[compiles and prints tasks without executing]'
|
'(-n --dry)'{-n,--dry}'[compiles and prints tasks without executing]'
|
||||||
'(--dry)--dry[dry-run mode, compile and print tasks only]'
|
'(--dry)--dry[dry-run mode, compile and print tasks only]'
|
||||||
'(-x --exit-code)'{-x,--exit-code}'[pass-through exit code of task command]'
|
'(-x --exit-code)'{-x,--exit-code}'[pass-through exit code of task command]'
|
||||||
|
|||||||
17
executor.go
17
executor.go
@@ -40,6 +40,7 @@ type (
|
|||||||
Watch bool
|
Watch bool
|
||||||
Verbose bool
|
Verbose bool
|
||||||
Silent bool
|
Silent bool
|
||||||
|
DisableFuzzy bool
|
||||||
AssumeYes bool
|
AssumeYes bool
|
||||||
AssumeTerm bool // Used for testing
|
AssumeTerm bool // Used for testing
|
||||||
Dry bool
|
Dry bool
|
||||||
@@ -65,7 +66,8 @@ type (
|
|||||||
UserWorkingDir string
|
UserWorkingDir string
|
||||||
EnableVersionCheck bool
|
EnableVersionCheck bool
|
||||||
|
|
||||||
fuzzyModel *fuzzy.Model
|
fuzzyModel *fuzzy.Model
|
||||||
|
fuzzyModelOnce sync.Once
|
||||||
|
|
||||||
concurrencySemaphore chan struct{}
|
concurrencySemaphore chan struct{}
|
||||||
taskCallCount map[string]*int32
|
taskCallCount map[string]*int32
|
||||||
@@ -312,6 +314,19 @@ func (o *silentOption) ApplyToExecutor(e *Executor) {
|
|||||||
e.Silent = o.silent
|
e.Silent = o.silent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithDisableFuzzy tells the [Executor] to disable fuzzy matching for task names.
|
||||||
|
func WithDisableFuzzy(disableFuzzy bool) ExecutorOption {
|
||||||
|
return &disableFuzzyOption{disableFuzzy}
|
||||||
|
}
|
||||||
|
|
||||||
|
type disableFuzzyOption struct {
|
||||||
|
disableFuzzy bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *disableFuzzyOption) ApplyToExecutor(e *Executor) {
|
||||||
|
e.DisableFuzzy = o.disableFuzzy
|
||||||
|
}
|
||||||
|
|
||||||
// WithAssumeYes tells the [Executor] to assume "yes" for all prompts.
|
// WithAssumeYes tells the [Executor] to assume "yes" for all prompts.
|
||||||
func WithAssumeYes(assumeYes bool) ExecutorOption {
|
func WithAssumeYes(assumeYes bool) ExecutorOption {
|
||||||
return &assumeYesOption{assumeYes}
|
return &assumeYesOption{assumeYes}
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ var (
|
|||||||
Watch bool
|
Watch bool
|
||||||
Verbose bool
|
Verbose bool
|
||||||
Silent bool
|
Silent bool
|
||||||
|
DisableFuzzy bool
|
||||||
AssumeYes bool
|
AssumeYes bool
|
||||||
Dry bool
|
Dry bool
|
||||||
Summary bool
|
Summary bool
|
||||||
@@ -125,6 +126,7 @@ func init() {
|
|||||||
pflag.BoolVarP(&Watch, "watch", "w", false, "Enables watch of the given task.")
|
pflag.BoolVarP(&Watch, "watch", "w", false, "Enables watch of the given task.")
|
||||||
pflag.BoolVarP(&Verbose, "verbose", "v", getConfig(config, func() *bool { return config.Verbose }, false), "Enables verbose mode.")
|
pflag.BoolVarP(&Verbose, "verbose", "v", getConfig(config, func() *bool { return config.Verbose }, false), "Enables verbose mode.")
|
||||||
pflag.BoolVarP(&Silent, "silent", "s", false, "Disables echoing.")
|
pflag.BoolVarP(&Silent, "silent", "s", false, "Disables echoing.")
|
||||||
|
pflag.BoolVar(&DisableFuzzy, "disable-fuzzy", getConfig(config, func() *bool { return config.DisableFuzzy }, false), "Disables fuzzy matching for task names.")
|
||||||
pflag.BoolVarP(&AssumeYes, "yes", "y", false, "Assume \"yes\" as answer to all prompts.")
|
pflag.BoolVarP(&AssumeYes, "yes", "y", false, "Assume \"yes\" as answer to all prompts.")
|
||||||
pflag.BoolVarP(&Parallel, "parallel", "p", false, "Executes tasks provided on command line in parallel.")
|
pflag.BoolVarP(&Parallel, "parallel", "p", false, "Executes tasks provided on command line in parallel.")
|
||||||
pflag.BoolVarP(&Dry, "dry", "n", false, "Compiles and prints tasks in the order that they would be run, without executing them.")
|
pflag.BoolVarP(&Dry, "dry", "n", false, "Compiles and prints tasks in the order that they would be run, without executing them.")
|
||||||
@@ -248,6 +250,7 @@ func (o *flagsOption) ApplyToExecutor(e *task.Executor) {
|
|||||||
task.WithWatch(Watch),
|
task.WithWatch(Watch),
|
||||||
task.WithVerbose(Verbose),
|
task.WithVerbose(Verbose),
|
||||||
task.WithSilent(Silent),
|
task.WithSilent(Silent),
|
||||||
|
task.WithDisableFuzzy(DisableFuzzy),
|
||||||
task.WithAssumeYes(AssumeYes),
|
task.WithAssumeYes(AssumeYes),
|
||||||
task.WithDry(Dry || Status),
|
task.WithDry(Dry || Status),
|
||||||
task.WithSummary(Summary),
|
task.WithSummary(Summary),
|
||||||
|
|||||||
1
setup.go
1
setup.go
@@ -36,7 +36,6 @@ func (e *Executor) Setup() error {
|
|||||||
if err := e.readTaskfile(node); err != nil {
|
if err := e.readTaskfile(node); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
e.setupFuzzyModel()
|
|
||||||
e.setupStdFiles()
|
e.setupStdFiles()
|
||||||
if err := e.setupOutput(); err != nil {
|
if err := e.setupOutput(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
7
task.go
7
task.go
@@ -456,8 +456,11 @@ func (e *Executor) GetTask(call *Call) (*ast.Task, error) {
|
|||||||
// If we found no tasks
|
// If we found no tasks
|
||||||
if len(aliasedTasks) == 0 {
|
if len(aliasedTasks) == 0 {
|
||||||
didYouMean := ""
|
didYouMean := ""
|
||||||
if e.fuzzyModel != nil {
|
if !e.DisableFuzzy {
|
||||||
didYouMean = e.fuzzyModel.SpellCheck(call.Task)
|
e.fuzzyModelOnce.Do(e.setupFuzzyModel)
|
||||||
|
if e.fuzzyModel != nil {
|
||||||
|
didYouMean = e.fuzzyModel.SpellCheck(call.Task)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil, &errors.TaskNotFoundError{
|
return nil, &errors.TaskNotFoundError{
|
||||||
TaskName: call.Task,
|
TaskName: call.Task,
|
||||||
|
|||||||
@@ -10,12 +10,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type TaskRC struct {
|
type TaskRC struct {
|
||||||
Version *semver.Version `yaml:"version"`
|
Version *semver.Version `yaml:"version"`
|
||||||
Verbose *bool `yaml:"verbose"`
|
Verbose *bool `yaml:"verbose"`
|
||||||
Concurrency *int `yaml:"concurrency"`
|
DisableFuzzy *bool `yaml:"disable-fuzzy"`
|
||||||
Remote Remote `yaml:"remote"`
|
Concurrency *int `yaml:"concurrency"`
|
||||||
Experiments map[string]int `yaml:"experiments"`
|
Remote Remote `yaml:"remote"`
|
||||||
Failfast bool `yaml:"failfast"`
|
Failfast bool `yaml:"failfast"`
|
||||||
|
Experiments map[string]int `yaml:"experiments"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Remote struct {
|
type Remote struct {
|
||||||
@@ -53,6 +54,7 @@ func (t *TaskRC) Merge(other *TaskRC) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t.Verbose = cmp.Or(other.Verbose, t.Verbose)
|
t.Verbose = cmp.Or(other.Verbose, t.Verbose)
|
||||||
|
t.DisableFuzzy = cmp.Or(other.DisableFuzzy, t.DisableFuzzy)
|
||||||
t.Concurrency = cmp.Or(other.Concurrency, t.Concurrency)
|
t.Concurrency = cmp.Or(other.Concurrency, t.Concurrency)
|
||||||
t.Failfast = cmp.Or(other.Failfast, t.Failfast)
|
t.Failfast = cmp.Or(other.Failfast, t.Failfast)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,16 @@ Disable command echoing.
|
|||||||
task deploy --silent
|
task deploy --silent
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `--disable-fuzzy`
|
||||||
|
|
||||||
|
Disable fuzzy matching for task names. When enabled, Task will not suggest similar task names when you mistype a task name.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
task buidl --disable-fuzzy
|
||||||
|
# Output: Task "buidl" does not exist
|
||||||
|
# (without "Did you mean 'build'?" suggestion)
|
||||||
|
```
|
||||||
|
|
||||||
### Execution Control
|
### Execution Control
|
||||||
|
|
||||||
#### `-F, --failfast`
|
#### `-F, --failfast`
|
||||||
|
|||||||
@@ -91,6 +91,17 @@ experiments:
|
|||||||
verbose: true
|
verbose: true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `disable-fuzzy`
|
||||||
|
|
||||||
|
- **Type**: `boolean`
|
||||||
|
- **Default**: `false`
|
||||||
|
- **Description**: Disable fuzzy matching for task names. When enabled, Task will not suggest similar task names when you mistype a task name.
|
||||||
|
- **CLI equivalent**: [`--disable-fuzzy`](./cli.md#--disable-fuzzy)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
disable-fuzzy: true
|
||||||
|
```
|
||||||
|
|
||||||
### `concurrency`
|
### `concurrency`
|
||||||
|
|
||||||
- **Type**: `integer`
|
- **Type**: `integer`
|
||||||
@@ -120,6 +131,7 @@ Here's a complete example of a `.taskrc.yml` file with all available options:
|
|||||||
```yaml
|
```yaml
|
||||||
# Global settings
|
# Global settings
|
||||||
verbose: true
|
verbose: true
|
||||||
|
disable-fuzzy: false
|
||||||
concurrency: 2
|
concurrency: 2
|
||||||
|
|
||||||
# Enable experimental features
|
# Enable experimental features
|
||||||
|
|||||||
@@ -57,6 +57,10 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Enable verbose output"
|
"description": "Enable verbose output"
|
||||||
},
|
},
|
||||||
|
"disable-fuzzy": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Disable fuzzy matching for task names"
|
||||||
|
},
|
||||||
"concurrency": {
|
"concurrency": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "Number of concurrent tasks to run",
|
"description": "Number of concurrent tasks to run",
|
||||||
|
|||||||
Reference in New Issue
Block a user