Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

editor: Add scroll_beyond_last_line setting #11155

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions assets/settings/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@
// Whether to show fold buttons in the gutter.
"folds": true
},
// Whether the editor will scroll beyond the last line.
"scroll_beyond_last_line": "one_page",
// The number of lines to keep above/below the cursor when scrolling.
"vertical_scroll_margin": 3,
// Scroll sensitivity multiplier. This multiplier is applied
Expand Down
21 changes: 21 additions & 0 deletions crates/editor/src/editor_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct EditorSettings {
pub toolbar: Toolbar,
pub scrollbar: Scrollbar,
pub gutter: Gutter,
pub scroll_beyond_last_line: ScrollBeyondLastLine,
pub vertical_scroll_margin: f32,
pub scroll_sensitivity: f32,
pub relative_line_numbers: bool,
Expand Down Expand Up @@ -99,6 +100,22 @@ pub enum MultiCursorModifier {
CmdOrCtrl,
}

/// Whether the editor will scroll beyond the last line.
///
/// Default: one_page
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ScrollBeyondLastLine {
/// The editor will not scroll beyond the last line.
Off,

/// The editor will scroll beyond the last line by one page.
OnePage,

/// The editor will scroll beyond the last line by the same number of lines as vertical_scroll_margin.
VerticalScrollMargin,
}

#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
pub struct EditorSettingsContent {
/// Whether the cursor blinks in the editor.
Expand Down Expand Up @@ -136,6 +153,10 @@ pub struct EditorSettingsContent {
pub scrollbar: Option<ScrollbarContent>,
/// Gutter related settings
pub gutter: Option<GutterContent>,
/// Whether the editor will scroll beyond the last line.
///
/// Default: one_page
pub scroll_beyond_last_line: Option<ScrollBeyondLastLine>,
/// The number of lines to keep above/below the cursor when auto-scrolling.
///
/// Default: 3.
Expand Down
23 changes: 20 additions & 3 deletions crates/editor/src/element.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::editor_settings::ScrollBeyondLastLine;
use crate::{
blame_entry_tooltip::{blame_entry_relative_timestamp, BlameEntryTooltip},
display_map::{
Expand Down Expand Up @@ -1099,11 +1100,17 @@ impl EditorElement {
point(bounds.lower_right().x, bounds.lower_left().y),
);

let settings = EditorSettings::get_global(cx);
let scroll_beyond_last_line: f32 = match settings.scroll_beyond_last_line {
ScrollBeyondLastLine::OnePage => rows_per_page,
ScrollBeyondLastLine::Off => 1.0,
ScrollBeyondLastLine::VerticalScrollMargin => 1.0 + settings.vertical_scroll_margin,
};
let total_rows = snapshot.max_point().row() as f32 + scroll_beyond_last_line;
let height = bounds.size.height;
let total_rows = snapshot.max_point().row() as f32 + rows_per_page;
let px_per_row = height / total_rows;
let thumb_height = (rows_per_page * px_per_row).max(ScrollbarLayout::MIN_THUMB_HEIGHT);
let row_height = (height - thumb_height) / snapshot.max_point().row() as f32;
let row_height = (height - thumb_height) / (total_rows - rows_per_page).max(0.0);

Some(ScrollbarLayout {
hitbox: cx.insert_hitbox(track_bounds, false),
Expand Down Expand Up @@ -3731,9 +3738,19 @@ impl Element for EditorElement {
cx,
);

let settings = EditorSettings::get_global(cx);
let scroll_max_row = max_row as f32;
let scroll_max_row = match settings.scroll_beyond_last_line {
ScrollBeyondLastLine::OnePage => scroll_max_row,
ScrollBeyondLastLine::Off => (scroll_max_row - height_in_lines + 1.0).max(0.0),
ScrollBeyondLastLine::VerticalScrollMargin => {
(scroll_max_row - height_in_lines + 1.0 + settings.vertical_scroll_margin)
.max(0.0)
}
};
let scroll_max = point(
((scroll_width - text_hitbox.size.width) / em_width).max(0.0),
max_row as f32,
scroll_max_row,
);

self.editor.update(cx, |editor, cx| {
Expand Down
18 changes: 15 additions & 3 deletions crates/editor/src/scroll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod actions;
pub(crate) mod autoscroll;
pub(crate) mod scroll_amount;

use crate::editor_settings::ScrollBeyondLastLine;
use crate::{
display_map::{DisplaySnapshot, ToDisplayPoint},
hover_popover::hide_hover,
Expand Down Expand Up @@ -194,8 +195,19 @@ impl ScrollManager {
0,
)
} else {
let scroll_top_buffer_point =
DisplayPoint::new(scroll_position.y as u32, 0).to_point(&map);
let scroll_top = scroll_position.y;
let scroll_top = match EditorSettings::get_global(cx).scroll_beyond_last_line {
ScrollBeyondLastLine::OnePage => scroll_top,
ScrollBeyondLastLine::Off => scroll_top
.min((map.max_buffer_row() as f32) - self.visible_line_count.unwrap() + 1.0),
ScrollBeyondLastLine::VerticalScrollMargin => scroll_top.min(
(map.max_buffer_row() as f32) - self.visible_line_count.unwrap()
+ 1.0
+ self.vertical_scroll_margin,
),
};

let scroll_top_buffer_point = DisplayPoint::new(scroll_top as u32, 0).to_point(&map);
let top_anchor = map
.buffer_snapshot
.anchor_at(scroll_top_buffer_point, Bias::Right);
Expand All @@ -205,7 +217,7 @@ impl ScrollManager {
anchor: top_anchor,
offset: point(
scroll_position.x.max(0.),
scroll_position.y - top_anchor.to_display_point(&map).row() as f32,
scroll_top - top_anchor.to_display_point(&map).row() as f32,
),
},
scroll_top_buffer_point.row,
Expand Down