| author | |
| committer | |
| log | e17f244e0d411422dacaa0a43669fb4e8436347d |
| tree | eaa756c4246805c9beabef0a0d2c21b5e341af9c |
| parent | 62bb97428a1bd007f4a83cdb1fcb8bbde2cdeef3 |
| signature | Signed by PGP key B5690EEEBB952194 |
8 files changed, 42 insertions(+), 7 deletions(-)
apps/server/src/keybindings.test.ts+1| ... | ... | @@ -203,6 +203,7 @@ it.layer(NodeServices.layer)("keybindings", (it) => { |
| 203 | 203 | assert.equal(defaultsByCommand.get("projectSearch.toggle"), "mod+shift+f"); |
| 204 | 204 | assert.equal(defaultsByCommand.get("sidebar.toggle"), "mod+b"); |
| 205 | 205 | assert.equal(defaultsByCommand.get("rightPanel.toggle"), "mod+alt+b"); |
| 206 | assert.isFalse(defaultsByCommand.has("rightPanel.toggleMaximized")); | |
| 206 | 207 | assert.equal(defaultsByCommand.get("terminal.splitVertical"), "mod+shift+d"); |
| 207 | 208 | assert.equal(defaultsByCommand.get("modelPicker.jump.1"), "mod+1"); |
| 208 | 209 | assert.equal(defaultsByCommand.get("modelPicker.jump.9"), "mod+9"); |
apps/web/src/components/ChatView.tsx+8| ... | ... | @@ -4739,6 +4739,13 @@ function ChatViewContent(props: ChatViewProps) { |
| 4739 | 4739 | return; |
| 4740 | 4740 | } |
| 4741 | 4741 | |
| 4742 | if (command === "rightPanel.toggleMaximized") { | |
| 4743 | event.preventDefault(); | |
| 4744 | event.stopPropagation(); | |
| 4745 | toggleRightPanelMaximized(); | |
| 4746 | return; | |
| 4747 | } | |
| 4748 | ||
| 4742 | 4749 | if (command === "terminal.split") { |
| 4743 | 4750 | event.preventDefault(); |
| 4744 | 4751 | event.stopPropagation(); |
| ... | ... | @@ -4834,6 +4841,7 @@ function ChatViewContent(props: ChatViewProps) { |
| 4834 | 4841 | keybindings, |
| 4835 | 4842 | onToggleDiff, |
| 4836 | 4843 | toggleRightPanel, |
| 4844 | toggleRightPanelMaximized, | |
| 4837 | 4845 | toggleTerminalVisibility, |
| 4838 | 4846 | composerRef, |
| 4839 | 4847 | ]); |
apps/web/src/components/settings/KeybindingsSettings.logic.test.ts+4-2| ... | ... | @@ -135,7 +135,7 @@ describe("KeybindingsSettings.logic", () => { |
| 135 | 135 | expect(options).not.toContain("customModeActive"); |
| 136 | 136 | }); |
| 137 | 137 | |
| 138 | it("builds command options from defaults and resolved project bindings", () => { | |
| 138 | it("builds command options from built-in commands and resolved project bindings", () => { | |
| 139 | 139 | const options = buildKeybindingCommandOptions([ |
| 140 | 140 | { |
| 141 | 141 | command: "script.setup-db.run", |
| ... | ... | @@ -150,7 +150,9 @@ describe("KeybindingsSettings.logic", () => { |
| 150 | 150 | }, |
| 151 | 151 | ] satisfies ResolvedKeybindingsConfig); |
| 152 | 152 | |
| 153 | expect(options).toEqual(expect.arrayContaining(["chat.new", "script.setup-db.run"])); | |
| 153 | expect(options).toEqual( | |
| 154 | expect.arrayContaining(["chat.new", "rightPanel.toggleMaximized", "script.setup-db.run"]), | |
| 155 | ); | |
| 154 | 156 | }); |
| 155 | 157 | |
| 156 | 158 | it("reports unknown when variables without rejecting parseable expressions", () => { |
apps/web/src/components/settings/KeybindingsSettings.logic.ts+2-4| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | import { |
| 2 | STATIC_KEYBINDING_COMMANDS, | |
| 2 | 3 | type KeybindingCommand, |
| 3 | 4 | type KeybindingShortcut, |
| 4 | 5 | type KeybindingWhenNode, |
| ... | ... | @@ -255,10 +256,7 @@ export function buildWhenVariableOptions(): ReadonlyArray<WhenVariableOption> { |
| 255 | 256 | export function buildKeybindingCommandOptions( |
| 256 | 257 | keybindings: ResolvedKeybindingsConfig, |
| 257 | 258 | ): ReadonlyArray<KeybindingCommandOption> { |
| 258 | const commands = new Set<KeybindingCommand>(); | |
| 259 | for (const binding of DEFAULT_RESOLVED_KEYBINDINGS) { | |
| 260 | commands.add(binding.command); | |
| 261 | } | |
| 259 | const commands = new Set<KeybindingCommand>(STATIC_KEYBINDING_COMMANDS); | |
| 262 | 260 | for (const binding of keybindings) { |
| 263 | 261 | commands.add(binding.command); |
| 264 | 262 | } |
apps/web/src/keybindings.test.ts+16| ... | ... | @@ -679,6 +679,22 @@ describe("resolveShortcutCommand", () => { |
| 679 | 679 | ); |
| 680 | 680 | }); |
| 681 | 681 | |
| 682 | it("resolves a custom right panel maximize binding", () => { | |
| 683 | const keybindings = compile([ | |
| 684 | { | |
| 685 | shortcut: modShortcut("m", { shiftKey: true }), | |
| 686 | command: "rightPanel.toggleMaximized", | |
| 687 | }, | |
| 688 | ]); | |
| 689 | ||
| 690 | assert.strictEqual( | |
| 691 | resolveShortcutCommand(event({ key: "m", metaKey: true, shiftKey: true }), keybindings, { | |
| 692 | platform: "MacIntel", | |
| 693 | }), | |
| 694 | "rightPanel.toggleMaximized", | |
| 695 | ); | |
| 696 | }); | |
| 697 | ||
| 682 | 698 | it("matches bracket shortcuts using the physical key code", () => { |
| 683 | 699 | assert.strictEqual( |
| 684 | 700 | resolveShortcutCommand( |
docs/user/keybindings.md+3| ... | ... | @@ -47,6 +47,9 @@ Use **Inspect** to pick an element in the app and reveal its color token. Inspec |
| 47 | 47 | successful pick; its hover glow and badge preview the element and token that click will select. |
| 48 | 48 | **Cancel** or `Escape` exits Inspect and clears its selection and spotlight. |
| 49 | 49 | |
| 50 | `rightPanel.toggleMaximized` maximizes or restores the open right panel. It has no default shortcut, | |
| 51 | so add one in **Settings** → **Keybindings** if you want to use it. | |
| 52 | ||
| 50 | 53 | The command palette searches active thread titles, projects, branches, user messages, and final |
| 51 | 54 | agent responses across connected environments. Message matches show one labeled excerpt while |
| 52 | 55 | keeping the thread's project, branch, and machine context visible. Message search begins after two |
packages/contracts/src/keybindings.test.ts+6| ... | ... | @@ -42,6 +42,12 @@ it.effect("parses keybinding rules", () => |
| 42 | 42 | }); |
| 43 | 43 | assert.strictEqual(parsedRightPanelToggle.command, "rightPanel.toggle"); |
| 44 | 44 | |
| 45 | const parsedRightPanelToggleMaximized = yield* decode(KeybindingRule, { | |
| 46 | key: "mod+shift+m", | |
| 47 | command: "rightPanel.toggleMaximized", | |
| 48 | }); | |
| 49 | assert.strictEqual(parsedRightPanelToggleMaximized.command, "rightPanel.toggleMaximized"); | |
| 50 | ||
| 45 | 51 | const parsedClose = yield* decode(KeybindingRule, { |
| 46 | 52 | key: "mod+w", |
| 47 | 53 | command: "terminal.close", |
packages/contracts/src/keybindings.ts+2-1| ... | ... | @@ -47,7 +47,7 @@ export const MODEL_PICKER_KEYBINDING_COMMANDS = [ |
| 47 | 47 | ] as const; |
| 48 | 48 | export type ModelPickerKeybindingCommand = (typeof MODEL_PICKER_KEYBINDING_COMMANDS)[number]; |
| 49 | 49 | |
| 50 | const STATIC_KEYBINDING_COMMANDS = [ | |
| 50 | export const STATIC_KEYBINDING_COMMANDS = [ | |
| 51 | 51 | "sidebar.toggle", |
| 52 | 52 | "terminal.toggle", |
| 53 | 53 | "terminal.split", |
| ... | ... | @@ -55,6 +55,7 @@ const STATIC_KEYBINDING_COMMANDS = [ |
| 55 | 55 | "terminal.new", |
| 56 | 56 | "terminal.close", |
| 57 | 57 | "rightPanel.toggle", |
| 58 | "rightPanel.toggleMaximized", | |
| 58 | 59 | "diff.toggle", |
| 59 | 60 | "preview.toggle", |
| 60 | 61 | "preview.refresh", |