diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index d63c248fb83..af6d83c131d 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -58,6 +58,8 @@ export type PromptRef = { const PLACEHOLDERS = ["Fix a TODO in the codebase", "What is the tech stack of this project?", "Fix broken tests"] const SHELL_PLACEHOLDERS = ["ls -la", "git status", "pwd"] +let killRing = "" + export function Prompt(props: PromptProps) { let input: TextareaRenderable let anchor: BoxRenderable @@ -836,6 +838,29 @@ export function Prompt(props: PromptProps) { e.preventDefault() return } + if (keybind.match("input_delete_to_line_end", e)) { + const text = input.plainText + const offset = input.cursorOffset + const nextNewline = text.indexOf("\n", offset) + const endOfLine = nextNewline === -1 ? text.length : nextNewline + const killed = offset === endOfLine && nextNewline !== -1 ? "\n" : text.slice(offset, endOfLine) + if (killed) killRing = killed + } + if (keybind.match("input_delete_to_line_start", e)) { + const text = input.plainText + const offset = input.cursorOffset + const prevNewline = text.lastIndexOf("\n", offset - 1) + const startOfLine = prevNewline === -1 ? 0 : prevNewline + 1 + const killed = text.slice(startOfLine, offset) + if (killed) killRing = killed + } + if (keybind.match("input_yank", e)) { + if (killRing) { + input.insertText(killRing) + } + e.preventDefault() + return + } // Handle clipboard paste (Ctrl+V) - check for images first on Windows // This is needed because Windows terminal doesn't properly send image data // through bracketed paste, so we need to intercept the keypress and diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index aad0fd76c4b..f39e8f239b6 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -880,6 +880,7 @@ export namespace Config { input_delete_line: z.string().optional().default("ctrl+shift+d").describe("Delete line in input"), input_delete_to_line_end: z.string().optional().default("ctrl+k").describe("Delete to end of line in input"), input_delete_to_line_start: z.string().optional().default("ctrl+u").describe("Delete to start of line in input"), + input_yank: z.string().optional().default("ctrl+y").describe("Yank killed text in input"), input_backspace: z.string().optional().default("backspace,shift+backspace").describe("Backspace in input"), input_delete: z.string().optional().default("ctrl+d,delete,shift+delete").describe("Delete character in input"), input_undo: z.string().optional().default("ctrl+-,super+z").describe("Undo in input"), diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 4050ef15738..5d0be61778b 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -1295,6 +1295,10 @@ export type KeybindsConfig = { * Delete to start of line in input */ input_delete_to_line_start?: string + /** + * Yank killed text in input + */ + input_yank?: string /** * Backspace in input */ diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 2741c2362ec..e337b057589 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -9030,6 +9030,11 @@ "default": "ctrl+u", "type": "string" }, + "input_yank": { + "description": "Yank killed text in input", + "default": "ctrl+y", + "type": "string" + }, "input_backspace": { "description": "Backspace in input", "default": "backspace,shift+backspace",