Skip to content

Commit 3af3474

Browse files
dvdskJosephTLyonsP1n3appl3
committed
Turns the keybind in command pallet entry into button to keymap editor
Opens a keybind create modal if there was no keybind set for the command pallet entry. Co-authored-by: Joseph T. Lyons <[email protected]> Co-authored-by: Julia Ryan <[email protected]>
1 parent 92ff29f commit 3af3474

File tree

3 files changed

+109
-15
lines changed

3 files changed

+109
-15
lines changed

crates/command_palette/src/command_palette.rs

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ use persistence::COMMAND_PALETTE_HISTORY;
2222
use picker::{Picker, PickerDelegate};
2323
use postage::{sink::Sink, stream::Stream};
2424
use settings::Settings;
25-
use ui::{HighlightedLabel, KeyBinding, ListItem, ListItemSpacing, h_flex, prelude::*, v_flex};
25+
use ui::{
26+
ButtonLike, HighlightedLabel, KeyBinding, ListItem, ListItemSpacing, h_flex, prelude::*, v_flex,
27+
};
2628
use util::ResultExt;
2729
use workspace::{ModalView, Workspace, WorkspaceSettings};
2830
use zed_actions::{OpenZedUrl, command_palette::Toggle};
@@ -448,6 +450,7 @@ impl PickerDelegate for CommandPaletteDelegate {
448450
) -> Option<Self::ListItem> {
449451
let matching_command = self.matches.get(ix)?;
450452
let command = self.commands.get(matching_command.candidate_id)?;
453+
let name = command.action.name();
451454
Some(
452455
ListItem::new(ix)
453456
.inset(true)
@@ -462,12 +465,49 @@ impl PickerDelegate for CommandPaletteDelegate {
462465
command.name.clone(),
463466
matching_command.positions.clone(),
464467
))
465-
.children(KeyBinding::for_action_in(
466-
&*command.action,
467-
&self.previous_focus_handle,
468-
window,
469-
cx,
470-
)),
468+
.child(
469+
div().child(
470+
KeyBinding::for_action_in(
471+
&*command.action,
472+
&self.previous_focus_handle,
473+
window,
474+
cx,
475+
)
476+
.map(|keybind| {
477+
ButtonLike::new(name)
478+
.style(ButtonStyle::Transparent)
479+
.child(keybind)
480+
.tooltip(ui::Tooltip::text("Change key binding…"))
481+
.on_click(|_, window, cx| {
482+
window.dispatch_action(
483+
zed_actions::OpenKeymapWithFilter {
484+
filter: name.to_string(),
485+
}
486+
.boxed_clone(),
487+
cx,
488+
);
489+
})
490+
.into_any_element()
491+
})
492+
.unwrap_or_else(|| {
493+
IconButton::new(command.action.name(), IconName::Keyboard)
494+
.style(ButtonStyle::Transparent)
495+
.alpha(0.8)
496+
.icon_size(IconSize::XSmall)
497+
.tooltip(ui::Tooltip::text("Add key binding…"))
498+
.on_click(|_, window, cx| {
499+
window.dispatch_action(
500+
zed_actions::OpenKeymapWithFilter {
501+
filter: name.to_string(),
502+
}
503+
.boxed_clone(),
504+
cx,
505+
);
506+
})
507+
.into_any_element()
508+
}),
509+
),
510+
),
471511
),
472512
)
473513
}

crates/keymap_editor/src/keymap_editor.rs

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use std::{
2+
cell::RefCell,
23
cmp::{self},
34
ops::{Not as _, Range},
5+
rc::Rc,
46
sync::Arc,
5-
time::Duration,
7+
time::{Duration, Instant},
68
};
79

810
mod ui_components;
@@ -40,7 +42,7 @@ use workspace::{
4042
};
4143

4244
pub use ui_components::*;
43-
use zed_actions::OpenKeymap;
45+
use zed_actions::{OpenKeymap, OpenKeymapWithFilter};
4446

4547
use crate::{
4648
persistence::KEYBINDING_EDITORS,
@@ -79,37 +81,75 @@ pub fn init(cx: &mut App) {
7981
let keymap_event_channel = KeymapEventChannel::new();
8082
cx.set_global(keymap_event_channel);
8183

82-
cx.on_action(|_: &OpenKeymap, cx| {
84+
fn common(filter: String, cx: &mut App) {
8385
workspace::with_active_or_new_workspace(cx, move |workspace, window, cx| {
8486
workspace
85-
.with_local_workspace(window, cx, |workspace, window, cx| {
87+
.with_local_workspace(window, cx, move |workspace, window, cx| {
8688
let existing = workspace
8789
.active_pane()
8890
.read(cx)
8991
.items()
9092
.find_map(|item| item.downcast::<KeymapEditor>());
9193

92-
if let Some(existing) = existing {
94+
let keymap_editor = if let Some(existing) = existing {
9395
workspace.activate_item(&existing, true, true, window, cx);
96+
existing
9497
} else {
9598
let keymap_editor =
9699
cx.new(|cx| KeymapEditor::new(workspace.weak_handle(), window, cx));
97100
workspace.add_item_to_active_pane(
98-
Box::new(keymap_editor),
101+
Box::new(keymap_editor.clone()),
99102
None,
100103
true,
101104
window,
102105
cx,
103106
);
104-
}
107+
keymap_editor
108+
};
109+
110+
keymap_editor.update(cx, |editor, cx| {
111+
editor.filter_editor.update(cx, |editor, cx| {
112+
editor.clear(window, cx);
113+
editor.insert(&filter, window, cx);
114+
});
115+
if !editor.has_binding_for(&filter) {
116+
open_binding_modal_after_loading(cx)
117+
}
118+
})
105119
})
106120
.detach();
107121
})
108-
});
122+
}
123+
124+
cx.on_action(|_: &OpenKeymap, cx| common(String::new(), cx));
125+
cx.on_action(|action: &OpenKeymapWithFilter, cx| common(action.filter.clone(), cx));
109126

110127
register_serializable_item::<KeymapEditor>(cx);
111128
}
112129

130+
fn open_binding_modal_after_loading(cx: &mut Context<KeymapEditor>) {
131+
let started_at = Instant::now();
132+
let observer = Rc::new(RefCell::new(None));
133+
let handle = {
134+
let observer = Rc::clone(&observer);
135+
cx.observe(&cx.entity(), move |editor, _, cx| {
136+
let subscription = observer.borrow_mut().take();
137+
138+
if started_at.elapsed().as_secs() > 10 {
139+
return;
140+
}
141+
if !editor.matches.is_empty() {
142+
editor.selected_index = Some(0);
143+
cx.dispatch_action(&CreateBinding);
144+
return;
145+
}
146+
147+
*observer.borrow_mut() = subscription;
148+
})
149+
};
150+
*observer.borrow_mut() = Some(handle);
151+
}
152+
113153
pub struct KeymapEventChannel {}
114154

115155
impl Global for KeymapEventChannel {}
@@ -1323,6 +1363,13 @@ impl KeymapEditor {
13231363
editor.set_keystrokes(keystrokes, cx);
13241364
});
13251365
}
1366+
1367+
fn has_binding_for(&self, action_name: &str) -> bool {
1368+
self.keybindings
1369+
.iter()
1370+
.filter(|kb| kb.keystrokes().is_some())
1371+
.any(|kb| kb.action().name == action_name)
1372+
}
13261373
}
13271374

13281375
struct HumanizedActionNameCache {

crates/zed_actions/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ pub struct OpenZedUrl {
2727
pub url: String,
2828
}
2929

30+
/// Opens the keymap editor.
31+
#[derive(PartialEq, Clone, Deserialize, Default, JsonSchema, Action)]
32+
#[action(namespace = zed)]
33+
pub struct OpenKeymapWithFilter {
34+
pub filter: String,
35+
}
36+
3037
actions!(
3138
zed,
3239
[

0 commit comments

Comments
 (0)