From c074bfd4417719ca34ba267bdd088597115b91f4 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Wed, 13 Sep 2023 14:27:19 -0700 Subject: [PATCH 1/4] Add select all command to the editor, equivalent to hitting cmd-d as many times as possible --- assets/keymaps/default.json | 3 +- crates/editor/src/editor.rs | 75 +++++++++++++++++++++++++++---------- 2 files changed, 58 insertions(+), 20 deletions(-) diff --git a/assets/keymaps/default.json b/assets/keymaps/default.json index 14b9d01b21513a2699c7533964c8c8375c4a7bd3..8ac4fcbf8dcd05c37fca7914792e15179e858632 100644 --- a/assets/keymaps/default.json +++ b/assets/keymaps/default.json @@ -294,6 +294,7 @@ "replace_newest": false } ], + "cmd-shift-d": "editor::SelectNextAll", "ctrl-cmd-d": [ "editor::SelectPrevious", { @@ -453,7 +454,7 @@ "context": "Editor", "bindings": { "ctrl-shift-k": "editor::DeleteLine", - "cmd-shift-d": "editor::DuplicateLine", + // "cmd-shift-d": "editor::DuplicateLine", "cmd-shift-l": "editor::SplitSelectionIntoLines", "ctrl-j": "editor::JoinLines", "ctrl-cmd-up": "editor::MoveLineUp", diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 8c30859841f09d0ddad41a3d18046d98570b05b2..fa0663f2cf989664b0064778188d1a6aed5daed0 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -129,6 +129,12 @@ pub struct SelectPrevious { pub replace_newest: bool, } +#[derive(Clone, Deserialize, PartialEq, Default)] +pub struct SelectNextAll { + #[serde(default)] + pub replace_newest: bool, +} + #[derive(Clone, Deserialize, PartialEq)] pub struct SelectToBeginningOfLine { #[serde(default)] @@ -325,6 +331,7 @@ impl_actions!( [ SelectNext, SelectPrevious, + SelectNextAll, SelectToBeginningOfLine, SelectToEndOfLine, ToggleCodeActions, @@ -427,6 +434,7 @@ pub fn init(cx: &mut AppContext) { cx.add_action(Editor::select_to_beginning); cx.add_action(Editor::select_to_end); cx.add_action(Editor::select_all); + cx.add_action(Editor::select_all_matches); cx.add_action(Editor::select_line); cx.add_action(Editor::split_selection_into_lines); cx.add_action(Editor::add_selection_above); @@ -5936,9 +5944,27 @@ impl Editor { } } - pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext) -> Result<()> { - self.push_to_selection_history(); - let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + pub fn select_next_match_internal( + &mut self, + display_map: &DisplaySnapshot, + replace_newest: bool, + cx: &mut ViewContext, + ) { + fn select_next_match_ranges( + this: &mut Editor, + range: Range, + replace_newest: bool, + cx: &mut ViewContext, + ) { + this.unfold_ranges([range.clone()], false, true, cx); + this.change_selections(Some(Autoscroll::newest()), cx, |s| { + if replace_newest { + s.delete(s.newest_anchor().id); + } + s.insert_range(range.clone()); + }); + } + let buffer = &display_map.buffer_snapshot; let mut selections = self.selections.all::(cx); if let Some(mut select_next_state) = self.select_next_state.take() { @@ -5976,13 +6002,7 @@ impl Editor { } if let Some(next_selected_range) = next_selected_range { - self.unfold_ranges([next_selected_range.clone()], false, true, cx); - self.change_selections(Some(Autoscroll::newest()), cx, |s| { - if action.replace_newest { - s.delete(s.newest_anchor().id); - } - s.insert_range(next_selected_range); - }); + select_next_match_ranges(self, next_selected_range, replace_newest, cx); } else { select_next_state.done = true; } @@ -6009,10 +6029,7 @@ impl Editor { wordwise: true, done: false, }; - self.unfold_ranges([selection.start..selection.end], false, true, cx); - self.change_selections(Some(Autoscroll::newest()), cx, |s| { - s.select(selections); - }); + select_next_match_ranges(self, selection.start..selection.end, replace_newest, cx); self.select_next_state = Some(select_state); } else { let query = buffer @@ -6029,11 +6046,31 @@ impl Editor { Ok(()) } - pub fn select_previous( - &mut self, - action: &SelectPrevious, - cx: &mut ViewContext, - ) -> Result<()> { + pub fn select_all_matches(&mut self, action: &SelectNextAll, cx: &mut ViewContext) { + self.push_to_selection_history(); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + + loop { + self.select_next_match_internal(&display_map, action.replace_newest, cx); + + if self + .select_next_state + .as_ref() + .map(|selection_state| selection_state.done) + .unwrap_or(true) + { + break; + } + } + } + + pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext) { + self.push_to_selection_history(); + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + self.select_next_match_internal(&display_map, action.replace_newest, cx); + } + + pub fn select_previous(&mut self, action: &SelectPrevious, cx: &mut ViewContext) { self.push_to_selection_history(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = &display_map.buffer_snapshot; From 03d4191685d3f92ec1213ecd61bb84bbb80067ba Mon Sep 17 00:00:00 2001 From: Mikayla Date: Wed, 20 Sep 2023 08:00:55 -0700 Subject: [PATCH 2/4] Fix infinite loop in select all matches --- assets/keymaps/default.json | 2 +- crates/editor/src/editor.rs | 29 +++++++++++++++++++++++------ crates/text/src/selection.rs | 4 ++++ 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/assets/keymaps/default.json b/assets/keymaps/default.json index 8ac4fcbf8dcd05c37fca7914792e15179e858632..2fa5c0980f3d45e7acc62f218967c2327dadeea5 100644 --- a/assets/keymaps/default.json +++ b/assets/keymaps/default.json @@ -294,7 +294,7 @@ "replace_newest": false } ], - "cmd-shift-d": "editor::SelectNextAll", + "cmd-shift-d": "editor::SelectAllMatches", "ctrl-cmd-d": [ "editor::SelectPrevious", { diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index fa0663f2cf989664b0064778188d1a6aed5daed0..cc4af44a1a8f2bbd5b2f5188f85519581b09c724 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -130,7 +130,7 @@ pub struct SelectPrevious { } #[derive(Clone, Deserialize, PartialEq, Default)] -pub struct SelectNextAll { +pub struct SelectAllMatches { #[serde(default)] pub replace_newest: bool, } @@ -331,7 +331,7 @@ impl_actions!( [ SelectNext, SelectPrevious, - SelectNextAll, + SelectAllMatches, SelectToBeginningOfLine, SelectToEndOfLine, ToggleCodeActions, @@ -732,13 +732,22 @@ struct AddSelectionsState { stack: Vec, } -#[derive(Clone, Debug)] +#[derive(Clone)] struct SelectNextState { query: AhoCorasick, wordwise: bool, done: bool, } +impl std::fmt::Debug for SelectNextState { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct(std::any::type_name::()) + .field("wordwise", &self.wordwise) + .field("done", &self.done) + .finish() + } +} + #[derive(Debug)] struct AutocloseRegion { selection_id: usize, @@ -5985,7 +5994,9 @@ impl Editor { .stream_find_iter(bytes_before_first_selection) .map(|result| (0, result)), ); + for (start_offset, query_match) in query_matches { + (start_offset, &query_match); let query_match = query_match.unwrap(); // can only fail due to I/O let offset_range = start_offset + query_match.start()..start_offset + query_match.end(); @@ -5996,8 +6007,14 @@ impl Editor { || (!movement::is_inside_word(&display_map, display_range.start) && !movement::is_inside_word(&display_map, display_range.end)) { - next_selected_range = Some(offset_range); - break; + if selections + .iter() + .find(|selection| selection.equals(&offset_range)) + .is_none() + { + next_selected_range = Some(offset_range); + break; + } } } @@ -6046,7 +6063,7 @@ impl Editor { Ok(()) } - pub fn select_all_matches(&mut self, action: &SelectNextAll, cx: &mut ViewContext) { + pub fn select_all_matches(&mut self, action: &SelectAllMatches, cx: &mut ViewContext) { self.push_to_selection_history(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); diff --git a/crates/text/src/selection.rs b/crates/text/src/selection.rs index d4f55a043b334eb1819a9ec9393538a7bda42c28..205c27239d90699257816b5edfe3f6e38fa34dec 100644 --- a/crates/text/src/selection.rs +++ b/crates/text/src/selection.rs @@ -100,6 +100,10 @@ impl Selection { reversed: false, } } + + pub fn equals(&self, offset_range: &Range) -> bool { + self.start == offset_range.start && self.end == offset_range.end + } } impl Selection { From 8cc7a023906a283b91b84bd790106500497779aa Mon Sep 17 00:00:00 2001 From: Mikayla Date: Wed, 20 Sep 2023 08:30:37 -0700 Subject: [PATCH 3/4] Fix rebase --- assets/keymaps/default.json | 1 - crates/editor/src/editor.rs | 26 ++++++++++++++++++-------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/assets/keymaps/default.json b/assets/keymaps/default.json index 2fa5c0980f3d45e7acc62f218967c2327dadeea5..68fe4b997e8be04406711e6b933edcef63c6d6a3 100644 --- a/assets/keymaps/default.json +++ b/assets/keymaps/default.json @@ -454,7 +454,6 @@ "context": "Editor", "bindings": { "ctrl-shift-k": "editor::DeleteLine", - // "cmd-shift-d": "editor::DuplicateLine", "cmd-shift-l": "editor::SplitSelectionIntoLines", "ctrl-j": "editor::JoinLines", "ctrl-cmd-up": "editor::MoveLineUp", diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index cc4af44a1a8f2bbd5b2f5188f85519581b09c724..455088a5137256a578e35c16c66cae2e26a333ce 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -5958,7 +5958,7 @@ impl Editor { display_map: &DisplaySnapshot, replace_newest: bool, cx: &mut ViewContext, - ) { + ) -> Result<()> { fn select_next_match_ranges( this: &mut Editor, range: Range, @@ -5996,7 +5996,6 @@ impl Editor { ); for (start_offset, query_match) in query_matches { - (start_offset, &query_match); let query_match = query_match.unwrap(); // can only fail due to I/O let offset_range = start_offset + query_match.start()..start_offset + query_match.end(); @@ -6057,18 +6056,22 @@ impl Editor { wordwise: false, done: false, }); - self.select_next(action, cx)?; + self.select_next_match_internal(display_map, replace_newest, cx)?; } } Ok(()) } - pub fn select_all_matches(&mut self, action: &SelectAllMatches, cx: &mut ViewContext) { + pub fn select_all_matches( + &mut self, + action: &SelectAllMatches, + cx: &mut ViewContext, + ) -> Result<()> { self.push_to_selection_history(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); loop { - self.select_next_match_internal(&display_map, action.replace_newest, cx); + self.select_next_match_internal(&display_map, action.replace_newest, cx)?; if self .select_next_state @@ -6079,15 +6082,22 @@ impl Editor { break; } } + + Ok(()) } - pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext) { + pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext) -> Result<()> { self.push_to_selection_history(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - self.select_next_match_internal(&display_map, action.replace_newest, cx); + self.select_next_match_internal(&display_map, action.replace_newest, cx)?; + Ok(()) } - pub fn select_previous(&mut self, action: &SelectPrevious, cx: &mut ViewContext) { + pub fn select_previous( + &mut self, + action: &SelectPrevious, + cx: &mut ViewContext, + ) -> Result<()> { self.push_to_selection_history(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = &display_map.buffer_snapshot; From fdf5278bbf573cf89d5b1ff40cb1caf3bbcdb1fd Mon Sep 17 00:00:00 2001 From: Mikayla Date: Wed, 20 Sep 2023 09:31:12 -0700 Subject: [PATCH 4/4] Only autoscroll on select_next operations --- crates/editor/src/editor.rs | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 455088a5137256a578e35c16c66cae2e26a333ce..29782eb1f35949b51ecd9d3d9bead041634ac3b4 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -5957,16 +5957,18 @@ impl Editor { &mut self, display_map: &DisplaySnapshot, replace_newest: bool, + autoscroll: Option, cx: &mut ViewContext, ) -> Result<()> { fn select_next_match_ranges( this: &mut Editor, range: Range, replace_newest: bool, + auto_scroll: Option, cx: &mut ViewContext, ) { this.unfold_ranges([range.clone()], false, true, cx); - this.change_selections(Some(Autoscroll::newest()), cx, |s| { + this.change_selections(auto_scroll, cx, |s| { if replace_newest { s.delete(s.newest_anchor().id); } @@ -6018,7 +6020,13 @@ impl Editor { } if let Some(next_selected_range) = next_selected_range { - select_next_match_ranges(self, next_selected_range, replace_newest, cx); + select_next_match_ranges( + self, + next_selected_range, + replace_newest, + autoscroll, + cx, + ); } else { select_next_state.done = true; } @@ -6045,7 +6053,13 @@ impl Editor { wordwise: true, done: false, }; - select_next_match_ranges(self, selection.start..selection.end, replace_newest, cx); + select_next_match_ranges( + self, + selection.start..selection.end, + replace_newest, + autoscroll, + cx, + ); self.select_next_state = Some(select_state); } else { let query = buffer @@ -6056,7 +6070,7 @@ impl Editor { wordwise: false, done: false, }); - self.select_next_match_internal(display_map, replace_newest, cx)?; + self.select_next_match_internal(display_map, replace_newest, autoscroll, cx)?; } } Ok(()) @@ -6071,7 +6085,7 @@ impl Editor { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); loop { - self.select_next_match_internal(&display_map, action.replace_newest, cx)?; + self.select_next_match_internal(&display_map, action.replace_newest, None, cx)?; if self .select_next_state @@ -6089,7 +6103,12 @@ impl Editor { pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext) -> Result<()> { self.push_to_selection_history(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - self.select_next_match_internal(&display_map, action.replace_newest, cx)?; + self.select_next_match_internal( + &display_map, + action.replace_newest, + Some(Autoscroll::newest()), + cx, + )?; Ok(()) }