diff --git a/src/main/frontend/components/cmdk/core.cljs b/src/main/frontend/components/cmdk/core.cljs index 79b2a80ceb..2da082f2f7 100644 --- a/src/main/frontend/components/cmdk/core.cljs +++ b/src/main/frontend/components/cmdk/core.cljs @@ -1053,10 +1053,13 @@ (util/stop e)) (cond - (and meta? enter?) - (let [repo (state/get-current-repo)] - (shui/dialog-close! :ls-dialog-cmdk) - (state/sidebar-add-block! repo input :search)) + (cmdk-state/consume-open-search-sidebar-keydown! + e + (fn [] + (let [repo (state/get-current-repo)] + (shui/dialog-close! :ls-dialog-cmdk) + (state/sidebar-add-block! repo input :search)))) + nil as-keydown? (if meta? (show-more) (do diff --git a/src/main/frontend/components/cmdk/state.cljs b/src/main/frontend/components/cmdk/state.cljs index cc68e816ae..f24f62da4f 100644 --- a/src/main/frontend/components/cmdk/state.cljs +++ b/src/main/frontend/components/cmdk/state.cljs @@ -1,6 +1,7 @@ (ns frontend.components.cmdk.state - "Persist query and filter group from the last cmdk query" - (:require [frontend.storage :as storage])) + "State helpers for command palette search." + (:require [frontend.storage :as storage] + [frontend.util :as util])) (def cmdk-last-search-storage-key :ls-cmdk-last-search) (def cmdk-empty-repo-key "__no-repo__") @@ -43,6 +44,14 @@ (catch :default _e nil))) +(defn consume-open-search-sidebar-keydown! + [event open-search!] + (when (and (util/meta-key? event) + (= "Enter" (.-key event))) + (util/stop event) + (open-search!) + true)) + (defn- explicit-mode-filter-group [opts search-mode] (when (and search-mode diff --git a/src/test/frontend/components/cmdk/state_test.cljs b/src/test/frontend/components/cmdk/state_test.cljs index cd30e3fff7..91df69aaa7 100644 --- a/src/test/frontend/components/cmdk/state_test.cljs +++ b/src/test/frontend/components/cmdk/state_test.cljs @@ -1,8 +1,24 @@ (ns frontend.components.cmdk.state-test (:require [cljs.test :refer [deftest is testing]] [frontend.components.cmdk.state :as state] + [frontend.util :as util] + [goog.object :as gobj] [frontend.storage :as storage])) +(defn- key-event + [{:keys [key ctrl? meta?]}] + (let [prevented? (atom false) + stopped? (atom false) + event (js-obj)] + (gobj/set event "key" key) + (gobj/set event "ctrlKey" (boolean ctrl?)) + (gobj/set event "metaKey" (boolean meta?)) + (gobj/set event "preventDefault" #(reset! prevented? true)) + (gobj/set event "stopPropagation" #(reset! stopped? true)) + {:event event + :prevented? prevented? + :stopped? stopped?})) + (deftest default-cmdk-context?-true-for-global-open (testing "default cmdk context is true for global open" (is (true? (state/default-cmdk-context? {} :global nil))) @@ -47,6 +63,33 @@ (state/load-last-cmdk-search "repo-b"))) (is (nil? (state/load-last-cmdk-search "repo-c")))))) +(deftest consume-open-search-sidebar-keydown-stops-editor-shortcut + (testing "cmdk consumes mod+Enter before the focused editor can cycle todo" + (let [{:keys [event prevented? stopped?]} (key-event {:key "Enter" :ctrl? true}) + opened? (atom false)] + (with-redefs [util/meta-key? (constantly true)] + (is (true? (state/consume-open-search-sidebar-keydown! event #(reset! opened? true)))) + (is (true? @opened?)) + (is (true? @prevented?)) + (is (true? @stopped?)))))) + +(deftest consume-open-search-sidebar-keydown-ignores-other-keys + (testing "cmdk leaves non-shortcut keydowns available to normal handling" + (let [{plain-enter :event plain-prevented? :prevented? plain-stopped? :stopped?} + (key-event {:key "Enter"}) + {mod-n :event mod-n-prevented? :prevented? mod-n-stopped? :stopped?} + (key-event {:key "n" :ctrl? true}) + opened* (atom 0)] + (with-redefs [util/meta-key? (constantly false)] + (is (nil? (state/consume-open-search-sidebar-keydown! plain-enter #(swap! opened* inc))))) + (with-redefs [util/meta-key? (constantly true)] + (is (nil? (state/consume-open-search-sidebar-keydown! mod-n #(swap! opened* inc))))) + (is (= 0 @opened*)) + (is (false? @plain-prevented?)) + (is (false? @plain-stopped?)) + (is (false? @mod-n-prevented?)) + (is (false? @mod-n-stopped?))))) + (deftest init-prioritizes-initial-input-over-saved-query (testing "initial-input wins over persisted query when both exist" (with-redefs [storage/get (fn [_]