Don't scroll the editor on select all matches (#28435)
Part of https://github.com/zed-industries/zed/issues/9309 Release Notes: - Improved scroll behavior of `editor: select all matches` --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev>
This commit is contained in:
parent
6aa0248ab3
commit
64de6bd2a8
2 changed files with 45 additions and 47 deletions
|
@ -11573,7 +11573,7 @@ impl Editor {
|
|||
window: &mut Window,
|
||||
cx: &mut Context<Editor>,
|
||||
) {
|
||||
this.unfold_ranges(&[range.clone()], false, true, cx);
|
||||
this.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
|
||||
this.change_selections(auto_scroll, window, cx, |s| {
|
||||
if replace_newest {
|
||||
s.delete(s.newest_anchor().id);
|
||||
|
@ -11748,16 +11748,21 @@ impl Editor {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let mut new_selections = self.selections.all::<usize>(cx);
|
||||
let mut new_selections = Vec::new();
|
||||
|
||||
let reversed = self.selections.oldest::<usize>(cx).reversed;
|
||||
let buffer = &display_map.buffer_snapshot;
|
||||
let query_matches = select_next_state
|
||||
.query
|
||||
.stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
|
||||
|
||||
for query_match in query_matches {
|
||||
let query_match = query_match.unwrap(); // can only fail due to I/O
|
||||
let offset_range = query_match.start()..query_match.end();
|
||||
for query_match in query_matches.into_iter() {
|
||||
let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
|
||||
let offset_range = if reversed {
|
||||
query_match.end()..query_match.start()
|
||||
} else {
|
||||
query_match.start()..query_match.end()
|
||||
};
|
||||
let display_range = offset_range.start.to_display_point(&display_map)
|
||||
..offset_range.end.to_display_point(&display_map);
|
||||
|
||||
|
@ -11765,52 +11770,14 @@ impl Editor {
|
|||
|| (!movement::is_inside_word(&display_map, display_range.start)
|
||||
&& !movement::is_inside_word(&display_map, display_range.end))
|
||||
{
|
||||
self.selections.change_with(cx, |selections| {
|
||||
new_selections.push(Selection {
|
||||
id: selections.new_selection_id(),
|
||||
start: offset_range.start,
|
||||
end: offset_range.end,
|
||||
reversed: false,
|
||||
goal: SelectionGoal::None,
|
||||
});
|
||||
});
|
||||
new_selections.push(offset_range.start..offset_range.end);
|
||||
}
|
||||
}
|
||||
|
||||
new_selections.sort_by_key(|selection| selection.start);
|
||||
let mut ix = 0;
|
||||
while ix + 1 < new_selections.len() {
|
||||
let current_selection = &new_selections[ix];
|
||||
let next_selection = &new_selections[ix + 1];
|
||||
if current_selection.range().overlaps(&next_selection.range()) {
|
||||
if current_selection.id < next_selection.id {
|
||||
new_selections.remove(ix + 1);
|
||||
} else {
|
||||
new_selections.remove(ix);
|
||||
}
|
||||
} else {
|
||||
ix += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let reversed = self.selections.oldest::<usize>(cx).reversed;
|
||||
|
||||
for selection in new_selections.iter_mut() {
|
||||
selection.reversed = reversed;
|
||||
}
|
||||
|
||||
select_next_state.done = true;
|
||||
self.unfold_ranges(
|
||||
&new_selections
|
||||
.iter()
|
||||
.map(|selection| selection.range())
|
||||
.collect::<Vec<_>>(),
|
||||
false,
|
||||
false,
|
||||
cx,
|
||||
);
|
||||
self.change_selections(Some(Autoscroll::fit()), window, cx, |selections| {
|
||||
selections.select(new_selections)
|
||||
self.unfold_ranges(&new_selections.clone(), false, false, cx);
|
||||
self.change_selections(None, window, cx, |selections| {
|
||||
selections.select_ranges(new_selections)
|
||||
});
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -5842,6 +5842,37 @@ async fn test_select_all_matches(cx: &mut TestAppContext) {
|
|||
cx.assert_editor_state("abc\n« ˇ»abc\nabc");
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_select_all_matches_does_not_scroll(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
|
||||
let large_body_1 = "\nd".repeat(200);
|
||||
let large_body_2 = "\ne".repeat(200);
|
||||
|
||||
cx.set_state(&format!(
|
||||
"abc\nabc{large_body_1} «ˇa»bc{large_body_2}\nefabc\nabc"
|
||||
));
|
||||
let initial_scroll_position = cx.update_editor(|editor, _, cx| {
|
||||
let scroll_position = editor.scroll_position(cx);
|
||||
assert!(scroll_position.y > 0.0, "Initial selection is between two large bodies and should have the editor scrolled to it");
|
||||
scroll_position
|
||||
});
|
||||
|
||||
cx.update_editor(|e, window, cx| e.select_all_matches(&SelectAllMatches, window, cx))
|
||||
.unwrap();
|
||||
cx.assert_editor_state(&format!(
|
||||
"«ˇa»bc\n«ˇa»bc{large_body_1} «ˇa»bc{large_body_2}\nef«ˇa»bc\n«ˇa»bc"
|
||||
));
|
||||
let scroll_position_after_selection =
|
||||
cx.update_editor(|editor, _, cx| editor.scroll_position(cx));
|
||||
assert_eq!(
|
||||
initial_scroll_position, scroll_position_after_selection,
|
||||
"Scroll position should not change after selecting all matches"
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_select_next_with_multiple_carets(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue