1//! Which-key support for Zed.
2
3mod which_key_modal;
4mod which_key_settings;
5
6use gpui::{App, Keystroke};
7use settings::Settings;
8use std::{sync::LazyLock, time::Duration};
9use util::ResultExt;
10use which_key_modal::WhichKeyModal;
11use which_key_settings::WhichKeySettings;
12use workspace::Workspace;
13
14pub fn init(cx: &mut App) {
15 WhichKeySettings::register(cx);
16
17 cx.observe_new(|_: &mut Workspace, window, cx| {
18 let Some(window) = window else {
19 return;
20 };
21 let mut timer = None;
22 cx.observe_pending_input(window, move |workspace, window, cx| {
23 if window.pending_input_keystrokes().is_none() {
24 if let Some(modal) = workspace.active_modal::<WhichKeyModal>(cx) {
25 modal.update(cx, |modal, cx| modal.dismiss(cx));
26 };
27 timer.take();
28 return;
29 }
30
31 let which_key_settings = WhichKeySettings::get_global(cx);
32 if !which_key_settings.enabled {
33 return;
34 }
35
36 let delay_ms = which_key_settings.delay_ms;
37
38 timer.replace(cx.spawn_in(window, async move |workspace_handle, cx| {
39 cx.background_executor()
40 .timer(Duration::from_millis(delay_ms))
41 .await;
42 workspace_handle
43 .update_in(cx, |workspace, window, cx| {
44 if workspace.active_modal::<WhichKeyModal>(cx).is_some() {
45 return;
46 };
47
48 workspace.toggle_modal(window, cx, |window, cx| {
49 WhichKeyModal::new(workspace_handle.clone(), window, cx)
50 });
51 })
52 .log_err();
53 }));
54 })
55 .detach();
56 })
57 .detach();
58}
59
60// Hard-coded list of keystrokes to filter out from which-key display
61pub static FILTERED_KEYSTROKES: LazyLock<Vec<Vec<Keystroke>>> = LazyLock::new(|| {
62 [
63 // Modifiers on normal vim commands
64 "g h",
65 "g j",
66 "g k",
67 "g l",
68 "g $",
69 "g ^",
70 // Duplicate keys with "ctrl" held, e.g. "ctrl-w ctrl-a" is duplicate of "ctrl-w a"
71 "ctrl-w ctrl-a",
72 "ctrl-w ctrl-c",
73 "ctrl-w ctrl-h",
74 "ctrl-w ctrl-j",
75 "ctrl-w ctrl-k",
76 "ctrl-w ctrl-l",
77 "ctrl-w ctrl-n",
78 "ctrl-w ctrl-o",
79 "ctrl-w ctrl-p",
80 "ctrl-w ctrl-q",
81 "ctrl-w ctrl-s",
82 "ctrl-w ctrl-v",
83 "ctrl-w ctrl-w",
84 "ctrl-w ctrl-]",
85 "ctrl-w ctrl-shift-w",
86 "ctrl-w ctrl-g t",
87 "ctrl-w ctrl-g shift-t",
88 ]
89 .iter()
90 .filter_map(|s| {
91 let keystrokes: Result<Vec<_>, _> = s
92 .split(' ')
93 .map(|keystroke_str| Keystroke::parse(keystroke_str))
94 .collect();
95 keystrokes.ok()
96 })
97 .collect()
98});