Detailed changes
@@ -49,7 +49,8 @@ use serde_json::{self, json};
use settings::{
AllLanguageSettingsContent, DelayMs, EditorSettingsContent, GlobalLspSettingsContent,
IndentGuideBackgroundColoring, IndentGuideColoring, InlayHintSettingsContent,
- ProjectSettingsContent, SearchSettingsContent, SettingsContent, SettingsStore,
+ ProjectSettingsContent, ScrollBeyondLastLine, SearchSettingsContent, SettingsContent,
+ SettingsStore,
};
use std::borrow::Cow;
use std::{cell::RefCell, future::Future, rc::Rc, sync::atomic::AtomicBool, time::Instant};
@@ -2784,6 +2785,60 @@ async fn test_autoscroll(cx: &mut TestAppContext) {
});
}
+#[gpui::test]
+async fn test_exclude_overscroll_margin_clamps_scroll_position(cx: &mut TestAppContext) {
+ init_test(cx, |_| {});
+ update_test_editor_settings(cx, &|settings| {
+ settings.scroll_beyond_last_line = Some(ScrollBeyondLastLine::OnePage);
+ });
+
+ let mut cx = EditorTestContext::new(cx).await;
+
+ let line_height = cx.update_editor(|editor, window, cx| {
+ editor.set_mode(EditorMode::Full {
+ scale_ui_elements_with_buffer_font_size: false,
+ show_active_line_background: false,
+ sizing_behavior: SizingBehavior::ExcludeOverscrollMargin,
+ });
+ editor
+ .style(cx)
+ .text
+ .line_height_in_pixels(window.rem_size())
+ });
+ let window = cx.window;
+ cx.simulate_window_resize(window, size(px(1000.), 6. * line_height));
+ cx.set_state(
+ &r#"
+ Λone
+ two
+ three
+ four
+ five
+ six
+ seven
+ eight
+ nine
+ ten
+ eleven
+ "#
+ .unindent(),
+ );
+
+ cx.update_editor(|editor, window, cx| {
+ let snapshot = editor.snapshot(window, cx);
+ let max_scroll_top =
+ (snapshot.max_point().row().as_f64() - editor.visible_line_count().unwrap() + 1.)
+ .max(0.);
+
+ editor.set_scroll_position(gpui::Point::new(0., max_scroll_top + 10.), window, cx);
+
+ assert_eq!(
+ editor.snapshot(window, cx).scroll_position(),
+ gpui::Point::new(0., max_scroll_top)
+ );
+ });
+}
+
#[gpui::test]
async fn test_move_page_up_page_down(cx: &mut TestAppContext) {
init_test(cx, |_| {});
@@ -9772,26 +9772,14 @@ impl Element for EditorElement {
f64::from(visible_bounds.size.height / line_height);
// The max scroll position for the top of the window
- let max_scroll_top = if matches!(
- snapshot.mode,
- EditorMode::SingleLine
- | EditorMode::AutoHeight { .. }
- | EditorMode::Full {
- sizing_behavior: SizingBehavior::ExcludeOverscrollMargin
- | SizingBehavior::SizeByContent,
- ..
- }
- ) {
- (max_row - height_in_lines + 1.).max(0.)
- } else {
- let settings = EditorSettings::get_global(cx);
- match settings.scroll_beyond_last_line {
- ScrollBeyondLastLine::OnePage => max_row,
- ScrollBeyondLastLine::Off => (max_row - height_in_lines + 1.).max(0.),
- ScrollBeyondLastLine::VerticalScrollMargin => {
- (max_row - height_in_lines + 1. + settings.vertical_scroll_margin)
- .max(0.)
- }
+ let scroll_beyond_last_line = self.editor.read(cx).scroll_beyond_last_line(cx);
+ let max_scroll_top = match scroll_beyond_last_line {
+ ScrollBeyondLastLine::OnePage => max_row,
+ ScrollBeyondLastLine::Off => (max_row - height_in_lines + 1.).max(0.),
+ ScrollBeyondLastLine::VerticalScrollMargin => {
+ let settings = EditorSettings::get_global(cx);
+ (max_row - height_in_lines + 1. + settings.vertical_scroll_margin)
+ .max(0.)
}
};
@@ -10309,6 +10297,7 @@ impl Element for EditorElement {
),
longest_line_blame_width,
EditorSettings::get_global(cx),
+ scroll_beyond_last_line,
);
let mut scroll_width = scrollbar_layout_information.scroll_range.width;
@@ -11187,8 +11176,9 @@ impl ScrollbarLayoutInformation {
document_size: Size<Pixels>,
longest_line_blame_width: Pixels,
settings: &EditorSettings,
+ scroll_beyond_last_line: ScrollBeyondLastLine,
) -> Self {
- let vertical_overscroll = match settings.scroll_beyond_last_line {
+ let vertical_overscroll = match scroll_beyond_last_line {
ScrollBeyondLastLine::OnePage => editor_bounds.size.height,
ScrollBeyondLastLine::Off => glyph_grid_cell.height,
ScrollBeyondLastLine::VerticalScrollMargin => {
@@ -5,7 +5,7 @@ pub(crate) mod scroll_amount;
use crate::editor_settings::ScrollBeyondLastLine;
use crate::{
Anchor, DisplayPoint, DisplayRow, Editor, EditorEvent, EditorMode, EditorSettings,
- InlayHintRefreshReason, MultiBufferSnapshot, RowExt, ToPoint,
+ InlayHintRefreshReason, MultiBufferSnapshot, RowExt, SizingBehavior, ToPoint,
display_map::{DisplaySnapshot, ToDisplayPoint},
hover_popover::hide_hover,
persistence::EditorDb,
@@ -372,6 +372,7 @@ impl ScrollManager {
&mut self,
scroll_position: gpui::Point<ScrollOffset>,
map: &DisplaySnapshot,
+ scroll_beyond_last_line: ScrollBeyondLastLine,
local: bool,
autoscroll: bool,
workspace_id: Option<WorkspaceId>,
@@ -379,7 +380,7 @@ impl ScrollManager {
cx: &mut Context<Editor>,
) -> WasScrolled {
let scroll_top = scroll_position.y.max(0.);
- let scroll_top = match EditorSettings::get_global(cx).scroll_beyond_last_line {
+ let scroll_top = match scroll_beyond_last_line {
ScrollBeyondLastLine::OnePage => scroll_top,
ScrollBeyondLastLine::Off => {
if let Some(height_in_lines) = self.visible_line_count {
@@ -400,7 +401,6 @@ impl ScrollManager {
}
}
};
-
let scroll_top_row = DisplayRow(scroll_top as u32);
let scroll_top_buffer_point = map
.clip_point(
@@ -639,6 +639,20 @@ impl Editor {
self.scroll_manager.vertical_scroll_margin as usize
}
+ pub(crate) fn scroll_beyond_last_line(&self, cx: &App) -> ScrollBeyondLastLine {
+ match self.mode {
+ EditorMode::Minimap { .. }
+ | EditorMode::Full {
+ sizing_behavior: SizingBehavior::Default,
+ ..
+ } => EditorSettings::get_global(cx).scroll_beyond_last_line,
+
+ EditorMode::Full { .. } | EditorMode::SingleLine | EditorMode::AutoHeight { .. } => {
+ ScrollBeyondLastLine::Off
+ }
+ }
+ }
+
pub fn set_vertical_scroll_margin(&mut self, margin_rows: usize, cx: &mut Context<Self>) {
self.scroll_manager.vertical_scroll_margin = margin_rows as f64;
cx.notify();
@@ -776,10 +790,11 @@ impl Editor {
} else {
scroll_position
};
-
+ let scroll_beyond_last_line = self.scroll_beyond_last_line(cx);
self.scroll_manager.set_scroll_position(
adjusted_position,
&display_map,
+ scroll_beyond_last_line,
local,
autoscroll,
workspace_id,