Merge pull request #923 from zed-industries/navigate-panic

Clip `scroll_top_row` before navigating back to it
This commit is contained in:
Antonio Scandurra
2022-04-28 10:22:09 +02:00
committed by GitHub
10 changed files with 116 additions and 36 deletions
+30 -6
View File
@@ -847,14 +847,15 @@ struct ClipboardSelection {
is_entire_line: bool,
}
#[derive(Debug)]
pub struct NavigationData {
// Matching offsets for anchor and scroll_top_anchor allows us to recreate the anchor if the buffer
// has since been closed
cursor_anchor: Anchor,
cursor_offset: usize,
cursor_position: Point,
scroll_position: Vector2F,
scroll_top_anchor: Anchor,
scroll_top_offset: usize,
scroll_top_row: u32,
}
pub struct EditorCreated(pub ViewHandle<Editor>);
@@ -1112,6 +1113,7 @@ impl Editor {
self.scroll_top_anchor = anchor;
}
self.autoscroll_request.take();
cx.emit(Event::ScrollPositionChanged { local });
cx.notify();
}
@@ -3910,9 +3912,8 @@ impl Editor {
) {
if let Some(nav_history) = &self.nav_history {
let buffer = self.buffer.read(cx).read(cx);
let offset = position.to_offset(&buffer);
let point = position.to_point(&buffer);
let scroll_top_offset = self.scroll_top_anchor.to_offset(&buffer);
let scroll_top_row = self.scroll_top_anchor.to_point(&buffer).row;
drop(buffer);
if let Some(new_position) = new_position {
@@ -3924,10 +3925,10 @@ impl Editor {
nav_history.push(Some(NavigationData {
cursor_anchor: position,
cursor_offset: offset,
cursor_position: point,
scroll_position: self.scroll_position,
scroll_top_anchor: self.scroll_top_anchor.clone(),
scroll_top_offset,
scroll_top_row,
}));
}
}
@@ -6826,6 +6827,29 @@ mod tests {
assert_eq!(editor.scroll_position, original_scroll_position);
assert_eq!(editor.scroll_top_anchor, original_scroll_top_anchor);
// Ensure we don't panic when navigation data contains invalid anchors *and* points.
let mut invalid_anchor = editor.scroll_top_anchor.clone();
invalid_anchor.text_anchor.buffer_id = Some(999);
let invalid_point = Point::new(9999, 0);
editor.navigate(
Box::new(NavigationData {
cursor_anchor: invalid_anchor.clone(),
cursor_position: invalid_point,
scroll_top_anchor: invalid_anchor.clone(),
scroll_top_row: invalid_point.row,
scroll_position: Default::default(),
}),
cx,
);
assert_eq!(
editor.selected_display_ranges(cx),
&[editor.max_point(cx)..editor.max_point(cx)]
);
assert_eq!(
editor.scroll_position(cx),
vec2f(0., editor.max_point(cx).row() as f32)
);
editor
});
}
+9 -7
View File
@@ -1,4 +1,4 @@
use crate::{Anchor, Autoscroll, Editor, Event, ExcerptId, NavigationData, ToOffset, ToPoint as _};
use crate::{Anchor, Autoscroll, Editor, Event, ExcerptId, NavigationData, ToPoint as _};
use anyhow::{anyhow, Result};
use futures::FutureExt;
use gpui::{
@@ -245,19 +245,21 @@ fn deserialize_selection(
impl Item for Editor {
fn navigate(&mut self, data: Box<dyn std::any::Any>, cx: &mut ViewContext<Self>) -> bool {
if let Some(data) = data.downcast_ref::<NavigationData>() {
if let Ok(data) = data.downcast::<NavigationData>() {
let buffer = self.buffer.read(cx).read(cx);
let offset = if buffer.can_resolve(&data.cursor_anchor) {
data.cursor_anchor.to_offset(&buffer)
data.cursor_anchor.to_point(&buffer)
} else {
buffer.clip_offset(data.cursor_offset, Bias::Left)
buffer.clip_point(data.cursor_position, Bias::Left)
};
let newest_selection = self.newest_selection_with_snapshot::<usize>(&buffer);
let newest_selection = self.newest_selection_with_snapshot::<Point>(&buffer);
let scroll_top_anchor = if buffer.can_resolve(&data.scroll_top_anchor) {
data.scroll_top_anchor.clone()
data.scroll_top_anchor
} else {
buffer.anchor_at(data.scroll_top_offset, Bias::Left)
buffer.anchor_before(
buffer.clip_point(Point::new(data.scroll_top_row, 0), Bias::Left),
)
};
drop(buffer);