Compare commits

...
Sign in to create a new pull request.

9 commits

Author SHA1 Message Date
MrSubidubi
ac307dd836 Merge branch 'main' into scroll-manager-display-map 2025-07-15 10:06:47 +02:00
MrSubidubi
b24f75663d Cleanup a bit 2025-07-12 13:26:06 +02:00
MrSubidubi
638eceda0e Merge branch 'main' into scroll-manager-display-map 2025-07-12 11:43:31 +02:00
MrSubidubi
9553650588 Remove inaccurate TODOs 2025-07-10 11:42:00 +02:00
MrSubidubi
10f5d616a4 Only create snapshot if needed 2025-07-10 11:40:58 +02:00
MrSubidubi
e68a84e027 Reuse snapshot for scroll position setting when possible 2025-07-10 00:23:41 +02:00
MrSubidubi
bd4098ca2d Use last snapshot to resolve scroll position where possible 2025-07-10 00:23:41 +02:00
MrSubidubi
86324b0935 Move and rename parameter 2025-07-10 00:23:41 +02:00
MrSubidubi
a70c76ce8b editor: Reduce snapshot creations during scroll 2025-07-10 00:23:41 +02:00
4 changed files with 103 additions and 73 deletions

View file

@ -3695,7 +3695,7 @@ impl Editor {
return;
}
self.apply_scroll_delta(scroll_delta, window, cx);
self.apply_scroll_delta(scroll_delta, &display_map, window, cx);
cx.notify();
}

View file

