From d3887cd5f201220e268ff53b7dcd62f4a5245880 Mon Sep 17 00:00:00 2001 From: Bougie <36102904+bougieL@users.noreply.github.com> Date: Thu, 22 Oct 2026 17:45:44 +0800 Subject: [PATCH] fix(document): size the docked column's content in points, not percent (#1150) (#1196) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A docked document was drawn in a fraction of the space its column had. The column itself was sized correctly — `document_body_px` and `document_column_px` agreed with what the column measured on screen — but the box holding the surface was `w_full()`, a share of whatever the flex ancestor chain resolved to, and on a fractional display scale that share resolved against the wrong ancestor entirely. On a 1.75x Wayland surface (GNOME's `scale-monitor-framebuffer`), a 404-point column handed its file a 123-point content box, so the editor laid out at a fifth of the width it was given, soft-wrapped every few characters, and left the rest of the column empty. The same build under X11, where the scale is 1, put the file across the column. surface scale 1 scale 1.75 fixed column (measured) 404.0 403.4 403.4 content box 404.0 123.4 403.4 editor 380.0 99.4 380.6 wrap width 302.9 22.3 303.4 The column is sized in points where it is drawn, so its content is sized the same way: a point count has no ancestor to be resolved against, and reads the same at every scale. `DOCUMENT_RULE` names the rule on the column's left edge so the border and the width that leaves room for it cannot drift apart. Fill is untouched — it never went through this box — and the diff view docked beside the terminal gets the same fix for free. --- src/ui/document_column.rs | 50 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/src/ui/document_column.rs b/src/ui/document_column.rs index aebc9f43..1e203254 100644 --- a/src/ui/document_column.rs +++ b/src/ui/document_column.rs @@ -573,7 +573,7 @@ impl Tty7App { .w(px(width)) .h_full() .bg(crate::ui::theme::workspace_surface_color(cx)) - .border_l_1() + .border_l(px(DOCUMENT_RULE)) .border_color(cx.theme().sidebar_border) .child(backing) // The clip belongs to the content, not to the column: the @@ -584,7 +584,7 @@ impl Tty7App { div() .flex_1() .min_h_0() - .w_full() + .w(px(document_content_px(width))) .overflow_hidden() .child(surface), ) @@ -696,6 +696,30 @@ impl Tty7App { } } +/// The rule on the docked column's left edge, in points. +/// +/// Named rather than written twice: the content box below is the column less +/// this, and the two have to move together. +pub(crate) const DOCUMENT_RULE: f32 = 1.; + +/// The width the docked column's content box is drawn at. +/// +/// The column is sized in points here, and its content has to be sized the +/// same way. It used to be `w_full()` — a share of whatever box the flex +/// ancestor chain resolved to — and on a fractional display scale (a 1.75x +/// Wayland surface, GNOME's `scale-monitor-framebuffer`) that share came out +/// against the wrong box entirely: a 404-point column handed its file a +/// 123-point content box, so the editor laid out at a fifth of the space it +/// was given and soft-wrapped every few characters (#1150). A point count has +/// no ancestor to be resolved against. +/// +/// [`DOCUMENT_RULE`] is taken off the content because the column draws it as a +/// border: sizing the content at the full width instead would push it a point +/// past the column, and the clip would eat that off the right. +pub(crate) fn document_content_px(column: f32) -> f32 { + (column - DOCUMENT_RULE).max(0.) +} + /// The ratio a divider dropped `raw` points from the right edge of a `body` /// wide area settles on. /// @@ -774,6 +798,28 @@ mod tests { } } + /// #1150: the content box is the column's own width, less the rule on its + /// left edge — never a share of a box resolved further up the flex chain. + /// A fractional display scale made that share resolve against the wrong + /// ancestor, and a 404-point column gave its file 123 points, so a docked + /// document soft-wrapped every few characters. + #[test] + fn the_docked_content_is_the_columns_own_width_less_its_rule() { + use super::{DOCUMENT_RULE, document_content_px}; + for column in [DOCUMENT_MIN_W, 320., 404.54688, 542., 1920.] { + let content = document_content_px(column); + assert_eq!(content, column - DOCUMENT_RULE, "column {column}"); + assert!( + content > 0., + "a column of {column} still has to have room for a file" + ); + } + // A column narrower than its own rule is not a layout; it must not + // answer with a negative width for taffy to reject. + assert_eq!(document_content_px(0.), 0.); + assert_eq!(document_content_px(0.5), 0.); + } + /// Third, half, two thirds, round again — and a dragged width joins at /// whichever stop it looks nearest to rather than always restarting. #[test]