mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 06:04:40 +00:00
fix(tui): remove backslash input buffering (#1037)
Instead of buffering `\` and waiting for the next key, let it be inserted immediately. On Enter, check if preceded by `\` and treat as newline. Removed backslash handling from the Input component entirely.
This commit is contained in:
parent
bac57f81be
commit
d57a26c88b
4 changed files with 61 additions and 43 deletions
|
|
@ -184,7 +184,6 @@ export class Editor implements Component, Focusable {
|
|||
// Bracketed paste mode buffering
|
||||
private pasteBuffer: string = "";
|
||||
private isInPaste: boolean = false;
|
||||
private pendingShiftEnter: boolean = false;
|
||||
|
||||
// Prompt history for up/down navigation
|
||||
private history: string[] = [];
|
||||
|
|
@ -448,21 +447,6 @@ export class Editor implements Component, Focusable {
|
|||
return;
|
||||
}
|
||||
|
||||
if (this.pendingShiftEnter) {
|
||||
if (data === "\r") {
|
||||
this.pendingShiftEnter = false;
|
||||
this.addNewLine();
|
||||
return;
|
||||
}
|
||||
this.pendingShiftEnter = false;
|
||||
this.insertCharacter("\\");
|
||||
}
|
||||
|
||||
if (data === "\\") {
|
||||
this.pendingShiftEnter = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Ctrl+C - let parent handle (exit/clear)
|
||||
if (kb.matches(data, "copy")) {
|
||||
return;
|
||||
|
|
@ -602,8 +586,7 @@ export class Editor implements Component, Focusable {
|
|||
data === "\x1b\r" ||
|
||||
data === "\x1b[13;2~" ||
|
||||
(data.length > 1 && data.includes("\x1b") && data.includes("\r")) ||
|
||||
(data === "\n" && data.length === 1) ||
|
||||
data === "\\\r"
|
||||
(data === "\n" && data.length === 1)
|
||||
) {
|
||||
this.addNewLine();
|
||||
return;
|
||||
|
|
@ -613,6 +596,15 @@ export class Editor implements Component, Focusable {
|
|||
if (kb.matches(data, "submit")) {
|
||||
if (this.disableSubmit) return;
|
||||
|
||||
// Workaround for terminals without Shift+Enter support:
|
||||
// If char before cursor is \, delete it and insert newline instead of submitting.
|
||||
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
||||
if (this.state.cursorCol > 0 && currentLine[this.state.cursorCol - 1] === "\\") {
|
||||
this.handleBackspace();
|
||||
this.addNewLine();
|
||||
return;
|
||||
}
|
||||
|
||||
let result = this.state.lines.join("\n").trim();
|
||||
for (const [pasteId, pasteContent] of this.pastes) {
|
||||
const markerRegex = new RegExp(`\\[paste #${pasteId}( (\\+\\d+ lines|\\d+ chars))?\\]`, "g");
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ export class Input implements Component, Focusable {
|
|||
// Bracketed paste mode buffering
|
||||
private pasteBuffer: string = "";
|
||||
private isInPaste: boolean = false;
|
||||
private pendingShiftEnter: boolean = false;
|
||||
|
||||
getValue(): string {
|
||||
return this.value;
|
||||
|
|
@ -68,22 +67,6 @@ export class Input implements Component, Focusable {
|
|||
return;
|
||||
}
|
||||
|
||||
if (this.pendingShiftEnter) {
|
||||
if (data === "\r") {
|
||||
this.pendingShiftEnter = false;
|
||||
if (this.onSubmit) this.onSubmit(this.value);
|
||||
return;
|
||||
}
|
||||
this.pendingShiftEnter = false;
|
||||
this.value = `${this.value.slice(0, this.cursor)}\\${this.value.slice(this.cursor)}`;
|
||||
this.cursor += 1;
|
||||
}
|
||||
|
||||
if (data === "\\") {
|
||||
this.pendingShiftEnter = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const kb = getEditorKeybindings();
|
||||
|
||||
// Escape/Cancel
|
||||
|
|
|
|||
|
|
@ -283,8 +283,17 @@ describe("Editor component", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("Shift+Enter handling", () => {
|
||||
it("treats split VS Code Shift+Enter as a newline", () => {
|
||||
describe("Backslash+Enter newline workaround", () => {
|
||||
it("inserts backslash immediately (no buffering)", () => {
|
||||
const editor = new Editor(createTestTUI(), defaultEditorTheme);
|
||||
|
||||
editor.handleInput("\\");
|
||||
|
||||
// Backslash should be visible immediately, not buffered
|
||||
assert.strictEqual(editor.getText(), "\\");
|
||||
});
|
||||
|
||||
it("converts standalone backslash to newline on Enter", () => {
|
||||
const editor = new Editor(createTestTUI(), defaultEditorTheme);
|
||||
|
||||
editor.handleInput("\\");
|
||||
|
|
@ -293,7 +302,7 @@ describe("Editor component", () => {
|
|||
assert.strictEqual(editor.getText(), "\n");
|
||||
});
|
||||
|
||||
it("inserts a literal backslash when not followed by Enter", () => {
|
||||
it("inserts backslash normally when followed by other characters", () => {
|
||||
const editor = new Editor(createTestTUI(), defaultEditorTheme);
|
||||
|
||||
editor.handleInput("\\");
|
||||
|
|
@ -301,6 +310,35 @@ describe("Editor component", () => {
|
|||
|
||||
assert.strictEqual(editor.getText(), "\\x");
|
||||
});
|
||||
|
||||
it("does not trigger newline when backslash is not immediately before cursor", () => {
|
||||
const editor = new Editor(createTestTUI(), defaultEditorTheme);
|
||||
let submitted = false;
|
||||
|
||||
editor.onSubmit = () => {
|
||||
submitted = true;
|
||||
};
|
||||
|
||||
editor.handleInput("\\");
|
||||
editor.handleInput("x");
|
||||
editor.handleInput("\r");
|
||||
|
||||
// Should submit, not insert newline (backslash not at cursor)
|
||||
assert.strictEqual(submitted, true);
|
||||
});
|
||||
|
||||
it("only removes one backslash when multiple are present", () => {
|
||||
const editor = new Editor(createTestTUI(), defaultEditorTheme);
|
||||
|
||||
editor.handleInput("\\");
|
||||
editor.handleInput("\\");
|
||||
editor.handleInput("\\");
|
||||
assert.strictEqual(editor.getText(), "\\\\\\");
|
||||
|
||||
editor.handleInput("\r");
|
||||
// Only the last backslash is removed, newline inserted
|
||||
assert.strictEqual(editor.getText(), "\\\\\n");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Unicode text editing behavior", () => {
|
||||
|
|
|
|||
|
|
@ -3,23 +3,28 @@ import { describe, it } from "node:test";
|
|||
import { Input } from "../src/components/input.js";
|
||||
|
||||
describe("Input component", () => {
|
||||
it("treats split VS Code Shift+Enter as submit", () => {
|
||||
it("submits value including backslash on Enter", () => {
|
||||
const input = new Input();
|
||||
let submitted: string | undefined;
|
||||
|
||||
input.setValue("hello");
|
||||
input.onSubmit = (value) => {
|
||||
submitted = value;
|
||||
};
|
||||
|
||||
// Type hello, then backslash, then Enter
|
||||
input.handleInput("h");
|
||||
input.handleInput("e");
|
||||
input.handleInput("l");
|
||||
input.handleInput("l");
|
||||
input.handleInput("o");
|
||||
input.handleInput("\\");
|
||||
input.handleInput("\r");
|
||||
|
||||
assert.strictEqual(submitted, "hello");
|
||||
assert.strictEqual(input.getValue(), "hello");
|
||||
// Input is single-line, no backslash+Enter workaround
|
||||
assert.strictEqual(submitted, "hello\\");
|
||||
});
|
||||
|
||||
it("inserts a literal backslash when not followed by Enter", () => {
|
||||
it("inserts backslash as regular character", () => {
|
||||
const input = new Input();
|
||||
|
||||
input.handleInput("\\");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue