fix(tui): default Ctrl+Z to undo on Windows (#21138)

pull/21147/head
Luke Parker 2026-04-06 12:38:35 +10:00 committed by GitHub
parent 9965d385de
commit 77a462c930
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 61 additions and 2 deletions

View File

@ -761,6 +761,7 @@ function App(props: { onSnapshot?: () => Promise<string[]> }) {
keybind: "terminal_suspend",
category: "System",
hidden: true,
enabled: tuiConfig.keybinds?.terminal_suspend !== "none",
onSelect: () => {
process.once("SIGCONT", () => {
renderer.resume()

View File

@ -148,5 +148,7 @@ const TIPS = [
"Use {highlight}/review{/highlight} to review uncommitted changes, branches, or PRs",
"Run {highlight}/help{/highlight} or {highlight}Ctrl+X H{/highlight} to show the help dialog",
"Use {highlight}/rename{/highlight} to rename the current session",
"Press {highlight}Ctrl+Z{/highlight} to suspend the terminal and return to your shell",
...(process.platform === "win32"
? ["Press {highlight}Ctrl+Z{/highlight} to undo changes in your prompt"]
: ["Press {highlight}Ctrl+Z{/highlight} to suspend the terminal and return to your shell"]),
]

View File

@ -111,7 +111,15 @@ export namespace TuiConfig {
}
}
acc.result.keybinds = Config.Keybinds.parse(acc.result.keybinds ?? {})
const keybinds = { ...(acc.result.keybinds ?? {}) }
if (process.platform === "win32") {
// Native Windows terminals do not support POSIX suspend, so prefer prompt undo.
keybinds.terminal_suspend = "none"
keybinds.input_undo ??= unique(["ctrl+z", ...Config.Keybinds.shape.input_undo.parse(undefined).split(",")]).join(
",",
)
}
acc.result.keybinds = Config.Keybinds.parse(keybinds)
const deps: Promise<void>[] = []
if (acc.result.plugin?.length) {

View File

@ -9,6 +9,7 @@ import { Global } from "../../src/global"
import { Filesystem } from "../../src/util/filesystem"
const managedConfigDir = process.env.OPENCODE_TEST_MANAGED_CONFIG_DIR!
const wintest = process.platform === "win32" ? test : test.skip
beforeEach(async () => {
await Config.invalidate(true)
@ -441,6 +442,53 @@ test("merges keybind overrides across precedence layers", async () => {
})
})
wintest("defaults Ctrl+Z to input undo on Windows", async () => {
await using tmp = await tmpdir()
await Instance.provide({
directory: tmp.path,
fn: async () => {
const config = await TuiConfig.get()
expect(config.keybinds?.terminal_suspend).toBe("none")
expect(config.keybinds?.input_undo).toBe("ctrl+z,ctrl+-,super+z")
},
})
})
wintest("keeps explicit input undo overrides on Windows", async () => {
await using tmp = await tmpdir({
init: async (dir) => {
await Bun.write(path.join(dir, "tui.json"), JSON.stringify({ keybinds: { input_undo: "ctrl+y" } }))
},
})
await Instance.provide({
directory: tmp.path,
fn: async () => {
const config = await TuiConfig.get()
expect(config.keybinds?.terminal_suspend).toBe("none")
expect(config.keybinds?.input_undo).toBe("ctrl+y")
},
})
})
wintest("ignores terminal suspend bindings on Windows", async () => {
await using tmp = await tmpdir({
init: async (dir) => {
await Bun.write(path.join(dir, "tui.json"), JSON.stringify({ keybinds: { terminal_suspend: "alt+z" } }))
},
})
await Instance.provide({
directory: tmp.path,
fn: async () => {
const config = await TuiConfig.get()
expect(config.keybinds?.terminal_suspend).toBe("none")
expect(config.keybinds?.input_undo).toBe("ctrl+z,ctrl+-,super+z")
},
})
})
test("OPENCODE_TUI_CONFIG provides settings when no project config exists", async () => {
await using tmp = await tmpdir({
init: async (dir) => {