editor: Fix horizontal scroll when soft wrap is active (#24735)

Closes #22252

This PR fixes the bug introduced in
https://github.com/zed-industries/zed/pull/19495 by:

Problem:

The vertical scrollbar is currently rendered absolutely on top of the
editor. When calculating soft wrap, the editor uses its width to decide
how many words fit on a line. This causes words to overlap with the
vertical scrollbar because it doesn't account for the scrollbar's width.
To fix the overlap, extra overflow is added to the scrollbar, which
solves the issue but creates unnecessary scrolling in soft wrap mode.

Fix:

The editor width is adjusted to account for the scrollbar's width. This
makes sure the correct number of words fit on a line and prevents
overlapping with the scrollbar in soft wrap mode.

Since the scrollbar width is now accounted for in the editor's width,
there's no need to add extra overflow, unless there’s no soft wrap. In
that case, when text overflows the editor’s width, we still need to add
extra overscroll to match the scrollbar width. Without this, long lines
will overlap with the scrollbar.

Release Notes:

- Fixed issue where horizontal scrollbar would scroll few characters
width when soft wrap is active.
This commit is contained in:
smit 2025-02-12 22:52:22 +05:30 committed by GitHub
parent ba7d2ba8c7
commit cc97f4131b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -6773,7 +6773,8 @@ impl Element for EditorElement {
.unwrap_or_default();
let text_width = bounds.size.width - gutter_dimensions.width;
let editor_width = text_width - gutter_dimensions.margin - em_width;
let editor_width =
text_width - gutter_dimensions.margin - em_width - style.scrollbar_width;
snapshot = self.editor.update(cx, |editor, cx| {
editor.last_bounds = Some(bounds);
@ -7108,6 +7109,7 @@ impl Element for EditorElement {
longest_line_width,
longest_line_blame_width,
&style,
editor_width,
cx,
);
@ -7716,6 +7718,7 @@ struct ScrollbarRangeData {
}
impl ScrollbarRangeData {
#[allow(clippy::too_many_arguments)]
pub fn new(
scrollbar_bounds: Bounds<Pixels>,
letter_size: Size<Pixels>,
@ -7723,15 +7726,13 @@ impl ScrollbarRangeData {
longest_line_width: Pixels,
longest_line_blame_width: Pixels,
style: &EditorStyle,
editor_width: Pixels,
cx: &mut App,
) -> ScrollbarRangeData {
// TODO: Simplify this function down, it requires a lot of parameters
let max_row = snapshot.max_point().row();
let text_bounds_size = size(longest_line_width, max_row.0 as f32 * letter_size.height);
let scrollbar_width = style.scrollbar_width;
let settings = EditorSettings::get_global(cx);
let scroll_beyond_last_line: Pixels = match settings.scroll_beyond_last_line {
ScrollBeyondLastLine::OnePage => px(scrollbar_bounds.size.height / letter_size.height),
@ -7739,8 +7740,14 @@ impl ScrollbarRangeData {
ScrollBeyondLastLine::VerticalScrollMargin => px(1.0 + settings.vertical_scroll_margin),
};
let right_margin = if longest_line_width + longest_line_blame_width >= editor_width {
letter_size.width + style.scrollbar_width
} else {
px(0.0)
};
let overscroll = size(
scrollbar_width + (letter_size.width / 2.0) + longest_line_blame_width,
right_margin + longest_line_blame_width,
letter_size.height * scroll_beyond_last_line,
);