Skip to content

Commit a40ddd4

Browse files
authored
refactor: optimize fuzzy matching with lazy initialization (#2523)
1 parent b181427 commit a40ddd4

File tree

12 files changed

+64
-10
lines changed

12 files changed

+64
-10
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
@vmaerten).
1818
- Improved shell completion scripts (Zsh, Fish, PowerShell) by adding missing
1919
flags and dynamic experimental feature detection (#2532 by @vmaerten).
20+
- Improved performance of fuzzy task name matching by implementing lazy
21+
initialization. Added `--disable-fuzzy` flag and `disable-fuzzy` taskrc option
22+
to allow disabling fuzzy matching entirely (#2521, #2523 by @vmaerten).
2023
- Added LLM-optimized documentation via VitePress plugin, generating `llms.txt`
2124
and `llms-full.txt` for AI-powered development tools (#2513 by @vmaerten).
2225
- Fixed Zsh and Fish completions to stop suggesting task names after `--`

completion/fish/task.fish

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ complete -c $GO_TASK_PROGNAME -s c -l color -d 'colored outp
7171
complete -c $GO_TASK_PROGNAME -s C -l concurrency -d 'limit number of concurrent tasks'
7272
complete -c $GO_TASK_PROGNAME -l completion -d 'generate shell completion script' -xa "bash zsh fish powershell"
7373
complete -c $GO_TASK_PROGNAME -s d -l dir -d 'set directory of execution'
74+
complete -c $GO_TASK_PROGNAME -l disable-fuzzy -d 'disable fuzzy matching for task names'
7475
complete -c $GO_TASK_PROGNAME -s n -l dry -d 'compile and print tasks without executing'
7576
complete -c $GO_TASK_PROGNAME -s x -l exit-code -d 'pass-through exit code of task command'
7677
complete -c $GO_TASK_PROGNAME -l experiments -d 'list available experiments'

completion/ps/task.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Register-ArgumentCompleter -CommandName task -ScriptBlock {
1515
[CompletionResult]::new('--completion', '--completion', [CompletionResultType]::ParameterName, 'generate shell completion'),
1616
[CompletionResult]::new('-d', '-d', [CompletionResultType]::ParameterName, 'set directory'),
1717
[CompletionResult]::new('--dir', '--dir', [CompletionResultType]::ParameterName, 'set directory'),
18+
[CompletionResult]::new('--disable-fuzzy', '--disable-fuzzy', [CompletionResultType]::ParameterName, 'disable fuzzy matching'),
1819
[CompletionResult]::new('-n', '-n', [CompletionResultType]::ParameterName, 'dry run'),
1920
[CompletionResult]::new('--dry', '--dry', [CompletionResultType]::ParameterName, 'dry run'),
2021
[CompletionResult]::new('-x', '-x', [CompletionResultType]::ParameterName, 'pass-through exit code'),

completion/zsh/_task

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ _task() {
6060
'(-c --color)'{-c,--color}'[colored output]'
6161
'(--completion)--completion[generate shell completion script]:shell:(bash zsh fish powershell)'
6262
'(-d --dir)'{-d,--dir}'[dir to run in]:execution dir:_dirs'
63+
'(--disable-fuzzy)--disable-fuzzy[disable fuzzy matching for task names]'
6364
'(-n --dry)'{-n,--dry}'[compiles and prints tasks without executing]'
6465
'(--dry)--dry[dry-run mode, compile and print tasks only]'
6566
'(-x --exit-code)'{-x,--exit-code}'[pass-through exit code of task command]'

executor.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ type (
4040
Watch bool
4141
Verbose bool
4242
Silent bool
43+
DisableFuzzy bool
4344
AssumeYes bool
4445
AssumeTerm bool // Used for testing
4546
Dry bool
@@ -65,7 +66,8 @@ type (
6566
UserWorkingDir string
6667
EnableVersionCheck bool
6768

68-
fuzzyModel *fuzzy.Model
69+
fuzzyModel *fuzzy.Model
70+
fuzzyModelOnce sync.Once
6971

7072
concurrencySemaphore chan struct{}
7173
taskCallCount map[string]*int32
@@ -312,6 +314,19 @@ func (o *silentOption) ApplyToExecutor(e *Executor) {
312314
e.Silent = o.silent
313315
}
314316

317+
// WithDisableFuzzy tells the [Executor] to disable fuzzy matching for task names.
318+
func WithDisableFuzzy(disableFuzzy bool) ExecutorOption {
319+
return &disableFuzzyOption{disableFuzzy}
320+
}
321+
322+
type disableFuzzyOption struct {
323+
disableFuzzy bool
324+
}
325+
326+
func (o *disableFuzzyOption) ApplyToExecutor(e *Executor) {
327+
e.DisableFuzzy = o.disableFuzzy
328+
}
329+
315330
// WithAssumeYes tells the [Executor] to assume "yes" for all prompts.
316331
func WithAssumeYes(assumeYes bool) ExecutorOption {
317332
return &assumeYesOption{assumeYes}

internal/flags/flags.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ var (
5858
Watch bool
5959
Verbose bool
6060
Silent bool
61+
DisableFuzzy bool
6162
AssumeYes bool
6263
Dry bool
6364
Summary bool
@@ -125,6 +126,7 @@ func init() {
125126
pflag.BoolVarP(&Watch, "watch", "w", false, "Enables watch of the given task.")
126127
pflag.BoolVarP(&Verbose, "verbose", "v", getConfig(config, func() *bool { return config.Verbose }, false), "Enables verbose mode.")
127128
pflag.BoolVarP(&Silent, "silent", "s", false, "Disables echoing.")
129+
pflag.BoolVar(&DisableFuzzy, "disable-fuzzy", getConfig(config, func() *bool { return config.DisableFuzzy }, false), "Disables fuzzy matching for task names.")
128130
pflag.BoolVarP(&AssumeYes, "yes", "y", false, "Assume \"yes\" as answer to all prompts.")
129131
pflag.BoolVarP(&Parallel, "parallel", "p", false, "Executes tasks provided on command line in parallel.")
130132
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) {
248250
task.WithWatch(Watch),
249251
task.WithVerbose(Verbose),
250252
task.WithSilent(Silent),
253+
task.WithDisableFuzzy(DisableFuzzy),
251254
task.WithAssumeYes(AssumeYes),
252255
task.WithDry(Dry || Status),
253256
task.WithSummary(Summary),

setup.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ func (e *Executor) Setup() error {
3636
if err := e.readTaskfile(node); err != nil {
3737
return err
3838
}
39-
e.setupFuzzyModel()
4039
e.setupStdFiles()
4140
if err := e.setupOutput(); err != nil {
4241
return err

task.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,8 +456,11 @@ func (e *Executor) GetTask(call *Call) (*ast.Task, error) {
456456
// If we found no tasks
457457
if len(aliasedTasks) == 0 {
458458
didYouMean := ""
459-
if e.fuzzyModel != nil {
460-
didYouMean = e.fuzzyModel.SpellCheck(call.Task)
459+
if !e.DisableFuzzy {
460+
e.fuzzyModelOnce.Do(e.setupFuzzyModel)
461+
if e.fuzzyModel != nil {
462+
didYouMean = e.fuzzyModel.SpellCheck(call.Task)
463+
}
461464
}
462465
return nil, &errors.TaskNotFoundError{
463466
TaskName: call.Task,

taskrc/ast/taskrc.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ import (
1010
)
1111

1212
type TaskRC struct {
13-
Version *semver.Version `yaml:"version"`
14-
Verbose *bool `yaml:"verbose"`
15-
Concurrency *int `yaml:"concurrency"`
16-
Remote Remote `yaml:"remote"`
17-
Experiments map[string]int `yaml:"experiments"`
18-
Failfast bool `yaml:"failfast"`
13+
Version *semver.Version `yaml:"version"`
14+
Verbose *bool `yaml:"verbose"`
15+
DisableFuzzy *bool `yaml:"disable-fuzzy"`
16+
Concurrency *int `yaml:"concurrency"`
17+
Remote Remote `yaml:"remote"`
18+
Failfast bool `yaml:"failfast"`
19+
Experiments map[string]int `yaml:"experiments"`
1920
}
2021

2122
type Remote struct {
@@ -53,6 +54,7 @@ func (t *TaskRC) Merge(other *TaskRC) {
5354
}
5455

5556
t.Verbose = cmp.Or(other.Verbose, t.Verbose)
57+
t.DisableFuzzy = cmp.Or(other.DisableFuzzy, t.DisableFuzzy)
5658
t.Concurrency = cmp.Or(other.Concurrency, t.Concurrency)
5759
t.Failfast = cmp.Or(other.Failfast, t.Failfast)
5860
}

website/src/docs/reference/cli.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,16 @@ Disable command echoing.
108108
task deploy --silent
109109
```
110110

111+
#### `--disable-fuzzy`
112+
113+
Disable fuzzy matching for task names. When enabled, Task will not suggest similar task names when you mistype a task name.
114+
115+
```bash
116+
task buidl --disable-fuzzy
117+
# Output: Task "buidl" does not exist
118+
# (without "Did you mean 'build'?" suggestion)
119+
```
120+
111121
### Execution Control
112122

113123
#### `-F, --failfast`

0 commit comments

Comments
 (0)