This commit is contained in:
roomote-v0[bot] 2026-04-10 12:42:44 +02:00 committed by GitHub
commit eda935f46a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 65 additions and 11 deletions

View file

@ -598,9 +598,13 @@ export const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
setShowContextMenu(showMenu)
if (showMenu) {
if (newValue.startsWith("/") && !newValue.includes(" ")) {
// Handle slash command - request fresh commands
const query = newValue
// Extract current line based on cursor position
const lineStart = newValue.lastIndexOf("\n", newCursorPosition - 1) + 1
const currentLineBefore = newValue.slice(lineStart, newCursorPosition)
if (currentLineBefore.startsWith("/") && !currentLineBefore.includes(" ")) {
// Handle slash command on current line - request fresh commands
const query = currentLineBefore
setSearchQuery(query)
// Set to first selectable item (skip section headers)
setSelectedMenuIndex(1) // Section header is at 0, first command is at 1

View file

@ -52,7 +52,7 @@ describe("insertMention", () => {
it("should handle slash command replacement", () => {
const result = insertMention("/mode some", 5, "code", true) // Simulating mode selection
expect(result.newValue).toBe("code") // Should replace the whole text
expect(result.newValue).toBe("code some") // Should replace slash token on current line, preserve rest
expect(result.mentionIndex).toBe(0)
})
@ -106,18 +106,34 @@ describe("insertMention", () => {
// --- Tests for isSlashCommand parameter ---
describe("isSlashCommand parameter", () => {
it("should replace entire text when isSlashCommand is true", () => {
it("should replace slash token on current line when isSlashCommand is true", () => {
const result = insertMention("/cod", 4, "code", true)
expect(result.newValue).toBe("code")
expect(result.mentionIndex).toBe(0)
})
it("should replace entire text even when @ mentions exist and isSlashCommand is true", () => {
it("should replace slash token but preserve text after cursor when isSlashCommand is true", () => {
const result = insertMention("/code @some/file.ts", 5, "debug", true)
expect(result.newValue).toBe("debug")
expect(result.newValue).toBe("debug @some/file.ts")
expect(result.mentionIndex).toBe(0)
})
it("should replace only current line slash token in multiline text", () => {
const text = "/code\n/deb"
const position = 10 // cursor at end of "/deb"
const result = insertMention(text, position, "debug", true)
expect(result.newValue).toBe("/code\ndebug")
expect(result.mentionIndex).toBe(6) // start of second line
})
it("should preserve other lines when inserting slash command on second line", () => {
const text = "/code\nsome text here\n/arc"
const position = 25 // cursor at end of "/arc"
const result = insertMention(text, position, "architect", true)
expect(result.newValue).toBe("/code\nsome text here\narchitect")
expect(result.mentionIndex).toBe(21) // start of third line
})
it("should insert @ mention correctly after slash command when isSlashCommand is false", () => {
const text = "/code @"
const position = 8 // cursor after @
@ -585,4 +601,29 @@ describe("shouldShowContextMenu", () => {
// This case means the regex wouldn't match anyway, but confirms context menu logic
expect(shouldShowContextMenu("@/path/with space", 13)).toBe(false) // Cursor after unescaped space
})
// --- Multiline slash command tests ---
it("should return true for slash command on second line", () => {
const text = "/code\n/deb"
const position = 10 // cursor at end of "/deb"
expect(shouldShowContextMenu(text, position)).toBe(true)
})
it("should return true for slash command on third line", () => {
const text = "/code\nsome text\n/arc"
const position = 19 // cursor at end of "/arc"
expect(shouldShowContextMenu(text, position)).toBe(true)
})
it("should return false for non-slash text on second line without @", () => {
const text = "/code\nhello"
const position = 11 // cursor at end of "hello"
expect(shouldShowContextMenu(text, position)).toBe(false)
})
it("should return false for slash command with space on second line", () => {
const text = "/code\n/debug something"
const position = 13 // cursor after space in "/debug "
expect(shouldShowContextMenu(text, position)).toBe(false)
})
})

View file

@ -32,9 +32,16 @@ export function insertMention(
): { newValue: string; mentionIndex: number } {
// Handle slash command selection (only when explicitly selecting a slash command)
if (isSlashCommand) {
const beforeCursor = text.slice(0, position)
const afterCursor = text.slice(position)
// Find the start of the current line
const currentLineStart = beforeCursor.lastIndexOf("\n") + 1
const beforeLine = text.slice(0, currentLineStart)
// Replace slash command token on the current line (from line start to cursor)
const newValue = beforeLine + value + afterCursor
return {
newValue: value,
mentionIndex: 0,
newValue,
mentionIndex: currentLineStart,
}
}
@ -367,8 +374,10 @@ export function getContextMenuOptions(
export function shouldShowContextMenu(text: string, position: number): boolean {
const beforeCursor = text.slice(0, position)
// Check if we're in a slash command context (at the beginning and no space yet)
if (text.startsWith("/") && !text.includes(" ") && position <= text.length) {
// Check if we're in a slash command context on the current line
const currentLineStart = beforeCursor.lastIndexOf("\n") + 1
const currentLineBefore = beforeCursor.slice(currentLineStart)
if (currentLineBefore.startsWith("/") && !currentLineBefore.includes(" ")) {
return true
}