editor: Fix scroll_beyond_last_line off for short files (#13571)

Evan Liu created

Release Notes:

- Fixed bug with `scroll_beyond_last_line: off` for short files
([#13559](https://github.com/zed-industries/zed/issues/13559)).

Change summary

crates/editor/src/element.rs | 15 ++++++++-------
crates/editor/src/scroll.rs  | 25 ++++++++++++++++++-------
2 files changed, 26 insertions(+), 14 deletions(-)

Detailed changes

crates/editor/src/element.rs 🔗

@@ -1119,11 +1119,12 @@ impl EditorElement {
             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 total_rows =
+            (snapshot.max_point().row().as_f32() + scroll_beyond_last_line).max(rows_per_page);
         let height = bounds.size.height;
         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) / (total_rows - rows_per_page).max(0.0);
+        let row_height = (height - thumb_height) / (total_rows - rows_per_page).max(0.);
 
         Some(ScrollbarLayout {
             hitbox: cx.insert_hitbox(track_bounds, false),
@@ -4676,17 +4677,17 @@ impl Element for EditorElement {
                         text_hitbox.origin + point(gutter_dimensions.margin, Pixels::ZERO);
 
                     let height_in_lines = bounds.size.height / line_height;
+                    let max_row = snapshot.max_point().row().as_f32();
                     let max_scroll_top = if matches!(snapshot.mode, EditorMode::AutoHeight { .. }) {
-                        (snapshot.max_point().row().as_f32() - height_in_lines + 1.).max(0.)
+                        (max_row - height_in_lines + 1.).max(0.)
                     } else {
                         let settings = EditorSettings::get_global(cx);
-                        let max_row = snapshot.max_point().row().as_f32();
                         match settings.scroll_beyond_last_line {
                             ScrollBeyondLastLine::OnePage => max_row,
-                            ScrollBeyondLastLine::Off => (max_row - height_in_lines + 1.0).max(0.0),
+                            ScrollBeyondLastLine::Off => (max_row - height_in_lines + 1.).max(0.),
                             ScrollBeyondLastLine::VerticalScrollMargin => {
-                                (max_row - height_in_lines + 1.0 + settings.vertical_scroll_margin)
-                                    .max(0.0)
+                                (max_row - height_in_lines + 1. + settings.vertical_scroll_margin)
+                                    .max(0.)
                             }
                         }
                     };

crates/editor/src/scroll.rs 🔗

@@ -203,13 +203,24 @@ impl ScrollManager {
             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,
-                ),
+                ScrollBeyondLastLine::Off => {
+                    if let Some(height_in_lines) = self.visible_line_count {
+                        let max_row = map.max_buffer_row().as_f32();
+                        scroll_top.min(max_row - height_in_lines + 1.).max(0.)
+                    } else {
+                        scroll_top
+                    }
+                }
+                ScrollBeyondLastLine::VerticalScrollMargin => {
+                    if let Some(height_in_lines) = self.visible_line_count {
+                        let max_row = map.max_buffer_row().as_f32();
+                        scroll_top
+                            .min(max_row - height_in_lines + 1. + self.vertical_scroll_margin)
+                            .max(0.)
+                    } else {
+                        scroll_top
+                    }
+                }
             };
 
             let scroll_top_buffer_point =