fix(vscode): restore undo and redo in the chat input

VS Code's webview preload intercepts Ctrl/Cmd+Z and Ctrl+Y and forwards
them to the workbench, so the prompt input stopped propagation but never
performed the edit. A webview keypress has no native undo default action
on macOS, so the undo stack stayed untouched and the shortcuts did
nothing.

Perform the edit with document.execCommand on the same native undo stack
real typing builds, and match keyCode like VS Code does so non-Latin
keyboard layouts no longer leak the key back to the workbench.

The Agent Manager New Worktree prompt had the same gap with no guard at
all; it now shares the same helper through prompt-input-utils.
This commit is contained in:
marius-kilocode
2026-09-16 09:29:51 +02:00
parent 9dab2370fe
commit 78a4d932a6
4 changed files with 42 additions and 7 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"kilo-code": patch
---
Fix Ctrl/Cmd+Z, Ctrl/Cmd+Shift+Z, and Ctrl+Y undo and redo in the chat input, including on non-Latin keyboard layouts
@@ -44,7 +44,7 @@ import { useSpeechToText } from "../src/components/speech-to-text/useSpeechToTex
import { useSpeechToTextModels } from "../src/context/speech-to-text-models"
import { createSpeechShortcut } from "../src/components/speech-to-text/shortcut"
import { convertToMentionPath, insertPathMentions } from "../src/utils/path-mentions"
import { insertSpacedText } from "../src/components/chat/prompt-input-utils"
import { insertSpacedText, undoKey } from "../src/components/chat/prompt-input-utils"
import { useSlashCommand } from "../src/hooks/useSlashCommand"
import { BranchSelect, BranchSelectPopover } from "../src/components/shared/BranchSelect"
import { tracker } from "./telemetry"
@@ -451,8 +451,14 @@ export const NewWorktreeDialog: Component<{
}
const undo = (e: KeyboardEvent) => {
if (e.key !== "z" || (!e.metaKey && !e.ctrlKey) || e.shiftKey || prior === null) return
const action = undoKey(e)
if (!action) return
e.stopPropagation()
e.preventDefault()
if (action === "redo" || prior === null) {
document.execCommand(action)
return
}
const restored = prior
cancel()
setPrompt(restored)
@@ -60,6 +60,7 @@ import {
memoryRest,
type SandboxDefaultState,
type SandboxState,
undoKey,
} from "./prompt-input-utils"
import { sandboxMessages } from "./prompt-sandbox-messages"
import type { ExtensionMessage, ReviewCommentEntry, SendMessageFailedMessage, TextPart } from "../../types/messages"
@@ -1266,6 +1267,19 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
return true
}
// Native undo/redo. Plain undo falls through to handleKeyDown when an
// Enhance result can be reverted first.
const undo = (e: KeyboardEvent): boolean => {
const action = undoKey(e)
if (!action) return false
e.stopPropagation()
if (action === "undo" && preEnhanceText !== null) return false
e.preventDefault()
if (readonly()) return true
document.execCommand(action)
return true
}
const handleKeyDown = (e: KeyboardEvent) => {
if (goal.pending()) {
escape(e)
@@ -1273,7 +1287,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
}
if (locked()) return
// Undo enhanced prompt with Ctrl+Z / ⌘Z
if (e.key === "z" && (e.metaKey || e.ctrlKey) && !e.shiftKey && preEnhanceText !== null) {
if (undoKey(e) === "undo" && preEnhanceText !== null) {
e.preventDefault()
const restored = preEnhanceText
preEnhanceText = null
@@ -2003,10 +2017,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
onInput={handleInput}
onKeyDown={(e) => {
if (speechDown(e)) return
const key = e.key.toLowerCase()
if ((e.ctrlKey || e.metaKey) && !e.altKey && (key === "z" || (key === "y" && !e.shiftKey))) {
e.stopPropagation()
}
if (undo(e)) return
handleKeyDown(e)
}}
onKeyUp={(e) => {
@@ -34,6 +34,19 @@ export function applySandboxStates(current: Record<string, SandboxState>, next:
return { ...current, [next.sessionID]: state }
}
// VS Code's webview preload intercepts Ctrl/Cmd+Z and Ctrl+Y and forwards them
// to the workbench, which can undo an unrelated editor (#13724). Callers must
// stop propagation, and because a webview keypress has no native undo default
// action on macOS, perform the edit with document.execCommand (#14191).
// Match keyCode like VS Code does so non-Latin layouts stay in lockstep.
export function undoKey(e: KeyboardEvent): "undo" | "redo" | undefined {
if (!(e.ctrlKey || e.metaKey) || e.altKey) return
const z = e.keyCode === 90 || e.key.toLowerCase() === "z"
const y = e.keyCode === 89 || e.key.toLowerCase() === "y"
if (z) return e.shiftKey ? "redo" : "undo"
if (y && !e.shiftKey) return "redo"
}
export function fileName(path: string): string {
const normalized = path.replaceAll("\\", "/").replace(/\/+$/, "")
return normalized.split("/").pop() ?? normalized