Allow centering selections when requesting autoscroll

We use this new capability in the "go to line" modal.
This commit is contained in:
Antonio Scandurra 2021-11-24 19:50:47 +01:00
parent cea8107242
commit 53a7da9d3f
2 changed files with 112 additions and 91 deletions

View file

@ -311,6 +311,11 @@ enum SelectMode {
All, All,
} }
pub enum Autoscroll {
Closest,
Center,
}
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
pub enum EditorMode { pub enum EditorMode {
SingleLine, SingleLine,
@ -338,7 +343,7 @@ pub struct Editor {
active_diagnostics: Option<ActiveDiagnosticGroup>, active_diagnostics: Option<ActiveDiagnosticGroup>,
scroll_position: Vector2F, scroll_position: Vector2F,
scroll_top_anchor: Anchor, scroll_top_anchor: Anchor,
autoscroll_requested: bool, autoscroll_request: Option<Autoscroll>,
build_settings: Rc<RefCell<dyn Fn(&AppContext) -> EditorSettings>>, build_settings: Rc<RefCell<dyn Fn(&AppContext) -> EditorSettings>>,
focused: bool, focused: bool,
show_local_cursors: bool, show_local_cursors: bool,
@ -473,7 +478,7 @@ impl Editor {
build_settings, build_settings,
scroll_position: Vector2F::zero(), scroll_position: Vector2F::zero(),
scroll_top_anchor: Anchor::min(), scroll_top_anchor: Anchor::min(),
autoscroll_requested: false, autoscroll_request: None,
focused: false, focused: false,
show_local_cursors: false, show_local_cursors: false,
blink_epoch: 0, blink_epoch: 0,
@ -577,11 +582,11 @@ impl Editor {
self.set_scroll_position(scroll_position, cx); self.set_scroll_position(scroll_position, cx);
} }
if self.autoscroll_requested { let autoscroll = if let Some(autoscroll) = self.autoscroll_request.take() {
self.autoscroll_requested = false; autoscroll
} else { } else {
return false; return false;
} };
let mut selections = self.selections::<Point>(cx).peekable(); let mut selections = self.selections::<Point>(cx).peekable();
let first_cursor_top = selections let first_cursor_top = selections
@ -597,29 +602,35 @@ impl Editor {
.to_display_point(&display_map) .to_display_point(&display_map)
.row() as f32 .row() as f32
+ 1.0; + 1.0;
let margin = if matches!(self.mode, EditorMode::AutoHeight { .. }) { let margin = if matches!(self.mode, EditorMode::AutoHeight { .. }) {
0. 0.
} else { } else {
((visible_lines - (last_cursor_bottom - first_cursor_top)) / 2.0) ((visible_lines - (last_cursor_bottom - first_cursor_top)) / 2.0).floor()
.floor()
.min(3.0)
}; };
if margin < 0.0 { if margin < 0.0 {
return false; return false;
} }
let target_top = (first_cursor_top - margin).max(0.0); match autoscroll {
let target_bottom = last_cursor_bottom + margin; Autoscroll::Closest => {
let start_row = scroll_position.y(); let margin = margin.min(3.0);
let end_row = start_row + visible_lines; let target_top = (first_cursor_top - margin).max(0.0);
let target_bottom = last_cursor_bottom + margin;
let start_row = scroll_position.y();
let end_row = start_row + visible_lines;
if target_top < start_row { if target_top < start_row {
scroll_position.set_y(target_top); scroll_position.set_y(target_top);
self.set_scroll_position(scroll_position, cx); self.set_scroll_position(scroll_position, cx);
} else if target_bottom >= end_row { } else if target_bottom >= end_row {
scroll_position.set_y(target_bottom - visible_lines); scroll_position.set_y(target_bottom - visible_lines);
self.set_scroll_position(scroll_position, cx); self.set_scroll_position(scroll_position, cx);
}
}
Autoscroll::Center => {
scroll_position.set_y((first_cursor_top - margin).max(0.0));
self.set_scroll_position(scroll_position, cx);
}
} }
true true
@ -782,7 +793,7 @@ impl Editor {
}; };
if !add { if !add {
self.update_selections::<usize>(Vec::new(), false, cx); self.update_selections::<usize>(Vec::new(), None, cx);
} else if click_count > 1 { } else if click_count > 1 {
// Remove the newest selection since it was only added as part of this multi-click. // Remove the newest selection since it was only added as part of this multi-click.
let newest_selection = self.newest_selection::<usize>(cx); let newest_selection = self.newest_selection::<usize>(cx);
@ -790,7 +801,7 @@ impl Editor {
self.selections(cx) self.selections(cx)
.filter(|selection| selection.id != newest_selection.id) .filter(|selection| selection.id != newest_selection.id)
.collect(), .collect(),
false, None,
cx, cx,
) )
} }
@ -921,7 +932,7 @@ impl Editor {
self.columnar_selection_tail.take(); self.columnar_selection_tail.take();
if self.pending_selection.is_some() { if self.pending_selection.is_some() {
let selections = self.selections::<usize>(cx).collect::<Vec<_>>(); let selections = self.selections::<usize>(cx).collect::<Vec<_>>();
self.update_selections(selections, false, cx); self.update_selections(selections, None, cx);
} }
} }
@ -961,7 +972,7 @@ impl Editor {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
self.update_selections(selections, false, cx); self.update_selections(selections, None, cx);
cx.notify(); cx.notify();
} }
@ -982,7 +993,7 @@ impl Editor {
goal: selection.goal, goal: selection.goal,
}; };
if self.selections::<Point>(cx).next().is_none() { if self.selections::<Point>(cx).next().is_none() {
self.update_selections(vec![selection], true, cx); self.update_selections(vec![selection], Some(Autoscroll::Closest), cx);
} }
} else { } else {
let mut oldest_selection = self.oldest_selection::<usize>(cx); let mut oldest_selection = self.oldest_selection::<usize>(cx);
@ -990,12 +1001,16 @@ impl Editor {
oldest_selection.start = oldest_selection.head().clone(); oldest_selection.start = oldest_selection.head().clone();
oldest_selection.end = oldest_selection.head().clone(); oldest_selection.end = oldest_selection.head().clone();
} }
self.update_selections(vec![oldest_selection], true, cx); self.update_selections(vec![oldest_selection], Some(Autoscroll::Closest), cx);
} }
} }
pub fn select_ranges<I, T>(&mut self, ranges: I, autoscroll: bool, cx: &mut ViewContext<Self>) pub fn select_ranges<I, T>(
where &mut self,
ranges: I,
autoscroll: Option<Autoscroll>,
cx: &mut ViewContext<Self>,
) where
I: IntoIterator<Item = Range<T>>, I: IntoIterator<Item = Range<T>>,
T: ToOffset, T: ToOffset,
{ {
@ -1053,7 +1068,7 @@ impl Editor {
} }
}) })
.collect(); .collect();
self.update_selections(selections, false, cx); self.update_selections(selections, None, cx);
Ok(()) Ok(())
} }
@ -1179,7 +1194,7 @@ impl Editor {
)) ))
}); });
self.update_selections(new_selections, true, cx); self.update_selections(new_selections, Some(Autoscroll::Closest), cx);
self.end_transaction(cx); self.end_transaction(cx);
#[derive(Default)] #[derive(Default)]
@ -1219,7 +1234,7 @@ impl Editor {
.collect(); .collect();
}); });
self.update_selections(new_selections, true, cx); self.update_selections(new_selections, Some(Autoscroll::Closest), cx);
self.end_transaction(cx); self.end_transaction(cx);
} }
@ -1319,7 +1334,7 @@ impl Editor {
}) })
.collect(); .collect();
self.autoclose_stack.pop(); self.autoclose_stack.pop();
self.update_selections(new_selections, true, cx); self.update_selections(new_selections, Some(Autoscroll::Closest), cx);
true true
} else { } else {
false false
@ -1347,7 +1362,7 @@ impl Editor {
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
self.insert("", cx); self.insert("", cx);
self.end_transaction(cx); self.end_transaction(cx);
} }
@ -1366,7 +1381,7 @@ impl Editor {
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
self.insert(&"", cx); self.insert(&"", cx);
self.end_transaction(cx); self.end_transaction(cx);
} }
@ -1437,7 +1452,7 @@ impl Editor {
} }
}); });
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
self.end_transaction(cx); self.end_transaction(cx);
} }
@ -1481,7 +1496,11 @@ impl Editor {
buffer.edit(deletion_ranges, "", cx); buffer.edit(deletion_ranges, "", cx);
}); });
self.update_selections(self.selections::<usize>(cx).collect(), true, cx); self.update_selections(
self.selections::<usize>(cx).collect(),
Some(Autoscroll::Closest),
cx,
);
self.end_transaction(cx); self.end_transaction(cx);
} }
@ -1550,7 +1569,7 @@ impl Editor {
.collect(); .collect();
self.buffer self.buffer
.update(cx, |buffer, cx| buffer.edit(edit_ranges, "", cx)); .update(cx, |buffer, cx| buffer.edit(edit_ranges, "", cx));
self.update_selections(new_selections, true, cx); self.update_selections(new_selections, Some(Autoscroll::Closest), cx);
self.end_transaction(cx); self.end_transaction(cx);
} }
@ -1608,7 +1627,7 @@ impl Editor {
} }
}); });
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
self.end_transaction(cx); self.end_transaction(cx);
} }
@ -1697,7 +1716,7 @@ impl Editor {
} }
}); });
self.fold_ranges(new_folds, cx); self.fold_ranges(new_folds, cx);
self.select_ranges(new_selection_ranges, true, cx); self.select_ranges(new_selection_ranges, Some(Autoscroll::Closest), cx);
self.end_transaction(cx); self.end_transaction(cx);
} }
@ -1784,7 +1803,7 @@ impl Editor {
} }
}); });
self.fold_ranges(new_folds, cx); self.fold_ranges(new_folds, cx);
self.select_ranges(new_selection_ranges, true, cx); self.select_ranges(new_selection_ranges, Some(Autoscroll::Closest), cx);
self.end_transaction(cx); self.end_transaction(cx);
} }
@ -1814,7 +1833,7 @@ impl Editor {
}); });
} }
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
self.insert("", cx); self.insert("", cx);
self.end_transaction(cx); self.end_transaction(cx);
@ -1899,7 +1918,7 @@ impl Editor {
selection.end = selection.start; selection.end = selection.start;
}); });
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} else { } else {
self.insert(clipboard_text, cx); self.insert(clipboard_text, cx);
} }
@ -1908,12 +1927,12 @@ impl Editor {
pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) { pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
self.buffer.update(cx, |buffer, cx| buffer.undo(cx)); self.buffer.update(cx, |buffer, cx| buffer.undo(cx));
self.request_autoscroll(cx); self.request_autoscroll(Autoscroll::Closest, cx);
} }
pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) { pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
self.buffer.update(cx, |buffer, cx| buffer.redo(cx)); self.buffer.update(cx, |buffer, cx| buffer.redo(cx));
self.request_autoscroll(cx); self.request_autoscroll(Autoscroll::Closest, cx);
} }
pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) { pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
@ -1935,7 +1954,7 @@ impl Editor {
selection.reversed = false; selection.reversed = false;
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) { pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
@ -1949,7 +1968,7 @@ impl Editor {
selection.set_head(cursor); selection.set_head(cursor);
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) { pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
@ -1971,7 +1990,7 @@ impl Editor {
selection.reversed = false; selection.reversed = false;
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) { pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
@ -1985,7 +2004,7 @@ impl Editor {
selection.set_head(cursor); selection.set_head(cursor);
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) { pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
@ -2010,7 +2029,7 @@ impl Editor {
selection.goal = goal; selection.goal = goal;
selection.reversed = false; selection.reversed = false;
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) { pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
@ -2023,7 +2042,7 @@ impl Editor {
selection.set_head(cursor); selection.set_head(cursor);
selection.goal = goal; selection.goal = goal;
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) { pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
@ -2048,7 +2067,7 @@ impl Editor {
selection.goal = goal; selection.goal = goal;
selection.reversed = false; selection.reversed = false;
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) { pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
@ -2061,7 +2080,7 @@ impl Editor {
selection.set_head(cursor); selection.set_head(cursor);
selection.goal = goal; selection.goal = goal;
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn move_to_previous_word_boundary( pub fn move_to_previous_word_boundary(
@ -2079,7 +2098,7 @@ impl Editor {
selection.reversed = false; selection.reversed = false;
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn select_to_previous_word_boundary( pub fn select_to_previous_word_boundary(
@ -2095,7 +2114,7 @@ impl Editor {
selection.set_head(cursor); selection.set_head(cursor);
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn delete_to_previous_word_boundary( pub fn delete_to_previous_word_boundary(
@ -2115,7 +2134,7 @@ impl Editor {
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
self.insert("", cx); self.insert("", cx);
self.end_transaction(cx); self.end_transaction(cx);
} }
@ -2135,7 +2154,7 @@ impl Editor {
selection.reversed = false; selection.reversed = false;
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn select_to_next_word_boundary( pub fn select_to_next_word_boundary(
@ -2151,7 +2170,7 @@ impl Editor {
selection.set_head(cursor); selection.set_head(cursor);
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn delete_to_next_word_boundary( pub fn delete_to_next_word_boundary(
@ -2171,7 +2190,7 @@ impl Editor {
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
self.insert("", cx); self.insert("", cx);
self.end_transaction(cx); self.end_transaction(cx);
} }
@ -2192,7 +2211,7 @@ impl Editor {
selection.reversed = false; selection.reversed = false;
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn select_to_beginning_of_line( pub fn select_to_beginning_of_line(
@ -2208,7 +2227,7 @@ impl Editor {
selection.set_head(new_head.to_point(&display_map)); selection.set_head(new_head.to_point(&display_map));
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn delete_to_beginning_of_line( pub fn delete_to_beginning_of_line(
@ -2236,7 +2255,7 @@ impl Editor {
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn select_to_end_of_line(&mut self, _: &SelectToEndOfLine, cx: &mut ViewContext<Self>) { pub fn select_to_end_of_line(&mut self, _: &SelectToEndOfLine, cx: &mut ViewContext<Self>) {
@ -2248,7 +2267,7 @@ impl Editor {
selection.set_head(new_head.to_point(&display_map)); selection.set_head(new_head.to_point(&display_map));
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) { pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
@ -2273,13 +2292,13 @@ impl Editor {
reversed: false, reversed: false,
goal: SelectionGoal::None, goal: SelectionGoal::None,
}; };
self.update_selections(vec![selection], true, cx); self.update_selections(vec![selection], Some(Autoscroll::Closest), cx);
} }
pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) { pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
let mut selection = self.selections::<Point>(cx).last().unwrap().clone(); let mut selection = self.selections::<Point>(cx).last().unwrap().clone();
selection.set_head(Point::zero()); selection.set_head(Point::zero());
self.update_selections(vec![selection], true, cx); self.update_selections(vec![selection], Some(Autoscroll::Closest), cx);
} }
pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) { pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
@ -2292,13 +2311,13 @@ impl Editor {
reversed: false, reversed: false,
goal: SelectionGoal::None, goal: SelectionGoal::None,
}; };
self.update_selections(vec![selection], true, cx); self.update_selections(vec![selection], Some(Autoscroll::Closest), cx);
} }
pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) { pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
let mut selection = self.selections::<usize>(cx).last().unwrap().clone(); let mut selection = self.selections::<usize>(cx).last().unwrap().clone();
selection.set_head(self.buffer.read(cx).len()); selection.set_head(self.buffer.read(cx).len());
self.update_selections(vec![selection], true, cx); self.update_selections(vec![selection], Some(Autoscroll::Closest), cx);
} }
pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) { pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
@ -2309,7 +2328,7 @@ impl Editor {
reversed: false, reversed: false,
goal: SelectionGoal::None, goal: SelectionGoal::None,
}; };
self.update_selections(vec![selection], false, cx); self.update_selections(vec![selection], None, cx);
} }
pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) { pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
@ -2323,7 +2342,7 @@ impl Editor {
selection.end = cmp::min(max_point, Point::new(rows.end, 0)); selection.end = cmp::min(max_point, Point::new(rows.end, 0));
selection.reversed = false; selection.reversed = false;
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn split_selection_into_lines( pub fn split_selection_into_lines(
@ -2357,7 +2376,7 @@ impl Editor {
to_unfold.push(selection.start..selection.end); to_unfold.push(selection.start..selection.end);
} }
self.unfold_ranges(to_unfold, cx); self.unfold_ranges(to_unfold, cx);
self.update_selections(new_selections, true, cx); self.update_selections(new_selections, Some(Autoscroll::Closest), cx);
} }
pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) { pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
@ -2455,7 +2474,7 @@ impl Editor {
state.stack.pop(); state.stack.pop();
} }
self.update_selections(new_selections, true, cx); self.update_selections(new_selections, Some(Autoscroll::Closest), cx);
if state.stack.len() > 1 { if state.stack.len() > 1 {
self.add_selections_state = Some(state); self.add_selections_state = Some(state);
} }
@ -2547,7 +2566,11 @@ impl Editor {
} }
}); });
self.update_selections(self.selections::<usize>(cx).collect(), true, cx); self.update_selections(
self.selections::<usize>(cx).collect(),
Some(Autoscroll::Closest),
cx,
);
self.end_transaction(cx); self.end_transaction(cx);
} }
@ -2592,7 +2615,7 @@ impl Editor {
if selected_larger_node { if selected_larger_node {
stack.push(old_selections); stack.push(old_selections);
new_selections.sort_unstable_by_key(|selection| selection.start); new_selections.sort_unstable_by_key(|selection| selection.start);
self.update_selections(new_selections, true, cx); self.update_selections(new_selections, Some(Autoscroll::Closest), cx);
} }
self.select_larger_syntax_node_stack = stack; self.select_larger_syntax_node_stack = stack;
} }
@ -2604,7 +2627,7 @@ impl Editor {
) { ) {
let mut stack = mem::take(&mut self.select_larger_syntax_node_stack); let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
if let Some(selections) = stack.pop() { if let Some(selections) = stack.pop() {
self.update_selections(selections.to_vec(), true, cx); self.update_selections(selections.to_vec(), Some(Autoscroll::Closest), cx);
} }
self.select_larger_syntax_node_stack = stack; self.select_larger_syntax_node_stack = stack;
} }
@ -2633,7 +2656,7 @@ impl Editor {
} }
} }
self.update_selections(selections, true, cx); self.update_selections(selections, Some(Autoscroll::Closest), cx);
} }
pub fn show_next_diagnostic(&mut self, _: &ShowNextDiagnostic, cx: &mut ViewContext<Self>) { pub fn show_next_diagnostic(&mut self, _: &ShowNextDiagnostic, cx: &mut ViewContext<Self>) {
@ -2679,7 +2702,7 @@ impl Editor {
reversed: false, reversed: false,
goal: SelectionGoal::None, goal: SelectionGoal::None,
}], }],
true, Some(Autoscroll::Center),
cx, cx,
); );
break; break;
@ -3007,7 +3030,7 @@ impl Editor {
fn update_selections<T>( fn update_selections<T>(
&mut self, &mut self,
mut selections: Vec<Selection<T>>, mut selections: Vec<Selection<T>>,
autoscroll: bool, autoscroll: Option<Autoscroll>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) where ) where
T: ToOffset + ToPoint + Ord + std::marker::Copy + std::fmt::Debug, T: ToOffset + ToPoint + Ord + std::marker::Copy + std::fmt::Debug,
@ -3053,8 +3076,8 @@ impl Editor {
} }
} }
if autoscroll { if let Some(autoscroll) = autoscroll {
self.request_autoscroll(cx); self.request_autoscroll(autoscroll, cx);
} }
self.pause_cursor_blinking(cx); self.pause_cursor_blinking(cx);
@ -3065,8 +3088,8 @@ impl Editor {
}); });
} }
fn request_autoscroll(&mut self, cx: &mut ViewContext<Self>) { fn request_autoscroll(&mut self, autoscroll: Autoscroll, cx: &mut ViewContext<Self>) {
self.autoscroll_requested = true; self.autoscroll_request = Some(autoscroll);
cx.notify(); cx.notify();
} }
@ -3189,7 +3212,7 @@ impl Editor {
fn fold_ranges<T: ToOffset>(&mut self, ranges: Vec<Range<T>>, cx: &mut ViewContext<Self>) { fn fold_ranges<T: ToOffset>(&mut self, ranges: Vec<Range<T>>, cx: &mut ViewContext<Self>) {
if !ranges.is_empty() { if !ranges.is_empty() {
self.display_map.update(cx, |map, cx| map.fold(ranges, cx)); self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
self.autoscroll_requested = true; self.request_autoscroll(Autoscroll::Closest, cx);
cx.notify(); cx.notify();
} }
} }
@ -3198,7 +3221,7 @@ impl Editor {
if !ranges.is_empty() { if !ranges.is_empty() {
self.display_map self.display_map
.update(cx, |map, cx| map.unfold(ranges, cx)); .update(cx, |map, cx| map.unfold(ranges, cx));
self.autoscroll_requested = true; self.request_autoscroll(Autoscroll::Closest, cx);
cx.notify(); cx.notify();
} }
} }
@ -4698,14 +4721,14 @@ mod tests {
// Cut with three selections. Clipboard text is divided into three slices. // Cut with three selections. Clipboard text is divided into three slices.
view.update(cx, |view, cx| { view.update(cx, |view, cx| {
view.select_ranges(vec![0..7, 11..17, 22..27], false, cx); view.select_ranges(vec![0..7, 11..17, 22..27], None, cx);
view.cut(&Cut, cx); view.cut(&Cut, cx);
assert_eq!(view.display_text(cx), "two four six "); assert_eq!(view.display_text(cx), "two four six ");
}); });
// Paste with three cursors. Each cursor pastes one slice of the clipboard text. // Paste with three cursors. Each cursor pastes one slice of the clipboard text.
view.update(cx, |view, cx| { view.update(cx, |view, cx| {
view.select_ranges(vec![4..4, 9..9, 13..13], false, cx); view.select_ranges(vec![4..4, 9..9, 13..13], None, cx);
view.paste(&Paste, cx); view.paste(&Paste, cx);
assert_eq!(view.display_text(cx), "two one✅ four three six five "); assert_eq!(view.display_text(cx), "two one✅ four three six five ");
assert_eq!( assert_eq!(
@ -4722,7 +4745,7 @@ mod tests {
// match the number of slices in the clipboard, the entire clipboard text // match the number of slices in the clipboard, the entire clipboard text
// is pasted at each cursor. // is pasted at each cursor.
view.update(cx, |view, cx| { view.update(cx, |view, cx| {
view.select_ranges(vec![0..0, 31..31], false, cx); view.select_ranges(vec![0..0, 31..31], None, cx);
view.handle_input(&Input("( ".into()), cx); view.handle_input(&Input("( ".into()), cx);
view.paste(&Paste, cx); view.paste(&Paste, cx);
view.handle_input(&Input(") ".into()), cx); view.handle_input(&Input(") ".into()), cx);
@ -4733,7 +4756,7 @@ mod tests {
}); });
view.update(cx, |view, cx| { view.update(cx, |view, cx| {
view.select_ranges(vec![0..0], false, cx); view.select_ranges(vec![0..0], None, cx);
view.handle_input(&Input("123\n4567\n89\n".into()), cx); view.handle_input(&Input("123\n4567\n89\n".into()), cx);
assert_eq!( assert_eq!(
view.display_text(cx), view.display_text(cx),

View file

@ -1,5 +1,5 @@
use buffer::{Bias, Point}; use buffer::{Bias, Point};
use editor::{Editor, EditorSettings}; use editor::{Autoscroll, Editor, EditorSettings};
use gpui::{ use gpui::{
action, elements::*, keymap::Binding, Entity, MutableAppContext, RenderContext, View, action, elements::*, keymap::Binding, Entity, MutableAppContext, RenderContext, View,
ViewContext, ViewHandle, ViewContext, ViewHandle,
@ -97,11 +97,9 @@ impl GoToLine {
let column = components.next().and_then(|row| row.parse::<u32>().ok()); let column = components.next().and_then(|row| row.parse::<u32>().ok());
if let Some(point) = row.map(|row| Point::new(row, column.unwrap_or(0))) { if let Some(point) = row.map(|row| Point::new(row, column.unwrap_or(0))) {
self.active_editor.update(cx, |active_editor, cx| { self.active_editor.update(cx, |active_editor, cx| {
let point = active_editor let buffer = active_editor.buffer().read(cx);
.buffer() let point = buffer.clip_point(point, Bias::Left);
.read(cx) active_editor.select_ranges([point..point], Some(Autoscroll::Center), cx);
.clip_point(point, Bias::Left);
active_editor.select_ranges([point..point], true, cx);
}); });
cx.notify(); cx.notify();
} }