From 822e7a3798d431910eeff677ae751eff8b48731a Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Wed, 27 May 2026 19:25:42 -0500 Subject: fix(org): stop folded property-drawer headings wrapping their tag indicators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A folded heading that also has a property drawer renders two glyphs after its right-aligned tag: the org-tidy inline dot (" ·") and the fold ellipsis (" ▾"). The tag-align reserve was 5 columns, and that " · ▾" spilled onto a second screen row, leaving a stray indicator line under the heading. The trailing glyphs measure 4 columns nominally, so the old 5-column reserve looked like it should fit. It didn't: the fallback triangle renders wider than its reported width and the :align-to stretch rounds, so the real overflow exceeds the column count. I sized the new reserve (9) from a rendered measurement, not arithmetic, and the docstring now says so and tells the next reader to verify by screenshot. That mismatch between column math and what actually renders is what let the earlier reserve ship broken. I verified the fix by rendering the real config off-screen at full width and reading the result: before, the two folded property-drawer headings wrapped "· ▾" to a second row; after, every heading is a single line. tests/manual/headline-wrap/ holds the fixture and a README so the check can be repeated by opening the file and looking, which is the only honest way to test a redisplay bug like this. --- modules/org-config.el | 14 ++++++++---- tests/manual/headline-wrap/README.org | 41 ++++++++++++++++++++++++++++++++++ tests/manual/headline-wrap/fixture.org | 28 +++++++++++++++++++++++ 3 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 tests/manual/headline-wrap/README.org create mode 100644 tests/manual/headline-wrap/fixture.org diff --git a/modules/org-config.el b/modules/org-config.el index 90a0a5d2..7d66acfd 100644 --- a/modules/org-config.el +++ b/modules/org-config.el @@ -108,12 +108,18 @@ Group 1 is the single gap character before the tags; group 2 is the tag string itself.") -(defconst cj/org-tag-right-margin 5 +(defconst cj/org-tag-right-margin 9 "Columns of gap left between right-aligned tags and the window's right edge. At least 1 keeps a glyph out of the final column, which would wrap a -non-truncated line. The extra columns leave room for the folded-heading -ellipsis (`org-ellipsis', \" ▾\") that org appends after the tags, so it -stays on the heading line instead of wrapping onto its own line.") +non-truncated line. The remaining columns reserve room for the glyphs org +appends AFTER the tags on a folded, property-drawer heading: the org-tidy +inline symbol (`org-tidy-properties-inline-symbol', \" ·\") and the fold +ellipsis (`org-ellipsis', \" ▾\"). Their nominal width is 4 columns, but the +fallback font renders the triangle wider than its reported width and the +`:align-to' stretch rounds, so the true overflow exceeds the nominal count. +The value is set from rendered measurement (see the headline-wrap harness), +not arithmetic -- that mismatch is what made the earlier 5-column reserve +wrap. Verify changes with a screenshot, never column math alone.") (defun cj/org--tag-align-spec (tag-string) "Return a display spec that right-aligns TAG-STRING to the window edge. diff --git a/tests/manual/headline-wrap/README.org b/tests/manual/headline-wrap/README.org new file mode 100644 index 00000000..dbd16a7e --- /dev/null +++ b/tests/manual/headline-wrap/README.org @@ -0,0 +1,41 @@ +#+TITLE: Headline-indicator wrap — manual render check + +* What this guards + +Org headline tags are right-aligned to the window edge by a font-lock display +property (see =cj/org-right-align-tags-keyword= in =modules/org-config.el=). +After the tag, a folded heading that also has a property drawer renders two +extra glyphs: the org-tidy inline symbol (" ·") and the fold ellipsis +(=org-ellipsis=, " ▾"). =cj/org-tag-right-margin= reserves columns between the +tag and the edge so those glyphs stay on the heading line. + +If the reserve is too small, the trailing " · ▾" wraps onto a second screen +row, leaving a stray indicator line under the heading. This is a redisplay +bug: the column arithmetic can say the glyphs fit while they visibly wrap (the +fallback triangle renders wider than its reported width, and the =:align-to= +stretch rounds). So it must be checked by rendering and looking, never by +column math. + +* How to check + +1. Open =fixture.org= in this directory with the full config: + + #+begin_src bash + emacs tests/manual/headline-wrap/fixture.org + #+end_src + +2. The =#+STARTUP: content= line folds every heading on open, so the folded + property-drawer headings show their " ·" and " ▾" indicators. + +3. Look at each =**= heading. Every one must sit on a single screen row, with + its tag and any trailing " ·" / " ▾" all on the heading line. + + - Expected: four single-line headings, no stray indicator wrapped below any + of them. + - Regression: the first two headings (folded, with property drawers) show + "· ▾" wrapped onto the line beneath them. + +* If it regresses + +Raise =cj/org-tag-right-margin= in =modules/org-config.el=, reload, and re-check +here. Confirm by the render above, not by recomputing column widths. diff --git a/tests/manual/headline-wrap/fixture.org b/tests/manual/headline-wrap/fixture.org new file mode 100644 index 00000000..9b4ae617 --- /dev/null +++ b/tests/manual/headline-wrap/fixture.org @@ -0,0 +1,28 @@ +#+TITLE: Headline-indicator wrap fixture +#+STARTUP: content + +# Regression fixture for the right-aligned-tag wrap bug. A folded heading that +# also has a property drawer renders two trailing indicators after its tag: the +# org-tidy inline symbol (" ·") and the fold ellipsis (" ▾"). If the tag-align +# reserve (cj/org-tag-right-margin in modules/org-config.el) is too small, those +# indicators spill onto a second screen row. Open this file, confirm every +# heading below stays on a single line. See README.org for steps. + +* Open Work +** TODO [#B] Interactive sort/order changes for the agenda view :feature: +:PROPERTIES: +:ID: one +:END: +Body text under the first heading so the subtree folds with an ellipsis. +** TODO [#C] Pager robustness: null customView and missing end-cursor :bug:discuss: +:PROPERTIES: +:ID: two +:END: +Body text under the second heading. +** TODO [#B] GitHub Actions CI :chore: +:PROPERTIES: +:ID: three +:END: +Body text under the third heading. +** TODO [#D] No property drawer here so org-tidy adds no dot :feature: +Body under a heading that has no properties drawer. -- cgit v1.2.3