From b6cb416036afefd485ae9ecc7d93f794b193fc6a Mon Sep 17 00:00:00 2001 From: ntbang0901 <121003585+ntbang0901@users.noreply.github.com> Date: Mon, 9 Nov 2026 23:58:36 +0700 Subject: [PATCH] fix(workbench): keep empty editor hints aligned when an action is unbound (#2345) The empty editor's hint grid places cells automatically in two columns; a row whose action had no shortcut left out its key cell, so every later label moved into the shortcut column. Rows with an action now always render the key cell, empty when unbound. Covered over every keymap preset and user overrides. Co-authored-by: ntbang0901 <121003585+ntbang0901@users.noreply.github.com> --- src/workbench/EditorArea.tsx | 3 +- src/workbench/emptyEditorHints.test.tsx | 53 +++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/workbench/emptyEditorHints.test.tsx diff --git a/src/workbench/EditorArea.tsx b/src/workbench/EditorArea.tsx index 6d55ce12f..2582c5138 100644 --- a/src/workbench/EditorArea.tsx +++ b/src/workbench/EditorArea.tsx @@ -43,7 +43,8 @@ export function EmptyEditor() { {h.label} )} - {keys &&
{keys}
} + {/* Rendered even when unbound: the grid auto-places cells, so a missing one shifts every later row. */} + {h.action &&
{keys}
} ); })} diff --git a/src/workbench/emptyEditorHints.test.tsx b/src/workbench/emptyEditorHints.test.tsx new file mode 100644 index 000000000..de8957a7c --- /dev/null +++ b/src/workbench/emptyEditorHints.test.tsx @@ -0,0 +1,53 @@ +import { afterEach, describe, expect, it } from "vitest"; +import { render } from "@testing-library/react"; +import { PRESETS, useKeymap, type Keymap } from "@/platform/keymap"; +import { usePlatform } from "@/platform/platformInfo"; +import { useProject } from "@/platform/project"; +import { EmptyEditor } from "./EditorArea"; + +const rows = (container: HTMLElement) => + [...container.querySelectorAll("dl > div")].map((row) => ({ + cells: [...row.children].map((c) => c.tagName), + label: row.querySelector("dt")?.textContent, + keys: row.querySelector("dd")?.textContent, + })); + +// The hint grid has two auto-placed columns; a row missing its key cell pulls the next label into it. +describe("empty editor hints", () => { + const { os } = usePlatform.getState(); + const { preset: initialPreset } = useKeymap.getState(); + afterEach(() => { + useKeymap.setState({ preset: initialPreset, overrides: {} }); + useProject.setState({ lightEdit: false }); + usePlatform.setState({ os }); + }); + + const cases: Array<{ name: string; preset: string; overrides?: Keymap }> = [ + ...Object.keys(PRESETS).map((preset) => ({ name: preset, preset })), + { name: "a removed Go to File binding", preset: "intellij-macos", overrides: { "navigate.gotoFile": [] } }, + { + name: "a mouse-only Recent Files binding", + preset: "intellij-windows", + overrides: { "navigate.recentFiles": ["Button4"] }, + }, + ]; + + for (const { name, preset, overrides = {} } of cases) + for (const lightEdit of [false, true]) + it(`keeps a label and a key cell on every row with ${name}${lightEdit ? " in LightEdit" : ""}`, () => { + useKeymap.setState({ preset, overrides }); + useProject.setState({ lightEdit }); + const all = rows(render().container); + const last = all.pop(); + for (const row of all) expect(row.cells, row.label ?? "").toEqual(["DT", "DD"]); + expect(last).toMatchObject({ cells: ["DT"], label: "Drop files here to open them" }); + }); + + it("leaves Recent Files' key cell empty and Navigation Bar's shortcut beside it in VS Code (macOS)", () => { + usePlatform.setState({ os: "macos" }); + useKeymap.setState({ preset: "vscode-macos", overrides: {} }); + const byLabel = Object.fromEntries(rows(render().container).map((r) => [r.label, r.keys])); + expect(byLabel["Recent Files"]).toBe(""); + expect(byLabel["Navigation Bar"]).toBe("⇧⌘."); + }); +});