From 6012b4d82c00940c2e01bdea8ee6325587e48892 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Mon, 28 Sep 2026 17:36:18 +0800 Subject: [PATCH] fix(keymap): route cmd-K cmd-D to the code editor's skip-occurrence The chord starts with ClearScrollback's key on macOS, and gpui drops a pending chord that ranks below a complete match, so the fork's binding never got its second key. Re-add it after tty7's table, in the CodeEditor context only, so other text fields don't wait on cmd-K. --- src/ui/keymap.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/ui/keymap.rs b/src/ui/keymap.rs index 8d851d0c..70f82ff9 100644 --- a/src/ui/keymap.rs +++ b/src/ui/keymap.rs @@ -91,6 +91,15 @@ fn fixed_bindings() -> Vec { )); bindings.push(KeyBinding::new("secondary-alt-up", AddCursorAbove, input)); bindings.push(KeyBinding::new("secondary-alt-down", AddCursorBelow, input)); + // ⌘K ⌘D: a chord whose first key is `ClearScrollback` on macOS. gpui + // drops a pending chord that ranks below a complete match, so this + // too has to come after tty7's table. Code editor only: in any other + // field ⌘K goes straight through, without waiting for a second key. + bindings.push(KeyBinding::new( + "secondary-k secondary-d", + gpui_component::input::SkipOccurrence, + Some(gpui_component::input::CODE_EDITOR_CONTEXT), + )); } // The language-server commands, on the keys VS Code taught everyone, and // only inside a text field: F2 and F12 in a terminal belong to the @@ -3126,6 +3135,35 @@ mod gpui_tests { "a terminal still splits on ⌘D" ); } + + // ⌘K ⌘D in the code editor skips to the next occurrence, and ⌘K + // there waits for the chord's second key. + let editor = [ + gpui::KeyContext::parse("Workspace").expect("the context parses"), + gpui::KeyContext::parse("Input CodeEditor").expect("the context parses"), + ]; + let keymap = cx.key_bindings(); + let keymap = keymap.borrow(); + let chord = [ + Keystroke::parse("secondary-k").unwrap(), + Keystroke::parse("secondary-d").unwrap(), + ]; + let (hits, _) = keymap.bindings_for_input(&chord, &editor); + assert_eq!( + hits.first().map(|b| b.action().name()), + Some(gpui_component::input::SkipOccurrence::name_for_type()) + ); + let (_, pending) = + keymap.bindings_for_input(&[Keystroke::parse("secondary-k").unwrap()], &editor); + assert!(pending, "⌘K waits for the chord in the code editor"); + // A plain text field isn't held up. + let field = [ + gpui::KeyContext::parse("Workspace").expect("the context parses"), + gpui::KeyContext::parse("Input").expect("the context parses"), + ]; + let (_, pending) = + keymap.bindings_for_input(&[Keystroke::parse("secondary-k").unwrap()], &field); + assert!(!pending, "⌘K goes straight through in other fields"); }); }