Merge pull request #786 from zed-industries/load-keymaps

Allow key bindings to be customized via a JSON file
This commit is contained in:
Max Brunsfeld 2022-04-11 17:31:22 -07:00 committed by GitHub
commit 25e1e3d2df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
74 changed files with 1092 additions and 729 deletions

View file

@ -20,6 +20,7 @@ workspace = { path = "../workspace" }
anyhow = "1.0"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
postage = { version = "0.4.1", features = ["futures-traits"] }
serde = { version = "1", features = ["derive"] }
[dev-dependencies]
editor = { path = "../editor", features = ["test-support"] }

View file

@ -1,55 +1,46 @@
use crate::{active_match_index, match_index_for_direction, Direction, SearchOption, SelectMatch};
use crate::{
active_match_index, match_index_for_direction, Direction, SearchOption, SelectNextMatch,
SelectPrevMatch,
};
use collections::HashMap;
use editor::{display_map::ToDisplayPoint, Anchor, Autoscroll, Bias, Editor};
use gpui::{
actions, elements::*, impl_actions, keymap::Binding, platform::CursorStyle, AppContext, Entity,
MutableAppContext, RenderContext, Subscription, Task, View, ViewContext, ViewHandle,
actions, elements::*, impl_actions, impl_internal_actions, platform::CursorStyle, AppContext,
Entity, MutableAppContext, RenderContext, Subscription, Task, View, ViewContext, ViewHandle,
WeakViewHandle,
};
use language::OffsetRangeExt;
use project::search::SearchQuery;
use serde::Deserialize;
use settings::Settings;
use std::ops::Range;
use workspace::{ItemHandle, Pane, ToolbarItemLocation, ToolbarItemView};
#[derive(Clone)]
pub struct Deploy(pub bool);
#[derive(Clone, Deserialize)]
pub struct Deploy {
pub focus: bool,
}
#[derive(Clone)]
pub struct ToggleSearchOption(pub SearchOption);
actions!(buffer_search, [Dismiss, FocusEditor]);
impl_actions!(buffer_search, [Deploy, ToggleSearchOption]);
impl_actions!(buffer_search, [Deploy]);
impl_internal_actions!(buffer_search, [ToggleSearchOption]);
pub enum Event {
UpdateLocation,
}
pub fn init(cx: &mut MutableAppContext) {
cx.add_bindings([
Binding::new("cmd-f", Deploy(true), Some("Editor && mode == full")),
Binding::new("cmd-e", Deploy(false), Some("Editor && mode == full")),
Binding::new("escape", Dismiss, Some("BufferSearchBar")),
Binding::new("cmd-f", FocusEditor, Some("BufferSearchBar")),
Binding::new(
"enter",
SelectMatch(Direction::Next),
Some("BufferSearchBar"),
),
Binding::new(
"shift-enter",
SelectMatch(Direction::Prev),
Some("BufferSearchBar"),
),
Binding::new("cmd-g", SelectMatch(Direction::Next), Some("Pane")),
Binding::new("cmd-shift-G", SelectMatch(Direction::Prev), Some("Pane")),
]);
cx.add_action(BufferSearchBar::deploy);
cx.add_action(BufferSearchBar::dismiss);
cx.add_action(BufferSearchBar::focus_editor);
cx.add_action(BufferSearchBar::toggle_search_option);
cx.add_action(BufferSearchBar::select_match);
cx.add_action(BufferSearchBar::select_match_on_pane);
cx.add_action(BufferSearchBar::select_next_match);
cx.add_action(BufferSearchBar::select_prev_match);
cx.add_action(BufferSearchBar::select_next_match_on_pane);
cx.add_action(BufferSearchBar::select_prev_match_on_pane);
}
pub struct BufferSearchBar {
@ -325,14 +316,17 @@ impl BufferSearchBar {
.with_style(style.container)
.boxed()
})
.on_click(move |cx| cx.dispatch_action(SelectMatch(direction)))
.on_click(move |cx| match direction {
Direction::Prev => cx.dispatch_action(SelectPrevMatch),
Direction::Next => cx.dispatch_action(SelectNextMatch),
})
.with_cursor_style(CursorStyle::PointingHand)
.boxed()
}
fn deploy(pane: &mut Pane, Deploy(focus): &Deploy, cx: &mut ViewContext<Pane>) {
fn deploy(pane: &mut Pane, action: &Deploy, cx: &mut ViewContext<Pane>) {
if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<BufferSearchBar>() {
if search_bar.update(cx, |search_bar, cx| search_bar.show(*focus, cx)) {
if search_bar.update(cx, |search_bar, cx| search_bar.show(action.focus, cx)) {
return;
}
}
@ -368,7 +362,15 @@ impl BufferSearchBar {
cx.notify();
}
fn select_match(&mut self, &SelectMatch(direction): &SelectMatch, cx: &mut ViewContext<Self>) {
fn select_next_match(&mut self, _: &SelectNextMatch, cx: &mut ViewContext<Self>) {
self.select_match(Direction::Next, cx);
}
fn select_prev_match(&mut self, _: &SelectPrevMatch, cx: &mut ViewContext<Self>) {
self.select_match(Direction::Prev, cx);
}
fn select_match(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
if let Some(index) = self.active_match_index {
if let Some(editor) = self.active_editor.as_ref() {
editor.update(cx, |editor, cx| {
@ -389,9 +391,23 @@ impl BufferSearchBar {
}
}
fn select_match_on_pane(pane: &mut Pane, action: &SelectMatch, cx: &mut ViewContext<Pane>) {
fn select_next_match_on_pane(
pane: &mut Pane,
action: &SelectNextMatch,
cx: &mut ViewContext<Pane>,
) {
if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<BufferSearchBar>() {
search_bar.update(cx, |search_bar, cx| search_bar.select_match(action, cx));
search_bar.update(cx, |bar, cx| bar.select_next_match(action, cx));
}
}
fn select_prev_match_on_pane(
pane: &mut Pane,
action: &SelectPrevMatch,
cx: &mut ViewContext<Pane>,
) {
if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<BufferSearchBar>() {
search_bar.update(cx, |bar, cx| bar.select_prev_match(action, cx));
}
}
@ -699,7 +715,7 @@ mod tests {
});
search_bar.update(cx, |search_bar, cx| {
assert_eq!(search_bar.active_match_index, Some(0));
search_bar.select_match(&SelectMatch(Direction::Next), cx);
search_bar.select_next_match(&SelectNextMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
[DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)]
@ -710,7 +726,7 @@ mod tests {
});
search_bar.update(cx, |search_bar, cx| {
search_bar.select_match(&SelectMatch(Direction::Next), cx);
search_bar.select_next_match(&SelectNextMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
[DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13)]
@ -721,7 +737,7 @@ mod tests {
});
search_bar.update(cx, |search_bar, cx| {
search_bar.select_match(&SelectMatch(Direction::Next), cx);
search_bar.select_next_match(&SelectNextMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
[DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)]
@ -732,7 +748,7 @@ mod tests {
});
search_bar.update(cx, |search_bar, cx| {
search_bar.select_match(&SelectMatch(Direction::Next), cx);
search_bar.select_next_match(&SelectNextMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
[DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)]
@ -743,7 +759,7 @@ mod tests {
});
search_bar.update(cx, |search_bar, cx| {
search_bar.select_match(&SelectMatch(Direction::Prev), cx);
search_bar.select_prev_match(&SelectPrevMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
[DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)]
@ -754,7 +770,7 @@ mod tests {
});
search_bar.update(cx, |search_bar, cx| {
search_bar.select_match(&SelectMatch(Direction::Prev), cx);
search_bar.select_prev_match(&SelectPrevMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
[DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13)]
@ -765,7 +781,7 @@ mod tests {
});
search_bar.update(cx, |search_bar, cx| {
search_bar.select_match(&SelectMatch(Direction::Prev), cx);
search_bar.select_prev_match(&SelectPrevMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
[DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)]
@ -782,7 +798,7 @@ mod tests {
});
search_bar.update(cx, |search_bar, cx| {
assert_eq!(search_bar.active_match_index, Some(1));
search_bar.select_match(&SelectMatch(Direction::Prev), cx);
search_bar.select_prev_match(&SelectPrevMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
[DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)]
@ -799,7 +815,7 @@ mod tests {
});
search_bar.update(cx, |search_bar, cx| {
assert_eq!(search_bar.active_match_index, Some(1));
search_bar.select_match(&SelectMatch(Direction::Next), cx);
search_bar.select_next_match(&SelectNextMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
[DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13)]
@ -816,7 +832,7 @@ mod tests {
});
search_bar.update(cx, |search_bar, cx| {
assert_eq!(search_bar.active_match_index, Some(2));
search_bar.select_match(&SelectMatch(Direction::Prev), cx);
search_bar.select_prev_match(&SelectPrevMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
[DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)]
@ -833,7 +849,7 @@ mod tests {
});
search_bar.update(cx, |search_bar, cx| {
assert_eq!(search_bar.active_match_index, Some(2));
search_bar.select_match(&SelectMatch(Direction::Next), cx);
search_bar.select_next_match(&SelectNextMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
[DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)]
@ -850,7 +866,7 @@ mod tests {
});
search_bar.update(cx, |search_bar, cx| {
assert_eq!(search_bar.active_match_index, Some(0));
search_bar.select_match(&SelectMatch(Direction::Prev), cx);
search_bar.select_prev_match(&SelectPrevMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
[DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)]

View file

@ -1,13 +1,13 @@
use crate::{
active_match_index, match_index_for_direction, Direction, SearchOption, SelectMatch,
ToggleSearchOption,
active_match_index, match_index_for_direction, Direction, SearchOption, SelectNextMatch,
SelectPrevMatch, ToggleSearchOption,
};
use collections::HashMap;
use editor::{Anchor, Autoscroll, Editor, MultiBuffer, SelectAll};
use gpui::{
actions, elements::*, keymap::Binding, platform::CursorStyle, AppContext, ElementBox, Entity,
ModelContext, ModelHandle, MutableAppContext, RenderContext, Subscription, Task, View,
ViewContext, ViewHandle, WeakModelHandle, WeakViewHandle,
actions, elements::*, platform::CursorStyle, AppContext, ElementBox, Entity, ModelContext,
ModelHandle, MutableAppContext, RenderContext, Subscription, Task, View, ViewContext,
ViewHandle, WeakModelHandle, WeakViewHandle,
};
use project::{search::SearchQuery, Project};
use settings::Settings;
@ -28,20 +28,12 @@ struct ActiveSearches(HashMap<WeakModelHandle<Project>, WeakViewHandle<ProjectSe
pub fn init(cx: &mut MutableAppContext) {
cx.set_global(ActiveSearches::default());
cx.add_bindings([
Binding::new("cmd-shift-F", ToggleFocus, Some("Pane")),
Binding::new("cmd-f", ToggleFocus, Some("Pane")),
Binding::new("cmd-shift-F", Deploy, Some("Workspace")),
Binding::new("enter", Search, Some("ProjectSearchBar")),
Binding::new("cmd-enter", SearchInNew, Some("ProjectSearchBar")),
Binding::new("cmd-g", SelectMatch(Direction::Next), Some("Pane")),
Binding::new("cmd-shift-G", SelectMatch(Direction::Prev), Some("Pane")),
]);
cx.add_action(ProjectSearchView::deploy);
cx.add_action(ProjectSearchBar::search);
cx.add_action(ProjectSearchBar::search_in_new);
cx.add_action(ProjectSearchBar::toggle_search_option);
cx.add_action(ProjectSearchBar::select_match);
cx.add_action(ProjectSearchBar::select_next_match);
cx.add_action(ProjectSearchBar::select_prev_match);
cx.add_action(ProjectSearchBar::toggle_focus);
cx.capture_action(ProjectSearchBar::tab);
}
@ -561,18 +553,23 @@ impl ProjectSearchBar {
}
}
fn select_match(
pane: &mut Pane,
&SelectMatch(direction): &SelectMatch,
cx: &mut ViewContext<Pane>,
) {
fn select_next_match(pane: &mut Pane, _: &SelectNextMatch, cx: &mut ViewContext<Pane>) {
if let Some(search_view) = pane
.active_item()
.and_then(|item| item.downcast::<ProjectSearchView>())
{
search_view.update(cx, |search_view, cx| {
search_view.select_match(direction, cx);
});
search_view.update(cx, |view, cx| view.select_match(Direction::Next, cx));
} else {
cx.propagate_action();
}
}
fn select_prev_match(pane: &mut Pane, _: &SelectPrevMatch, cx: &mut ViewContext<Pane>) {
if let Some(search_view) = pane
.active_item()
.and_then(|item| item.downcast::<ProjectSearchView>())
{
search_view.update(cx, |view, cx| view.select_match(Direction::Prev, cx));
} else {
cx.propagate_action();
}
@ -651,7 +648,10 @@ impl ProjectSearchBar {
.with_style(style.container)
.boxed()
})
.on_click(move |cx| cx.dispatch_action(SelectMatch(direction)))
.on_click(move |cx| match direction {
Direction::Prev => cx.dispatch_action(SelectPrevMatch),
Direction::Next => cx.dispatch_action(SelectNextMatch),
})
.with_cursor_style(CursorStyle::PointingHand)
.boxed()
}

View file

@ -1,6 +1,6 @@
pub use buffer_search::BufferSearchBar;
use editor::{Anchor, MultiBufferSnapshot};
use gpui::{impl_actions, MutableAppContext};
use gpui::{actions, impl_internal_actions, MutableAppContext};
pub use project_search::{ProjectSearchBar, ProjectSearchView};
use std::{
cmp::{self, Ordering},
@ -18,10 +18,8 @@ pub fn init(cx: &mut MutableAppContext) {
#[derive(Clone)]
pub struct ToggleSearchOption(pub SearchOption);
#[derive(Clone)]
pub struct SelectMatch(pub Direction);
impl_actions!(search, [ToggleSearchOption, SelectMatch]);
actions!(search, [SelectNextMatch, SelectPrevMatch]);
impl_internal_actions!(search, [ToggleSearchOption]);
#[derive(Clone, Copy)]
pub enum SearchOption {