From f42deae13e103f933a33e26343f738ca7322307c Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Thu, 22 Jan 2026 23:12:33 +0100 Subject: [PATCH] fix(tui): gate slash menu to empty input --- packages/tui/CHANGELOG.md | 4 ++++ packages/tui/src/components/editor.ts | 24 ++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/packages/tui/CHANGELOG.md b/packages/tui/CHANGELOG.md index a45af6ed..ff17086d 100644 --- a/packages/tui/CHANGELOG.md +++ b/packages/tui/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Slash command menu now only triggers when the editor input is otherwise empty ([#904](https://github.com/badlogic/pi-mono/issues/904)) + ## [0.49.3] - 2026-01-22 ### Added diff --git a/packages/tui/src/components/editor.ts b/packages/tui/src/components/editor.ts index ed173937..3471577f 100644 --- a/packages/tui/src/components/editor.ts +++ b/packages/tui/src/components/editor.ts @@ -984,7 +984,7 @@ export class Editor implements Component, Focusable { const currentLine = this.state.lines[this.state.cursorLine] || ""; const textBeforeCursor = currentLine.slice(0, this.state.cursorCol); // Check if we're in a slash command (with or without space for arguments) - if (textBeforeCursor.trimStart().startsWith("/")) { + if (this.isInSlashCommandContext(textBeforeCursor)) { this.tryTriggerAutocomplete(); } // Check if we're in an @ file reference context @@ -1169,7 +1169,7 @@ export class Editor implements Component, Focusable { const currentLine = this.state.lines[this.state.cursorLine] || ""; const textBeforeCursor = currentLine.slice(0, this.state.cursorCol); // Slash command context - if (textBeforeCursor.trimStart().startsWith("/")) { + if (this.isInSlashCommandContext(textBeforeCursor)) { this.tryTriggerAutocomplete(); } // @ file reference context @@ -1388,7 +1388,7 @@ export class Editor implements Component, Focusable { const currentLine = this.state.lines[this.state.cursorLine] || ""; const textBeforeCursor = currentLine.slice(0, this.state.cursorCol); // Slash command context - if (textBeforeCursor.trimStart().startsWith("/")) { + if (this.isInSlashCommandContext(textBeforeCursor)) { this.tryTriggerAutocomplete(); } // @ file reference context @@ -1802,15 +1802,27 @@ export class Editor implements Component, Focusable { } } + // Slash menu only allowed when all other lines are empty (no mixed content) + private isSlashMenuAllowed(): boolean { + for (let i = 0; i < this.state.lines.length; i++) { + if (i === this.state.cursorLine) continue; + if (this.state.lines[i].trim() !== "") return false; + } + return true; + } + // Helper method to check if cursor is at start of message (for slash command detection) private isAtStartOfMessage(): boolean { + if (!this.isSlashMenuAllowed()) return false; const currentLine = this.state.lines[this.state.cursorLine] || ""; const beforeCursor = currentLine.slice(0, this.state.cursorCol); - - // At start if line is empty, only contains whitespace, or is just "/" return beforeCursor.trim() === "" || beforeCursor.trim() === "/"; } + private isInSlashCommandContext(textBeforeCursor: string): boolean { + return this.isSlashMenuAllowed() && textBeforeCursor.trimStart().startsWith("/"); + } + // Autocomplete methods private tryTriggerAutocomplete(explicitTab: boolean = false): void { if (!this.autocompleteProvider) return; @@ -1848,7 +1860,7 @@ export class Editor implements Component, Focusable { const beforeCursor = currentLine.slice(0, this.state.cursorCol); // Check if we're in a slash command context - if (beforeCursor.trimStart().startsWith("/") && !beforeCursor.trimStart().includes(" ")) { + if (this.isInSlashCommandContext(beforeCursor) && !beforeCursor.trimStart().includes(" ")) { this.handleSlashCommandCompletion(); } else { this.forceFileAutocomplete();