| 20 | * Pure logic — no vscode dependency. |
| 21 | */ |
| 22 | export function resolveCompletions( |
| 23 | lines: string[], |
| 24 | cursorLine: number, |
| 25 | cursorCol: number, |
| 26 | frontmatterStartLine: number, |
| 27 | frontmatterEndLine: number, |
| 28 | scopes?: readonly ScopeEntry[], |
| 29 | taskEntries?: readonly TaskEntry[] |
| 30 | ): CompletionResult | undefined { |
| 31 | if (cursorLine <= frontmatterStartLine || cursorLine >= frontmatterEndLine) { |
| 32 | return undefined; |
| 33 | } |
| 34 | |
| 35 | const lineText = lines[cursorLine]; |
| 36 | if (!lineText) return undefined; |
| 37 | |
| 38 | const beforeCursor = lineText.substring(0, cursorCol); |
| 39 | |
| 40 | // Check for enum field completions: "status: " |
| 41 | const enumMatch = beforeCursor.match(/^(\w+):\s*$/); |
| 42 | if (enumMatch) { |
| 43 | const fieldName = enumMatch[1]; |
| 44 | const allowed = ENUM_FIELDS[fieldName]; |
| 45 | if (allowed) { |
| 46 | const colonIndex = lineText.indexOf(":"); |
| 47 | return { |
| 48 | fieldName, |
| 49 | values: allowed, |
| 50 | insertTexts: allowed.map((val) => ` ${val}`), |
| 51 | replaceColumns: [colonIndex + 1, cursorCol], |
| 52 | }; |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | // Check for touches scope completions |
| 57 | if (scopes && scopes.length > 0) { |
| 58 | const touchesResult = resolveTouchesCompletions( |
| 59 | lines, cursorLine, cursorCol, frontmatterStartLine, scopes |
| 60 | ); |
| 61 | if (touchesResult) return touchesResult; |
| 62 | } |
| 63 | |
| 64 | // Check for task ID completions (dependencies, parent) |
| 65 | if (taskEntries && taskEntries.length > 0) { |
| 66 | const taskIdResult = resolveTaskIdCompletions( |
| 67 | lines, cursorLine, cursorCol, frontmatterStartLine, taskEntries |
| 68 | ); |
| 69 | if (taskIdResult) return taskIdResult; |
| 70 | } |
| 71 | |
| 72 | return undefined; |
| 73 | } |
| 74 | |
| 75 | /** |
| 76 | * Resolve completions for touches field values (scope names). |