diff options
| author | Sandy Tao <[email protected]> | 2025-07-18 14:54:10 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-07-18 21:54:10 +0000 |
| commit | 4915050ad47236a6d8349ed87b68cd202f96efbe (patch) | |
| tree | 63b9eb50bccc10d7918e7dd8bca3eeaa59dae829 /packages/cli/src/ui/components/InputPrompt.tsx | |
| parent | b5f5ea2c31e296bc1f51cd315badbd4f40c99059 (diff) | |
improve command completion trigger logic based on cursor position (#4462)
Co-authored-by: Jacob Richman <[email protected]>
Diffstat (limited to 'packages/cli/src/ui/components/InputPrompt.tsx')
| -rw-r--r-- | packages/cli/src/ui/components/InputPrompt.tsx | 48 |
1 files changed, 46 insertions, 2 deletions
diff --git a/packages/cli/src/ui/components/InputPrompt.tsx b/packages/cli/src/ui/components/InputPrompt.tsx index 4d66b10c..46326431 100644 --- a/packages/cli/src/ui/components/InputPrompt.tsx +++ b/packages/cli/src/ui/components/InputPrompt.tsx @@ -10,7 +10,7 @@ import { Colors } from '../colors.js'; import { SuggestionsDisplay } from './SuggestionsDisplay.js'; import { useInputHistory } from '../hooks/useInputHistory.js'; import { TextBuffer } from './shared/text-buffer.js'; -import { cpSlice, cpLen } from '../utils/textUtils.js'; +import { cpSlice, cpLen, toCodePoints } from '../utils/textUtils.js'; import chalk from 'chalk'; import stringWidth from 'string-width'; import { useShellHistory } from '../hooks/useShellHistory.js'; @@ -58,10 +58,54 @@ export const InputPrompt: React.FC<InputPromptProps> = ({ setShellModeActive, }) => { const [justNavigatedHistory, setJustNavigatedHistory] = useState(false); + + // Check if cursor is after @ or / without unescaped spaces + const isCursorAfterCommandWithoutSpace = useCallback(() => { + const [row, col] = buffer.cursor; + const currentLine = buffer.lines[row] || ''; + + // Convert current line to code points for Unicode-aware processing + const codePoints = toCodePoints(currentLine); + + // Search backwards from cursor position within the current line only + for (let i = col - 1; i >= 0; i--) { + const char = codePoints[i]; + + if (char === ' ') { + // Check if this space is escaped by counting backslashes before it + let backslashCount = 0; + for (let j = i - 1; j >= 0 && codePoints[j] === '\\'; j--) { + backslashCount++; + } + + // If there's an odd number of backslashes, the space is escaped + const isEscaped = backslashCount % 2 === 1; + + if (!isEscaped) { + // Found unescaped space before @ or /, return false + return false; + } + // If escaped, continue searching backwards + } else if (char === '@' || char === '/') { + // Found @ or / without unescaped space in between + return true; + } + } + + return false; + }, [buffer.cursor, buffer.lines]); + + const shouldShowCompletion = useCallback( + () => + (isAtCommand(buffer.text) || isSlashCommand(buffer.text)) && + isCursorAfterCommandWithoutSpace(), + [buffer.text, isCursorAfterCommandWithoutSpace], + ); + const completion = useCompletion( buffer.text, config.getTargetDir(), - isAtCommand(buffer.text) || isSlashCommand(buffer.text), + shouldShowCompletion(), slashCommands, commandContext, config, |
