Compare commits
9 commits
main
...
scroll-man
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ac307dd836 | ||
![]() |
b24f75663d | ||
![]() |
638eceda0e | ||
![]() |
9553650588 | ||
![]() |
10f5d616a4 | ||
![]() |
e68a84e027 | ||
![]() |
bd4098ca2d | ||
![]() |
86324b0935 | ||
![]() |
a70c76ce8b |
4 changed files with 103 additions and 73 deletions
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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>) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue