resolveTask finds a task by exact match, file path, or fuzzy match.
(query string, tasks []*model.Task, exactOnly bool, threshold float64)
| 157 | |
| 158 | // resolveTask finds a task by exact match, file path, or fuzzy match. |
| 159 | func resolveTask(query string, tasks []*model.Task, exactOnly bool, threshold float64) (*model.Task, error) { |
| 160 | if task := findExactMatch(query, tasks); task != nil { |
| 161 | if dupes := findDuplicatesByID(task.ID, tasks); len(dupes) > 1 { |
| 162 | return nil, fmt.Errorf("duplicate task ID %q found in %d files:\n%s\nRun 'taskmd deduplicate' to fix", |
| 163 | task.ID, len(dupes), formatDuplicatePathsWithTitles(dupes)) |
| 164 | } |
| 165 | return task, nil |
| 166 | } |
| 167 | |
| 168 | task, err := findFilePathMatch(query, tasks) |
| 169 | if err != nil { |
| 170 | return nil, err |
| 171 | } |
| 172 | if task != nil { |
| 173 | return task, nil |
| 174 | } |
| 175 | |
| 176 | if exactOnly { |
| 177 | return nil, fmt.Errorf("task not found: %s", query) |
| 178 | } |
| 179 | |
| 180 | matches := fuzzyMatchTasks(query, tasks, threshold) |
| 181 | if len(matches) == 0 { |
| 182 | return nil, fmt.Errorf("task not found: %s", query) |
| 183 | } |
| 184 | |
| 185 | return promptSelection(query, matches) |
| 186 | } |
| 187 | |
| 188 | // findExactMatch tries ID match (case-sensitive), then title match (case-insensitive). |
| 189 | func findExactMatch(query string, tasks []*model.Task) *model.Task { |