@ -1018,7 +1018,7 @@ impl EditorElement {
drop_cursor.start = drop_anchor;
drop_cursor.end = drop_anchor;
*hide_drop_cursor = !text_hitbox.is_hovered(window);
editor.apply_scroll_delta(scroll_delta, window, cx);
editor.apply_scroll_delta(scroll_delta, &position_map.snapshot, window, cx);
cx.notify();
}
SelectionDragState::ReadyToDrag {
@ -1042,7 +1042,7 @@ impl EditorElement {
drop_cursor,
hide_drop_cursor: false,
};
editor.apply_scroll_delta(scroll_delta, window, cx);
editor.apply_scroll_delta(scroll_delta, &position_map.snapshot, window, cx);
cx.notify();
} else {
let click_point = position_map.point_for_position(*click_position);
@ -8060,7 +8060,14 @@ impl Element for EditorElement {
autoscroll_request.is_some() || editor.has_pending_selection();
let (needs_horizontal_autoscroll, was_scrolled) = editor
.autoscroll_vertically(bounds, line_height, max_scroll_top, window, cx);
.autoscroll_vertically(
bounds,
line_height,
max_scroll_top,
&snapshot,
window,
cx,
);
if was_scrolled.0 {
snapshot = editor.snapshot(window, cx);
}
@ -8496,6 +8503,7 @@ impl Element for EditorElement {
scroll_width,
em_advance,
&line_layouts,
&snapshot,
window,
cx,
)

View file

@ -211,10 +211,10 @@ impl ScrollManager {
fn set_scroll_position(
&mut self,
scroll_position: gpui::Point<f32>,
map: &DisplaySnapshot,
local: bool,
autoscroll: bool,
workspace_id: Option<WorkspaceId>,
display_snapshot: &DisplaySnapshot,
window: &mut Window,
cx: &mut Context<Editor>,
) -> WasScrolled {
@ -223,7 +223,7 @@ impl ScrollManager {
ScrollBeyondLastLine::OnePage => scroll_top,
ScrollBeyondLastLine::Off => {
if let Some(height_in_lines) = self.visible_line_count {
let max_row = map.max_point().row().0 as f32;
let max_row = display_snapshot.max_point().row().0 as f32;
scroll_top.min(max_row - height_in_lines + 1.).max(0.)
} else {
scroll_top
@ -231,7 +231,7 @@ impl ScrollManager {
}
ScrollBeyondLastLine::VerticalScrollMargin => {
if let Some(height_in_lines) = self.visible_line_count {
let max_row = map.max_point().row().0 as f32;
let max_row = display_snapshot.max_point().row().0 as f32;
scroll_top
.min(max_row - height_in_lines + 1. + self.vertical_scroll_margin)
.max(0.)
@ -242,13 +242,13 @@ impl ScrollManager {
};
let scroll_top_row = DisplayRow(scroll_top as u32);
let scroll_top_buffer_point = map
let scroll_top_buffer_point = display_snapshot
.clip_point(
DisplayPoint::new(scroll_top_row, scroll_position.x as u32),
Bias::Left,
)
.to_point(map);
let top_anchor = map
.to_point(display_snapshot);
let top_anchor = display_snapshot
.buffer_snapshot
.anchor_at(scroll_top_buffer_point, Bias::Right);
@ -257,7 +257,7 @@ impl ScrollManager {
anchor: top_anchor,
offset: point(
scroll_position.x.max(0.),
scroll_top - top_anchor.to_display_point(map).row().as_f32(),
scroll_top - top_anchor.to_display_point(display_snapshot).row().as_f32(),
),
},
scroll_top_buffer_point.row,
@ -512,6 +512,7 @@ impl Editor {
pub fn apply_scroll_delta(
&mut self,
scroll_delta: gpui::Point<f32>,
display_snapshot: &DisplaySnapshot,
window: &mut Window,
cx: &mut Context<Self>,
) {
@ -519,9 +520,8 @@ impl Editor {
if self.scroll_manager.forbid_vertical_scroll {
delta.y = 0.0;
}
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let position = self.scroll_manager.anchor.scroll_position(&display_map) + delta;
self.set_scroll_position_taking_display_map(position, true, false, display_map, window, cx);
let position = self.scroll_manager.anchor.scroll_position(display_snapshot) + delta;
self.set_scroll_position_internal(position, true, false, display_snapshot, window, cx);
}
pub fn set_scroll_position(
@ -535,7 +535,17 @@ impl Editor {
let current_position = self.scroll_position(cx);
position.y = current_position.y;
}
self.set_scroll_position_internal(position, true, false, window, cx)
if let Some(display_snapshot) = self
.last_position_map
.clone()
.as_ref()
.map(|position_map| &position_map.snapshot)
{
self.set_scroll_position_internal(position, true, false, &display_snapshot, window, cx)
} else {
let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
self.set_scroll_position_internal(position, true, false, &display_snapshot, window, cx)
}
}
/// Scrolls so that `row` is at the top of the editor view.
@ -565,26 +575,7 @@ impl Editor {
scroll_position: gpui::Point<f32>,
local: bool,
autoscroll: bool,
window: &mut Window,
cx: &mut Context<Self>,
) -> WasScrolled {
let map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
self.set_scroll_position_taking_display_map(
scroll_position,
local,
autoscroll,
map,
window,
cx,
)
}
fn set_scroll_position_taking_display_map(
&mut self,
scroll_position: gpui::Point<f32>,
local: bool,
autoscroll: bool,
display_map: DisplaySnapshot,
display_map: &DisplaySnapshot,
window: &mut Window,
cx: &mut Context<Self>,
) -> WasScrolled {
@ -595,7 +586,7 @@ impl Editor {
.set_previous_scroll_position(None);
let adjusted_position = if self.scroll_manager.forbid_vertical_scroll {
let current_position = self.scroll_manager.anchor.scroll_position(&display_map);
let current_position = self.scroll_manager.anchor.scroll_position(display_map);
gpui::Point::new(scroll_position.x, current_position.y)
} else {
scroll_position
@ -603,10 +594,10 @@ impl Editor {
let editor_was_scrolled = self.scroll_manager.set_scroll_position(
adjusted_position,
&display_map,
local,
autoscroll,
workspace_id,
display_map,
window,
cx,
);
@ -617,8 +608,20 @@ impl Editor {
}
pub fn scroll_position(&self, cx: &mut Context<Self>) -> gpui::Point<f32> {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
self.scroll_manager.anchor.scroll_position(&display_map)
self.last_position_map
.as_ref()
.map(|position_map| {
self.scroll_manager
.anchor
.scroll_position(&position_map.snapshot)
})
.unwrap_or_else(|| {
self.scroll_manager.anchor.scroll_position(
&self
.display_map
.update(cx, |display_map, cx| display_map.snapshot(cx)),
)
})
}
pub fn set_scroll_anchor(

View file

@ -1,6 +1,7 @@
use crate::{
DisplayRow, Editor, EditorMode, LineWithInvisibles, RowExt, SelectionEffects,
display_map::ToDisplayPoint, scroll::WasScrolled,
display_map::{DisplaySnapshot, ToDisplayPoint},
scroll::WasScrolled,
};
use gpui::{Bounds, Context, Pixels, Window, px};
use language::Point;
@ -111,13 +112,13 @@ impl Editor {
bounds: Bounds<Pixels>,
line_height: Pixels,
max_scroll_top: f32,
display_snapshot: &DisplaySnapshot,
window: &mut Window,
cx: &mut Context<Editor>,
) -> (NeedsHorizontalAutoscroll, WasScrolled) {
let viewport_height = bounds.size.height;
let visible_lines = viewport_height / line_height;
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let mut scroll_position = self.scroll_manager.scroll_position(&display_map);
let mut scroll_position = self.scroll_manager.scroll_position(display_snapshot);
let original_y = scroll_position.y;
if let Some(last_bounds) = self.expect_bounds_change.take() {
if scroll_position.y != 0. {
@ -144,7 +145,7 @@ impl Editor {
let mut target_top;
let mut target_bottom;
if let Some(first_highlighted_row) =
self.highlighted_display_row_for_autoscroll(&display_map)
self.highlighted_display_row_for_autoscroll(display_snapshot)
{
target_top = first_highlighted_row.as_f32();
target_bottom = target_top + 1.;
@ -155,14 +156,14 @@ impl Editor {
.first()
.unwrap()
.head()
.to_display_point(&display_map)
.to_display_point(display_snapshot)
.row()
.as_f32();
target_bottom = selections
.last()
.unwrap()
.head()
.to_display_point(&display_map)
.to_display_point(display_snapshot)
.row()
.next_row()
.as_f32();
@ -179,7 +180,7 @@ impl Editor {
.max_by_key(|s| s.id)
.unwrap()
.head()
.to_display_point(&display_map)
.to_display_point(display_snapshot)
.row()
.as_f32();
target_top = newest_selection_top;
@ -212,11 +213,11 @@ impl Editor {
}
};
if let Autoscroll::Strategy(_, Some(anchor)) = autoscroll {
target_top = anchor.to_display_point(&display_map).row().as_f32();
target_top = anchor.to_display_point(display_snapshot).row().as_f32();
target_bottom = target_top + 1.;
}
let was_autoscrolled = match strategy {
let needs_autoscroll = match strategy {
AutoscrollStrategy::Fit | AutoscrollStrategy::Newest => {
let margin = margin.min(self.scroll_manager.vertical_scroll_margin);
let target_top = (target_top - margin).max(0.0);
@ -233,39 +234,48 @@ impl Editor {
scroll_position.y = target_bottom - visible_lines;
}
if needs_scroll_up ^ needs_scroll_down {
self.set_scroll_position_internal(scroll_position, local, true, window, cx)
} else {
WasScrolled(false)
}
needs_scroll_up ^ needs_scroll_down
}
AutoscrollStrategy::Center => {
scroll_position.y = (target_top - margin).max(0.0);
self.set_scroll_position_internal(scroll_position, local, true, window, cx)
true
}
AutoscrollStrategy::Focused => {
let margin = margin.min(self.scroll_manager.vertical_scroll_margin);
scroll_position.y = (target_top - margin).max(0.0);
self.set_scroll_position_internal(scroll_position, local, true, window, cx)
true
}
AutoscrollStrategy::Top => {
scroll_position.y = (target_top).max(0.0);
self.set_scroll_position_internal(scroll_position, local, true, window, cx)
true
}
AutoscrollStrategy::Bottom => {
scroll_position.y = (target_bottom - visible_lines).max(0.0);
self.set_scroll_position_internal(scroll_position, local, true, window, cx)
true
}
AutoscrollStrategy::TopRelative(lines) => {
scroll_position.y = target_top - lines as f32;
self.set_scroll_position_internal(scroll_position, local, true, window, cx)
true
}
AutoscrollStrategy::BottomRelative(lines) => {
scroll_position.y = target_bottom + lines as f32;
self.set_scroll_position_internal(scroll_position, local, true, window, cx)
true
}
};
let was_autoscrolled = needs_autoscroll
.then(|| {
self.set_scroll_position_internal(
scroll_position,
local,
true,
display_snapshot,
window,
cx,
)
})
.unwrap_or(WasScrolled(false));
self.scroll_manager.last_autoscroll = Some((
self.scroll_manager.anchor.offset,
target_top,
@ -284,29 +294,29 @@ impl Editor {
scroll_width: Pixels,
em_advance: Pixels,
layouts: &[LineWithInvisibles],
display_snapshot: &DisplaySnapshot,
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<gpui::Point<f32>> {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let selections = self.selections.all::<Point>(cx);
let mut scroll_position = self.scroll_manager.scroll_position(&display_map);
let mut scroll_position = self.scroll_manager.scroll_position(display_snapshot);
let mut target_left;
let mut target_right;
if self
.highlighted_display_row_for_autoscroll(&display_map)
.highlighted_display_row_for_autoscroll(display_snapshot)
.is_none()
{
target_left = px(f32::INFINITY);
target_right = px(0.);
for selection in selections {
let head = selection.head().to_display_point(&display_map);
let head = selection.head().to_display_point(display_snapshot);
if head.row() >= start_row
&& head.row() < DisplayRow(start_row.0 + layouts.len() as u32)
{
let start_column = head.column();
let end_column = cmp::min(display_map.line_len(head.row()), head.column());
let end_column = cmp::min(display_snapshot.line_len(head.row()), head.column());
target_left = target_left.min(
layouts[head.row().minus(start_row) as usize]
.x_for_index(start_column as usize)
@ -333,21 +343,30 @@ impl Editor {
let scroll_left = self.scroll_manager.anchor.offset.x * em_advance;
let scroll_right = scroll_left + viewport_width;
let was_scrolled = if target_left < scroll_left {
let needs_scroll = if target_left < scroll_left {
scroll_position.x = target_left / em_advance;
self.set_scroll_position_internal(scroll_position, true, true, window, cx)
true
} else if target_right > scroll_right {
scroll_position.x = (target_right - viewport_width) / em_advance;
self.set_scroll_position_internal(scroll_position, true, true, window, cx)
true
} else {
WasScrolled(false)
false
};
if was_scrolled.0 {
Some(scroll_position)
} else {
None
}
let was_scrolled = needs_scroll
.then(|| {
self.set_scroll_position_internal(
scroll_position,
true,
true,
display_snapshot,
window,
cx,
)
})
.unwrap_or(WasScrolled(false));
was_scrolled.0.then_some(scroll_position)
}
pub fn request_autoscroll(&mut self, autoscroll: Autoscroll, cx: &mut Context<Self>) {