diff --git a/crates/settings_ui/src/keybindings.rs b/crates/settings_ui/src/keybindings.rs index 9b87949ea15d64f986e922885166a0bc18f31867..80bb143d8b8626ccc4c9da404a5fae0bd9a8226d 100644 --- a/crates/settings_ui/src/keybindings.rs +++ b/crates/settings_ui/src/keybindings.rs @@ -1,9 +1,13 @@ -use std::fmt::Write as _; +use std::{cell::RefCell, fmt::Write as _, rc::Rc}; use db::anyhow::anyhow; -use gpui::{AppContext as _, EventEmitter, FocusHandle, Focusable, actions}; +use gpui::{ + AppContext as _, Context, Entity, EventEmitter, FocusHandle, Focusable, Global, Keymap, + Subscription, Task, actions, +}; use ui::{ - ActiveTheme as _, App, ParentElement as _, Render, Styled as _, Table, Window, div, string_cell, + ActiveTheme as _, App, BorrowAppContext, ParentElement as _, Render, SharedString, Styled as _, + Table, Window, div, string_cell, }; use workspace::{Item, SerializableItem, Workspace, register_serializable_item}; @@ -12,6 +16,9 @@ use crate::keybindings::persistence::KEYBINDING_EDITORS; actions!(zed, [OpenKeymapEditor]); pub fn init(cx: &mut App) { + let keymap_event_channel = KeymapEventChannel::new(); + cx.set_global(keymap_event_channel); + cx.observe_new(|workspace: &mut Workspace, _window, _cx| { workspace.register_action(|workspace, _: &OpenKeymapEditor, window, cx| { let open_keymap_editor = cx.new(|cx| KeymapEditor::new(cx)); @@ -23,8 +30,32 @@ pub fn init(cx: &mut App) { register_serializable_item::(cx); } +enum KeymapEvent { + KeymapChanged, +} + +pub struct KeymapEventChannel {} + +impl EventEmitter for KeymapEventChannel {} +impl Global for KeymapEventChannel {} + +impl KeymapEventChannel { + fn new() -> Self { + Self {} + } + + pub fn trigger_keymap_changed(cx: &mut App) { + cx.update_global(|_event_channel: &mut Self, _| { + dbg!("updating global"); + *_event_channel = Self::new(); + }); + } +} + struct KeymapEditor { focus_handle: FocusHandle, + _keymap_subscription: Subscription, + processed_bindings: Vec, } impl EventEmitter<()> for KeymapEditor {} @@ -37,12 +68,52 @@ impl Focusable for KeymapEditor { impl KeymapEditor { fn new(cx: &mut gpui::Context) -> Self { + let _keymap_subscription = cx.observe_global::(|this, cx| { + let key_bindings = Self::process_bindings(cx); + this.processed_bindings = key_bindings; + }); Self { focus_handle: cx.focus_handle(), + _keymap_subscription, + processed_bindings: vec![], + } + } + + fn process_bindings(cx: &mut Context) -> Vec { + let key_bindings_ptr = cx.key_bindings(); + let lock = key_bindings_ptr.borrow(); + let key_bindings = lock.bindings(); + + let mut processed_bindings = Vec::new(); + + for key_binding in key_bindings { + let mut keystroke_text = String::new(); + for keystroke in key_binding.keystrokes() { + write!(&mut keystroke_text, "{} ", keystroke.unparse()).ok(); + } + let keystroke_text = keystroke_text.trim().to_string(); + + let context = key_binding + .predicate() + .map(|predicate| predicate.to_string()) + .unwrap_or_else(|| "".to_string()); + + processed_bindings.push(ProcessedKeybinding { + keystroke_text: keystroke_text.into(), + action: key_binding.action().name().into(), + context: context.into(), + }) } + processed_bindings } } +struct ProcessedKeybinding { + keystroke_text: SharedString, + action: SharedString, + context: SharedString, +} + impl SerializableItem for KeymapEditor { fn serialized_item_kind() -> &'static str { "KeymapEditor" @@ -116,29 +187,17 @@ impl Item for KeymapEditor { impl Render for KeymapEditor { fn render(&mut self, _window: &mut Window, cx: &mut ui::Context) -> impl ui::IntoElement { - let key_bindings_ptr = cx.key_bindings(); - let lock = key_bindings_ptr.borrow(); - let key_bindings = lock.bindings(); + dbg!("rendering"); + if self.processed_bindings.is_empty() { + self.processed_bindings = Self::process_bindings(cx); + } let mut table = Table::new(vec!["Command", "Keystrokes", "Context"]); - for key_binding in key_bindings { - let mut keystroke_text = String::new(); - for keystroke in key_binding.keystrokes() { - write!(&mut keystroke_text, "{} ", keystroke.unparse()).ok(); - } - let keystroke_text = keystroke_text.trim().to_string(); - - let context = key_binding - .predicate() - .map(|predicate| predicate.to_string()) - .unwrap_or_else(|| "".to_string()); - - // dbg!(key_binding.action().name(), &keystroke_text, &context); - + for key_binding in &self.processed_bindings { table = table.row(vec![ - string_cell(key_binding.action().name()), - string_cell(keystroke_text), - string_cell(context), + string_cell(key_binding.action.clone()), + string_cell(key_binding.keystroke_text.clone()), + string_cell(key_binding.context.clone()), // TODO: Add a source field // string_cell(keybinding.source().to_string()), ]); diff --git a/crates/settings_ui/src/settings_ui.rs b/crates/settings_ui/src/settings_ui.rs index bb2d7ba63da1409a24b7b84104523a32bbde3cf9..122f801d6941fe467f29798afd2704ee94dadef9 100644 --- a/crates/settings_ui/src/settings_ui.rs +++ b/crates/settings_ui/src/settings_ui.rs @@ -20,7 +20,7 @@ use workspace::{Workspace, with_active_or_new_workspace}; use crate::appearance_settings_controls::AppearanceSettingsControls; -mod keybindings; +pub mod keybindings; pub struct SettingsUiFeatureFlag; diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 62e29eb7e2ace3c8da78815c2a6c16e30bb7e0cc..8e90ca33493ebca03647f815df3aeab71dac8d87 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -1419,6 +1419,7 @@ fn reload_keymaps(cx: &mut App, mut user_key_bindings: Vec) { "New Window", workspace::NewWindow, )]); + settings_ui::keybindings::KeymapEventChannel::trigger_keymap_changed(cx); } pub fn load_default_keymap(cx: &mut App) {