Skip to content

Commit

Permalink
Select all matches (#2717)
Browse files Browse the repository at this point in the history
Closes https://github.com/zed-industries/community/issues/75
Closes https://github.com/zed-industries/community/issues/1749

The PR 

* changes keybindings for `Editor && mode == auto_height` context:
before, `alt-enter` and `alt-shift-enter` added new lines in such
editors, including the one from buffer search.

New bindings are the same as in `Editor && mode == full` context.

* adds `search::SelectAllMatches` action and binds it to `Alt + Enter`
by default, to select all matches of a buffer search

The behavior mimics VSCode: we do not move the screen even if all
selections are out of the visible range (Cmd+G will navigate there) and
allow reselecting the results from both pane and search field, as long
as the search is not dismissed.

Release Notes:

- Added `search::SelectAllMatches` (`Alt + Enter` default) action to
place carets and select all buffer search results
([#75](https://github.com/zed-industries/community/issues/75),
[#1749](https://github.com/zed-industries/community/issues/1749)).
  • Loading branch information
SomeoneToIgnore committed Jul 14, 2023
2 parents 0f54893 + b14cd5f commit cde5b39
Show file tree
Hide file tree
Showing 12 changed files with 337 additions and 31 deletions.
8 changes: 5 additions & 3 deletions assets/keymaps/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,8 @@
{
"context": "Editor && mode == auto_height",
"bindings": {
"alt-enter": "editor::Newline",
"cmd-alt-enter": "editor::NewlineBelow"
"shift-enter": "editor::Newline",
"cmd-shift-enter": "editor::NewlineBelow"
}
},
{
Expand All @@ -221,7 +221,8 @@
"escape": "buffer_search::Dismiss",
"tab": "buffer_search::FocusEditor",
"enter": "search::SelectNextMatch",
"shift-enter": "search::SelectPrevMatch"
"shift-enter": "search::SelectPrevMatch",
"alt-enter": "search::SelectAllMatches"
}
},
{
Expand All @@ -242,6 +243,7 @@
"cmd-f": "project_search::ToggleFocus",
"cmd-g": "search::SelectNextMatch",
"cmd-shift-g": "search::SelectPrevMatch",
"alt-enter": "search::SelectAllMatches",
"alt-cmd-c": "search::ToggleCaseSensitive",
"alt-cmd-w": "search::ToggleWholeWord",
"alt-cmd-r": "search::ToggleRegex"
Expand Down
37 changes: 32 additions & 5 deletions crates/editor/src/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -887,10 +887,20 @@ pub(crate) enum BufferSearchHighlights {}
impl SearchableItem for Editor {
type Match = Range<Anchor>;

fn to_search_event(event: &Self::Event) -> Option<SearchEvent> {
fn to_search_event(
&mut self,
event: &Self::Event,
_: &mut ViewContext<Self>,
) -> Option<SearchEvent> {
match event {
Event::BufferEdited => Some(SearchEvent::MatchesInvalidated),
Event::SelectionsChanged { .. } => Some(SearchEvent::ActiveMatchChanged),
Event::SelectionsChanged { .. } => {
if self.selections.disjoint_anchors().len() == 1 {
Some(SearchEvent::ActiveMatchChanged)
} else {
None
}
}
_ => None,
}
}
Expand Down Expand Up @@ -941,6 +951,11 @@ impl SearchableItem for Editor {
});
}

fn select_matches(&mut self, matches: Vec<Self::Match>, cx: &mut ViewContext<Self>) {
self.unfold_ranges(matches.clone(), false, false, cx);
self.change_selections(None, cx, |s| s.select_ranges(matches));
}

fn match_index_for_direction(
&mut self,
matches: &Vec<Range<Anchor>>,
Expand All @@ -949,16 +964,28 @@ impl SearchableItem for Editor {
cx: &mut ViewContext<Self>,
) -> usize {
let buffer = self.buffer().read(cx).snapshot(cx);
let cursor = self.selections.newest_anchor().head();
if matches[current_index].start.cmp(&cursor, &buffer).is_gt() {
let current_index_position = if self.selections.disjoint_anchors().len() == 1 {
self.selections.newest_anchor().head()
} else {
matches[current_index].start
};
if matches[current_index]
.start
.cmp(&current_index_position, &buffer)
.is_gt()
{
if direction == Direction::Prev {
if current_index == 0 {
current_index = matches.len() - 1;
} else {
current_index -= 1;
}
}
} else if matches[current_index].end.cmp(&cursor, &buffer).is_lt() {
} else if matches[current_index]
.end
.cmp(&current_index_position, &buffer)
.is_lt()
{
if direction == Direction::Next {
current_index = 0;
}
Expand Down
4 changes: 2 additions & 2 deletions crates/editor/src/selections_collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ use crate::{
Anchor, DisplayPoint, ExcerptId, MultiBuffer, MultiBufferSnapshot, SelectMode, ToOffset,
};

#[derive(Clone)]
#[derive(Debug, Clone)]
pub struct PendingSelection {
pub selection: Selection<Anchor>,
pub mode: SelectMode,
}

#[derive(Clone)]
#[derive(Debug, Clone)]
pub struct SelectionsCollection {
display_map: ModelHandle<DisplayMap>,
buffer: ModelHandle<MultiBuffer>,
Expand Down
14 changes: 12 additions & 2 deletions crates/feedback/src/feedback_editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,13 @@ impl Item for FeedbackEditor {
impl SearchableItem for FeedbackEditor {
type Match = Range<Anchor>;

fn to_search_event(event: &Self::Event) -> Option<workspace::searchable::SearchEvent> {
Editor::to_search_event(event)
fn to_search_event(
&mut self,
event: &Self::Event,
cx: &mut ViewContext<Self>,
) -> Option<workspace::searchable::SearchEvent> {
self.editor
.update(cx, |editor, cx| editor.to_search_event(event, cx))
}

fn clear_matches(&mut self, cx: &mut ViewContext<Self>) {
Expand Down Expand Up @@ -391,6 +396,11 @@ impl SearchableItem for FeedbackEditor {
.update(cx, |editor, cx| editor.activate_match(index, matches, cx))
}

fn select_matches(&mut self, matches: Vec<Self::Match>, cx: &mut ViewContext<Self>) {
self.editor
.update(cx, |e, cx| e.select_matches(matches, cx))
}

fn find_matches(
&mut self,
query: project::search::SearchQuery,
Expand Down
14 changes: 12 additions & 2 deletions crates/language_tools/src/lsp_log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,13 @@ impl Item for LspLogView {
impl SearchableItem for LspLogView {
type Match = <Editor as SearchableItem>::Match;

fn to_search_event(event: &Self::Event) -> Option<workspace::searchable::SearchEvent> {
Editor::to_search_event(event)
fn to_search_event(
&mut self,
event: &Self::Event,
cx: &mut ViewContext<Self>,
) -> Option<workspace::searchable::SearchEvent> {
self.editor
.update(cx, |editor, cx| editor.to_search_event(event, cx))
}

fn clear_matches(&mut self, cx: &mut ViewContext<Self>) {
Expand All @@ -494,6 +499,11 @@ impl SearchableItem for LspLogView {
.update(cx, |e, cx| e.activate_match(index, matches, cx))
}

fn select_matches(&mut self, matches: Vec<Self::Match>, cx: &mut ViewContext<Self>) {
self.editor
.update(cx, |e, cx| e.select_matches(matches, cx))
}

fn find_matches(
&mut self,
query: project::search::SearchQuery,
Expand Down
Loading

0 comments on commit cde5b39

Please sign in to comment.