Skip to content

Fix underline and strikethrough not being drawn across spaces - #2

Open
kay-ws wants to merge 1 commit into
antmicro:masterfrom
kay-ws:underline-across-spaces
Open

Fix underline and strikethrough not being drawn across spaces#2
kay-ws wants to merge 1 commit into
antmicro:masterfrom
kay-ws:underline-across-spaces

Conversation

@kay-ws

@kay-ws kay-ws commented Aug 28, 2026

Copy link
Copy Markdown

An underlined run that contains a space is drawn with gaps: ESC[4mA B C
produces three separate underline segments where other terminals produce one.
The same applies to strikethrough.

Cause

Screen::drawText() splits a line into runs of glyphs and runs of spaces.
Glyph runs reach drawGlyph(), which draws the decoration; space runs are
handled by a bare fillRect() that paints the background and nothing else:

if (draw_space) {
    draw_space = false;
    fillRect(startx, y, x - startx, FH(1), bc);
}

There are two such call sites — one inside the loop, one after it — and
neither is passed ul or st.

Fix

Rather than repeating the fillRect() pair at each site, the decoration is
factored into Screen::drawDecoration() and called from all three places. The
y offsets then live in one place, which is what keeps the glyph path and the
space path from drifting apart again — the drift is exactly what this bug is.

drawGlyph() passes its own h, which may have been clipped against the
bottom of the screen, rather than letting the helper re-read FH(1).

Reproducing

printf '\e[4mA B C\e[0m\n'
printf '\e[4m日本語 中文\e[0m\n'

Top: before, three and two segments respectively. Bottom: after, one continuous
underline in both cases, with the double-width cells still underlined for their
full width. Same framebuffer region, only the binary changed.

underline-across-spaces

Verification

Built and tested on x86_64 (Arch, i915drmfb console), where char is signed
and the underline path is otherwise healthy, so the change can be observed on
its own. Also present in an armv7l build; the two captures above are from the
same framebuffer region with only the binary changed.

The change itself has no platform-dependent parts.

drawText() splits a line into runs of glyphs and runs of spaces. Glyph runs
reach drawGlyph(), which draws the decoration; space runs are handled by a bare
fillRect() that paints the background only. An underlined run containing a
space is drawn with gaps, so ESC[4mA B C produces three separate underline
segments where other terminals produce one.

Factored the decoration into Screen::drawDecoration() and called it from both
paths, so the y offsets are defined once and the two cannot drift apart again.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@kay-ws

kay-ws commented Sep 3, 2026

Copy link
Copy Markdown
Author

@k-filipek — you added the decoration rendering in ccf83cf and #1 and #2 both
surfaced with it, so tagging you here rather than opening a separate thread.

There are three PRs open, all small and independent:

All three still merge cleanly. The one with a shelf life is this one:
src/screen.cpp moved in 2eb28a5 (SDL2) after the PR was opened, and
src/screen.h in c1502c0 (DRM/KMS) shortly before it. If it is easier to take
these once that work settles, I am glad to rebase whenever it suits you.
src/lib/vterm.h and vterm_states.cpp have been quiet since bde12cf, so #1
and #3 are in no hurry.

No rush on my side — I would just rather these not turn into conflicts you have
to untangle.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant