diff --git a/packages/opencode/src/cli/cmd/tui/component/vim/vim-handler.ts b/packages/opencode/src/cli/cmd/tui/component/vim/vim-handler.ts index 2eb0ec7e4ed8..35933d6e58b7 100644 --- a/packages/opencode/src/cli/cmd/tui/component/vim/vim-handler.ts +++ b/packages/opencode/src/cli/cmd/tui/component/vim/vim-handler.ts @@ -120,6 +120,7 @@ export function createVimHandler(input: { function value(event: VimEvent) { if (event.name === "space") return " " + if (event.shift && event.name?.length === 1 && /[a-z]/.test(event.name)) return event.name.toUpperCase() return event.name ?? "" } diff --git a/packages/opencode/test/cli/tui/vim-motions.test.ts b/packages/opencode/test/cli/tui/vim-motions.test.ts index a32be49d36bf..7b074bee3c9f 100644 --- a/packages/opencode/test/cli/tui/vim-motions.test.ts +++ b/packages/opencode/test/cli/tui/vim-motions.test.ts @@ -1611,6 +1611,17 @@ describe("vim motion handler", () => { expect(ctx.state.mode()).toBe("replace") }) + test("replace mode preserves shifted uppercase letters", () => { + const ctx = createHandler("abcd", { mode: "replace" }) + ctx.textarea.cursorOffset = 1 + + const key = createEvent("x", { shift: true }) + expect(ctx.handler.handleKey(key.event)).toBe(true) + expect(key.prevented()).toBe(true) + expect(ctx.textarea.plainText).toBe("aXcd") + expect(ctx.textarea.cursorOffset).toBe(2) + }) + test("replace mode overwrites with space key", () => { const ctx = createHandler("abcd", { mode: "replace" }) ctx.textarea.cursorOffset = 1