From 8266018f4980a29affb7d9dcc24a60097f93eee5 Mon Sep 17 00:00:00 2001 From: liruifengv Date: Tue, 30 Jun 2026 15:28:05 +0800 Subject: [PATCH] fix(tui): open @ file mentions inside slash command arguments Typing @ in the middle of a slash command argument (for example `/goal Fix the @checkout docs`) was swallowed by the slash-argument completion guard before the @ mention branch ran, so the file list never opened. Run the @ mention branch ahead of the slash guards so file mentions take priority; plain slash-argument editing is still suppressed as before. --- .changeset/fix-at-mention-slash-arg.md | 5 +++ .../editor/file-mention-provider.ts | 33 +++++++++++-------- .../editor/file-mention-provider.test.ts | 15 +++++++++ 3 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 .changeset/fix-at-mention-slash-arg.md diff --git a/.changeset/fix-at-mention-slash-arg.md b/.changeset/fix-at-mention-slash-arg.md new file mode 100644 index 0000000000..64c373cd0a --- /dev/null +++ b/.changeset/fix-at-mention-slash-arg.md @@ -0,0 +1,5 @@ +--- +"@moonshot-ai/kimi-code": patch +--- + +Fix @ file mentions not opening when typed inside a slash command argument. diff --git a/apps/kimi-code/src/tui/components/editor/file-mention-provider.ts b/apps/kimi-code/src/tui/components/editor/file-mention-provider.ts index fb6ae3acbb..4e4b85c2fd 100644 --- a/apps/kimi-code/src/tui/components/editor/file-mention-provider.ts +++ b/apps/kimi-code/src/tui/components/editor/file-mention-provider.ts @@ -67,20 +67,11 @@ export class FileMentionProvider implements AutocompleteProvider { const currentLine = lines[cursorLine] ?? ''; const textBeforeCursor = currentLine.slice(0, cursorCol); - if (shouldSuppressLeadingWhitespaceSlashPath(textBeforeCursor, options.force)) { - return null; - } - - if ( - shouldSuppressSlashArgumentCompletion( - textBeforeCursor, - currentLine.slice(cursorCol), - options.force, - ) - ) { - return null; - } - + // `@` file / folder mentions take priority over the slash-command guards + // below. Without this, typing `@` inside a slash command's argument text + // (e.g. `/goal Fix the @|checkout docs`) would be swallowed by + // `shouldSuppressSlashArgumentCompletion` before the mention branch ever + // runs, so the file list never opens. const atPrefix = extractAtPrefix(textBeforeCursor); if (atPrefix !== null) { if (this.fdPath === null || this.additionalDirs.length > 0) { @@ -104,6 +95,20 @@ export class FileMentionProvider implements AutocompleteProvider { } } + if (shouldSuppressLeadingWhitespaceSlashPath(textBeforeCursor, options.force)) { + return null; + } + + if ( + shouldSuppressSlashArgumentCompletion( + textBeforeCursor, + currentLine.slice(cursorCol), + options.force, + ) + ) { + return null; + } + // Handle slash-command name completion ourselves so that aliases are // searchable and visible in the label. if (!options.force && textBeforeCursor.startsWith('/')) { diff --git a/apps/kimi-code/test/tui/components/editor/file-mention-provider.test.ts b/apps/kimi-code/test/tui/components/editor/file-mention-provider.test.ts index ac6c950462..dd310d1379 100644 --- a/apps/kimi-code/test/tui/components/editor/file-mention-provider.test.ts +++ b/apps/kimi-code/test/tui/components/editor/file-mention-provider.test.ts @@ -99,6 +99,21 @@ describe('FileMentionProvider', () => { expect(result).toBeNull(); }); + it('opens @ file mention when typed in the middle of a slash command argument', async () => { + writeFileSync(join(workDir, 'README.md'), 'readme'); + const provider = new FileMentionProvider([GOAL_COMMAND], workDir, NO_FD); + // Cursor sits in the middle of the /goal argument text, right after a + // freshly typed `@`. The slash-argument guard must not suppress the @ + // file list here. + const line = '/goal Fix the @checkout docs'; + const result = await provider.getSuggestions([line], 0, '/goal Fix the @'.length, { + signal: ctrl(), + }); + expect(result).not.toBeNull(); + expect(result!.prefix).toBe('@'); + expect(result!.items.map((item) => item.value)).toContain('@README.md'); + }); + it('still completes slash arguments at the end of an empty argument', async () => { const provider = new FileMentionProvider([GOAL_COMMAND], workDir, NO_FD); const line = '/goal ';