Detailed changes
@@ -81,50 +81,61 @@ pub fn init(cx: &mut App) {
let keymap_event_channel = KeymapEventChannel::new();
cx.set_global(keymap_event_channel);
- fn common(filter: Option<String>, cx: &mut App) {
- workspace::with_active_or_new_workspace(cx, move |workspace, window, cx| {
- workspace
- .with_local_workspace(window, cx, move |workspace, window, cx| {
- let existing = workspace
- .active_pane()
- .read(cx)
- .items()
- .find_map(|item| item.downcast::<KeymapEditor>());
-
- let keymap_editor = if let Some(existing) = existing {
- workspace.activate_item(&existing, true, true, window, cx);
- existing
- } else {
- let keymap_editor =
- cx.new(|cx| KeymapEditor::new(workspace.weak_handle(), window, cx));
- workspace.add_item_to_active_pane(
- Box::new(keymap_editor.clone()),
- None,
- true,
- window,
- cx,
- );
- keymap_editor
- };
-
- if let Some(filter) = filter {
- keymap_editor.update(cx, |editor, cx| {
- editor.filter_editor.update(cx, |editor, cx| {
- editor.clear(window, cx);
- editor.insert(&filter, window, cx);
- });
- if !editor.has_binding_for(&filter) {
- open_binding_modal_after_loading(cx)
- }
- })
- }
- })
- .detach();
- })
+ fn open_keymap_editor(
+ filter: Option<String>,
+ workspace: &mut Workspace,
+ window: &mut Window,
+ cx: &mut Context<Workspace>,
+ ) {
+ workspace
+ .with_local_workspace(window, cx, |workspace, window, cx| {
+ let existing = workspace
+ .active_pane()
+ .read(cx)
+ .items()
+ .find_map(|item| item.downcast::<KeymapEditor>());
+
+ let keymap_editor = if let Some(existing) = existing {
+ workspace.activate_item(&existing, true, true, window, cx);
+ existing
+ } else {
+ let keymap_editor =
+ cx.new(|cx| KeymapEditor::new(workspace.weak_handle(), window, cx));
+ workspace.add_item_to_active_pane(
+ Box::new(keymap_editor.clone()),
+ None,
+ true,
+ window,
+ cx,
+ );
+ keymap_editor
+ };
+
+ if let Some(filter) = filter {
+ keymap_editor.update(cx, |editor, cx| {
+ editor.filter_editor.update(cx, |editor, cx| {
+ editor.clear(window, cx);
+ editor.insert(&filter, window, cx);
+ });
+ if !editor.has_binding_for(&filter) {
+ open_binding_modal_after_loading(cx)
+ }
+ })
+ }
+ })
+ .detach_and_log_err(cx);
}
- cx.on_action(|_: &OpenKeymap, cx| common(None, cx))
- .on_action(|action: &ChangeKeybinding, cx| common(Some(action.action.clone()), cx));
+ cx.observe_new(|workspace: &mut Workspace, _window, _cx| {
+ workspace
+ .register_action(|workspace, _: &OpenKeymap, window, cx| {
+ open_keymap_editor(None, workspace, window, cx);
+ })
+ .register_action(|workspace, action: &ChangeKeybinding, window, cx| {
+ open_keymap_editor(Some(action.action.clone()), workspace, window, cx);
+ });
+ })
+ .detach();
register_serializable_item::<KeymapEditor>(cx);
}
@@ -1,12 +1,12 @@
-use gpui::App;
+use gpui::{Action as _, App};
use settings::{LanguageSettingsContent, SettingsContent};
use std::sync::Arc;
use strum::IntoDiscriminant as _;
use ui::{IntoElement, SharedString};
use crate::{
- DynamicItem, PROJECT, SettingField, SettingItem, SettingsFieldMetadata, SettingsPage,
- SettingsPageItem, SubPageLink, USER, all_language_names, sub_page_stack,
+ ActionLink, DynamicItem, PROJECT, SettingField, SettingItem, SettingsFieldMetadata,
+ SettingsPage, SettingsPageItem, SubPageLink, USER, all_language_names, sub_page_stack,
};
const DEFAULT_STRING: String = String::new();
@@ -1054,6 +1054,25 @@ pub(crate) fn settings_data(cx: &App) -> Vec<SettingsPage> {
SettingsPage {
title: "Keymap",
items: vec![
+ SettingsPageItem::SectionHeader("Keybindings"),
+ SettingsPageItem::ActionLink(ActionLink {
+ title: "Edit Keybindings".into(),
+ description: Some("Customize keybindings in the keymap editor.".into()),
+ button_text: "Open Keymap".into(),
+ on_click: Arc::new(|settings_window, window, cx| {
+ let Some(original_window) = settings_window.original_window else {
+ return;
+ };
+ original_window
+ .update(cx, |_workspace, original_window, cx| {
+ original_window
+ .dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx);
+ original_window.activate_window();
+ })
+ .ok();
+ window.remove_window();
+ }),
+ }),
SettingsPageItem::SectionHeader("Base Keymap"),
SettingsPageItem::SettingItem(SettingItem {
title: "Base Keymap",
@@ -731,6 +731,7 @@ enum SettingsPageItem {
SettingItem(SettingItem),
SubPageLink(SubPageLink),
DynamicItem(DynamicItem),
+ ActionLink(ActionLink),
}
impl std::fmt::Debug for SettingsPageItem {
@@ -746,6 +747,9 @@ impl std::fmt::Debug for SettingsPageItem {
SettingsPageItem::DynamicItem(dynamic_item) => {
write!(f, "DynamicItem({})", dynamic_item.discriminant.title)
}
+ SettingsPageItem::ActionLink(action_link) => {
+ write!(f, "ActionLink({})", action_link.title)
+ }
}
}
}
@@ -973,6 +977,55 @@ impl SettingsPageItem {
return content.into_any_element();
}
+ SettingsPageItem::ActionLink(action_link) => v_flex()
+ .group("setting-item")
+ .px_8()
+ .child(
+ h_flex()
+ .id(action_link.title.clone())
+ .w_full()
+ .min_w_0()
+ .justify_between()
+ .map(apply_padding)
+ .child(
+ v_flex()
+ .relative()
+ .w_full()
+ .max_w_1_2()
+ .child(Label::new(action_link.title.clone()))
+ .when_some(
+ action_link.description.as_ref(),
+ |this, description| {
+ this.child(
+ Label::new(description.clone())
+ .size(LabelSize::Small)
+ .color(Color::Muted),
+ )
+ },
+ ),
+ )
+ .child(
+ Button::new(
+ ("action-link".into(), action_link.title.clone()),
+ action_link.button_text.clone(),
+ )
+ .icon(IconName::ArrowUpRight)
+ .tab_index(0_isize)
+ .icon_position(IconPosition::End)
+ .icon_color(Color::Muted)
+ .icon_size(IconSize::Small)
+ .style(ButtonStyle::OutlinedGhost)
+ .size(ButtonSize::Medium)
+ .on_click({
+ let on_click = action_link.on_click.clone();
+ cx.listener(move |this, _, window, cx| {
+ on_click(this, window, cx);
+ })
+ }),
+ ),
+ )
+ .when(!is_last, |this| this.child(Divider::horizontal()))
+ .into_any_element(),
}
}
}
@@ -1207,6 +1260,20 @@ impl PartialEq for SubPageLink {
}
}
+#[derive(Clone)]
+struct ActionLink {
+ title: SharedString,
+ description: Option<SharedString>,
+ button_text: SharedString,
+ on_click: Arc<dyn Fn(&mut SettingsWindow, &mut Window, &mut App) + Send + Sync>,
+}
+
+impl PartialEq for ActionLink {
+ fn eq(&self, other: &Self) -> bool {
+ self.title == other.title
+ }
+}
+
fn all_language_names(cx: &App) -> Vec<SharedString> {
workspace::AppState::global(cx)
.upgrade()
@@ -1626,6 +1693,9 @@ impl SettingsWindow {
any_found_since_last_header = true;
}
}
+ SettingsPageItem::ActionLink(_) => {
+ any_found_since_last_header = true;
+ }
}
}
if let Some(last_header) = page_filter.get_mut(header_index)
@@ -1864,6 +1934,18 @@ impl SettingsWindow {
sub_page_link.title.as_ref(),
);
}
+ SettingsPageItem::ActionLink(action_link) => {
+ documents.push(bm25::Document {
+ id: key_index,
+ contents: [page.title, header_str, action_link.title.as_ref()]
+ .join("\n"),
+ });
+ push_candidates(
+ &mut fuzzy_match_candidates,
+ key_index,
+ action_link.title.as_ref(),
+ );
+ }
}
push_candidates(&mut fuzzy_match_candidates, key_index, page.title);
push_candidates(&mut fuzzy_match_candidates, key_index, header_str);