mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 18:01:22 +00:00
feat(tui): add Alt+D to delete word forward (kill)
Adds deleteWordForward action bound to Alt+D, which deletes from cursor to the end of the current word and saves to kill ring for later yanking. Consecutive forward kills append to the same kill ring entry.
This commit is contained in:
parent
9fb7434a06
commit
505894f4ea
4 changed files with 80 additions and 0 deletions
|
|
@ -3437,6 +3437,7 @@ export class InteractiveMode {
|
|||
const submit = this.getEditorKeyDisplay("submit");
|
||||
const newLine = this.getEditorKeyDisplay("newLine");
|
||||
const deleteWordBackward = this.getEditorKeyDisplay("deleteWordBackward");
|
||||
const deleteWordForward = this.getEditorKeyDisplay("deleteWordForward");
|
||||
const deleteToLineStart = this.getEditorKeyDisplay("deleteToLineStart");
|
||||
const deleteToLineEnd = this.getEditorKeyDisplay("deleteToLineEnd");
|
||||
const yank = this.getEditorKeyDisplay("yank");
|
||||
|
|
@ -3471,6 +3472,7 @@ export class InteractiveMode {
|
|||
| \`${submit}\` | Send message |
|
||||
| \`${newLine}\` | New line${process.platform === "win32" ? " (Ctrl+Enter on Windows Terminal)" : ""} |
|
||||
| \`${deleteWordBackward}\` | Delete word backwards |
|
||||
| \`${deleteWordForward}\` | Delete word forwards |
|
||||
| \`${deleteToLineStart}\` | Delete to start of line |
|
||||
| \`${deleteToLineEnd}\` | Delete to end of line |
|
||||
| \`${yank}\` | Paste the most-recently-deleted text |
|
||||
|
|
|
|||
|
|
@ -646,6 +646,10 @@ export class Editor implements Component, Focusable {
|
|||
this.deleteWordBackwards();
|
||||
return;
|
||||
}
|
||||
if (kb.matches(data, "deleteWordForward")) {
|
||||
this.deleteWordForward();
|
||||
return;
|
||||
}
|
||||
if (kb.matches(data, "deleteCharBackward") || matchesKey(data, "shift+backspace")) {
|
||||
this.handleBackspace();
|
||||
return;
|
||||
|
|
@ -1242,6 +1246,46 @@ export class Editor implements Component, Focusable {
|
|||
}
|
||||
}
|
||||
|
||||
private deleteWordForward(): void {
|
||||
this.historyIndex = -1; // Exit history browsing mode
|
||||
|
||||
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
||||
|
||||
// If at end of line, merge with next line (delete the newline)
|
||||
if (this.state.cursorCol >= currentLine.length) {
|
||||
if (this.state.cursorLine < this.state.lines.length - 1) {
|
||||
// Treat newline as deleted text (forward deletion = append)
|
||||
this.addToKillRing("\n", false);
|
||||
this.lastAction = "kill";
|
||||
|
||||
const nextLine = this.state.lines[this.state.cursorLine + 1] || "";
|
||||
this.state.lines[this.state.cursorLine] = currentLine + nextLine;
|
||||
this.state.lines.splice(this.state.cursorLine + 1, 1);
|
||||
}
|
||||
} else {
|
||||
// Save lastAction before cursor movement (moveWordForwards resets it)
|
||||
const wasKill = this.lastAction === "kill";
|
||||
|
||||
const oldCursorCol = this.state.cursorCol;
|
||||
this.moveWordForwards();
|
||||
const deleteTo = this.state.cursorCol;
|
||||
this.state.cursorCol = oldCursorCol;
|
||||
|
||||
// Restore kill state for accumulation check, then save to kill ring
|
||||
this.lastAction = wasKill ? "kill" : null;
|
||||
const deletedText = currentLine.slice(this.state.cursorCol, deleteTo);
|
||||
this.addToKillRing(deletedText, false);
|
||||
this.lastAction = "kill";
|
||||
|
||||
this.state.lines[this.state.cursorLine] =
|
||||
currentLine.slice(0, this.state.cursorCol) + currentLine.slice(deleteTo);
|
||||
}
|
||||
|
||||
if (this.onChange) {
|
||||
this.onChange(this.getText());
|
||||
}
|
||||
}
|
||||
|
||||
private handleForwardDelete(): void {
|
||||
this.historyIndex = -1; // Exit history browsing mode
|
||||
this.lastAction = null;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ export type EditorAction =
|
|||
| "deleteCharBackward"
|
||||
| "deleteCharForward"
|
||||
| "deleteWordBackward"
|
||||
| "deleteWordForward"
|
||||
| "deleteToLineStart"
|
||||
| "deleteToLineEnd"
|
||||
// Text input
|
||||
|
|
@ -69,6 +70,7 @@ export const DEFAULT_EDITOR_KEYBINDINGS: Required<EditorKeybindingsConfig> = {
|
|||
deleteCharBackward: "backspace",
|
||||
deleteCharForward: "delete",
|
||||
deleteWordBackward: ["ctrl+w", "alt+backspace"],
|
||||
deleteWordForward: "alt+d",
|
||||
deleteToLineStart: "ctrl+u",
|
||||
deleteToLineEnd: "ctrl+k",
|
||||
// Text input
|
||||
|
|
|
|||
|
|
@ -1062,5 +1062,37 @@ describe("Editor component", () => {
|
|||
editor.handleInput("\x1by"); // Alt+Y
|
||||
assert.strictEqual(editor.getText(), "hello SINGLEworld");
|
||||
});
|
||||
|
||||
it("Alt+D deletes word forward and saves to kill ring", () => {
|
||||
const editor = new Editor(createTestTUI(), defaultEditorTheme);
|
||||
|
||||
editor.setText("hello world test");
|
||||
editor.handleInput("\x01"); // Ctrl+A - go to start
|
||||
|
||||
editor.handleInput("\x1bd"); // Alt+D - deletes "hello"
|
||||
assert.strictEqual(editor.getText(), " world test");
|
||||
|
||||
editor.handleInput("\x1bd"); // Alt+D - deletes " world" (skips whitespace, then word)
|
||||
assert.strictEqual(editor.getText(), " test");
|
||||
|
||||
// Yank should get accumulated text
|
||||
editor.handleInput("\x19"); // Ctrl+Y
|
||||
assert.strictEqual(editor.getText(), "hello world test");
|
||||
});
|
||||
|
||||
it("Alt+D at end of line deletes newline", () => {
|
||||
const editor = new Editor(createTestTUI(), defaultEditorTheme);
|
||||
|
||||
editor.setText("line1\nline2");
|
||||
// Move to start of document, then to end of first line
|
||||
editor.handleInput("\x1b[A"); // Up arrow - go to first line
|
||||
editor.handleInput("\x05"); // Ctrl+E - end of line
|
||||
|
||||
editor.handleInput("\x1bd"); // Alt+D - deletes newline (merges lines)
|
||||
assert.strictEqual(editor.getText(), "line1line2");
|
||||
|
||||
editor.handleInput("\x19"); // Ctrl+Y
|
||||
assert.strictEqual(editor.getText(), "line1\nline2");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue