Fixed word-wrapping: space at overflow no longer exceeds available_width - #159

Merged
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/issue-130-utf8-word-wrap
Jun 2, 2026
Merged

Fixed word-wrapping: space at overflow no longer exceeds available_width#159
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/issue-130-utf8-word-wrap

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

In _gx_multi_line_text_view_display_info_get() the overflow condition had a guard (ch.gx_string_ptr[0] != ' ') that prevented the overflow branch from executing when an ASCII space caused overflow. The space was instead added to gx_text_display_width, making it exceed available_width — the bug reported in issue #130.

Remove the guard and handle the space case explicitly: consume the overflowing space plus any immediately-following consecutive spaces in gx_text_display_number without adding to gx_text_display_width, then break. The trailing-spaces loop ensures that multiple spaces at the overflow boundary are all consumed so the next line starts at the next word (matching the behaviour of the old checkpoint-save path).

UTF-8 safety: ASCII 0x20 comparisons in the while loop are byte-safe because UTF-8 continuation bytes are always >= 0x80.

Files changed:

  • gx_multi_line_text_view_display_info_get.c

Regression test added:

  1. Space at overflow: gx_text_display_width <= available_width.
  2. Space at overflow: gx_text_display_number includes the trailing space (next line does not start with a space).
  3. Multiple consecutive spaces at overflow: all trailing spaces are consumed in gx_text_display_number.
  4. Normal word overflow (non-space char): backtrack to last word boundary still works correctly (no regression).

Closes#130

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

In _gx_multi_line_text_view_display_info_get() the overflow condition
had a guard (ch.gx_string_ptr[0] != ' ') that prevented the overflow
branch from executing when an ASCII space caused overflow. The space
was instead added to gx_text_display_width, making it exceed
available_width — the bug reported in issue eclipse-threadx#130.
Remove the guard and handle the space case explicitly: consume the
overflowing space plus any immediately-following consecutive spaces in
gx_text_display_number without adding to gx_text_display_width, then
break. The trailing-spaces loop ensures that multiple spaces at the
overflow boundary are all consumed so the next line starts at the next
word (matching the behaviour of the old checkpoint-save path).
UTF-8 safety: ASCII 0x20 comparisons in the while loop are byte-safe
because UTF-8 continuation bytes are always >= 0x80.
Files changed:
- gx_multi_line_text_view_display_info_get.c
Regression test added:
1. Space at overflow: gx_text_display_width <= available_width.
2. Space at overflow: gx_text_display_number includes the trailing
space (next line does not start with a space).
3. Multiple consecutive spaces at overflow: all trailing spaces are
consumed in gx_text_display_number.
4. Normal word overflow (non-space char): backtrack to last word
boundary still works correctly (no regression).
Closeseclipse-threadx#130
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens
fdesbiens merged commit b8bb23b into eclipse-threadx:devJun 2, 2026
1 check passed
@fdesbiens
fdesbiens deleted the fix/issue-130-utf8-word-wrap branch June 2, 2026 14:52
fdesbiens added a commit that referenced this pull request Aug 27, 2026
b8bb23b (#159) fixed issue #130 by letting the overflow branch of
_gx_multi_line_text_view_display_info_get() run when an ASCII space is the
character that overflows the available width. That branch consumes the space
and any consecutive spaces without adding them to the row width, which is
correct, and then breaks. When the whitespace ran to the end of the source
line, the line terminator was left behind: the next call started on it, hit
the GX_KEY_LINE_FEED case immediately and returned a row of one byte and zero
width, which draws as a blank line that is not in the text.
The overflow branch now takes the line terminator with the whitespace when
nothing else separates them, handling a bare line feed and a carriage return /
line feed pair, and guarding the second byte on the remaining length -- unlike
the pre-existing GX_KEY_CARRIAGE_RETURN case earlier in the same loop, which
reads ch.gx_string_ptr[1] unchecked. gx_text_display_width is untouched, so the
issue #130 fix stands.
Two such rows appear in the guix_ml_text_view_32bpp fixture, at string offsets
2992 and 23988 of readme_guix_generic.txt: "...Improved internal logic." with
twelve trailing spaces, and "...cursor_pos_calculate.c" with one. Both were
confirmed with a conditional breakpoint on display_number == 1 and
display_width == 0 preceded by a space, which fires exactly twice on the
pre-fix code and never after.
The two extra rows are why 268 of that test's 300 frames and 144 of
guix_bidi_text_draw_32bpp's 429 frames have differed from their golden data
since June. Nothing inside GUIX reads gx_text_display_width -- every caller
uses only gx_text_display_number, to advance its index -- so the row count
alone governs where every row starts, and two extra rows change the
scrollbar's value-to-pixel mapping. Every scroll step then lands at a slightly
different pixel offset and the whole text block is drawn a few pixels up or
down. Of the 300 frames, 297 were a pure vertical shift of otherwise identical
text; only 3 were laid out differently, and those 3 are the two places above.
No golden data is regenerated. gx_multi_line_text_view_text_total_rows for the
long text view goes back from 2226 to 2224, and both tests pass against their
existing golden files.
guix_ml_text_view_word_wrap_no_output did not protect #159's fix: it passed on
the pre-#159 code as well. Its available_width was one pixel too generous --
a_width + space_width, so the over-wide row the old code produced measured
exactly available_width and still satisfied "width <= available_width". It is
now a_width + space_width - 1, which makes appending the space genuinely
overflow, and three cases are added: a line feed terminator, a carriage return
/ line feed terminator, and the total row count that
_gx_multi_line_text_view_string_total_rows_compute() derives from them. That
last one is the quantity the golden frames actually depend on, and the only
one of the three a unit test can pin without golden data.
The test was verified to discriminate in both directions by rebuilding against
each. Against the pre-#159 source it fails four width assertions, which is
issue #130. Against #159 as shipped it fails the line feed row (2 bytes, not
3), the carriage return / line feed row (2, not 4) and the row count (3, not
2). It passes only with both fixes in place.
Verified on Linux across all eighteen build configurations, 1847 tests, no
failures. default_build_coverage 733/733, dynamic_bidi_text_build 3/3
including guix_bidi_text_draw_32bpp, no_utf8_build_coverage 135/135.
One coverage boundary worth naming: the unit test builds against the
all_widgets demo, which is not in NO_UTF8_DEMOS, so it runs in
default_build_coverage and disable_error_check_build but not in the
GX_UTF8_SUPPORT-off configurations. The changed code is common to both paths
-- only the surrounding character advance differs -- and no_utf8_build_coverage
covers it through its 135 golden tests.
No documentation change is required. _gx_multi_line_text_view_display_info_get
is internal, and the GUIX documentation does not describe multi-line text view
wrapping behaviour for trailing whitespace.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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

@fdesbiens
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Fixed word-wrapping: space at overflow no longer exceeds available_width - #159

Merged
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/issue-130-utf8-word-wrap
Jun 2, 2026
Merged

Fixed word-wrapping: space at overflow no longer exceeds available_width#159
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/issue-130-utf8-word-wrap

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

In _gx_multi_line_text_view_display_info_get() the overflow condition had a guard (ch.gx_string_ptr[0] != ' ') that prevented the overflow branch from executing when an ASCII space caused overflow. The space was instead added to gx_text_display_width, making it exceed available_width — the bug reported in issue #130.

Remove the guard and handle the space case explicitly: consume the overflowing space plus any immediately-following consecutive spaces in gx_text_display_number without adding to gx_text_display_width, then break. The trailing-spaces loop ensures that multiple spaces at the overflow boundary are all consumed so the next line starts at the next word (matching the behaviour of the old checkpoint-save path).

UTF-8 safety: ASCII 0x20 comparisons in the while loop are byte-safe because UTF-8 continuation bytes are always >= 0x80.

Files changed:

  • gx_multi_line_text_view_display_info_get.c

Regression test added:

  1. Space at overflow: gx_text_display_width <= available_width.
  2. Space at overflow: gx_text_display_number includes the trailing space (next line does not start with a space).
  3. Multiple consecutive spaces at overflow: all trailing spaces are consumed in gx_text_display_number.
  4. Normal word overflow (non-space char): backtrack to last word boundary still works correctly (no regression).

Closes#130

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

In _gx_multi_line_text_view_display_info_get() the overflow condition
had a guard (ch.gx_string_ptr[0] != ' ') that prevented the overflow
branch from executing when an ASCII space caused overflow. The space
was instead added to gx_text_display_width, making it exceed
available_width — the bug reported in issue eclipse-threadx#130.
Remove the guard and handle the space case explicitly: consume the
overflowing space plus any immediately-following consecutive spaces in
gx_text_display_number without adding to gx_text_display_width, then
break. The trailing-spaces loop ensures that multiple spaces at the
overflow boundary are all consumed so the next line starts at the next
word (matching the behaviour of the old checkpoint-save path).
UTF-8 safety: ASCII 0x20 comparisons in the while loop are byte-safe
because UTF-8 continuation bytes are always >= 0x80.
Files changed:
- gx_multi_line_text_view_display_info_get.c
Regression test added:
1. Space at overflow: gx_text_display_width <= available_width.
2. Space at overflow: gx_text_display_number includes the trailing
space (next line does not start with a space).
3. Multiple consecutive spaces at overflow: all trailing spaces are
consumed in gx_text_display_number.
4. Normal word overflow (non-space char): backtrack to last word
boundary still works correctly (no regression).
Closeseclipse-threadx#130
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens
fdesbiens merged commit b8bb23b into eclipse-threadx:devJun 2, 2026
1 check passed
@fdesbiens
fdesbiens deleted the fix/issue-130-utf8-word-wrap branch June 2, 2026 14:52
fdesbiens added a commit that referenced this pull request Aug 27, 2026
b8bb23b (#159) fixed issue #130 by letting the overflow branch of
_gx_multi_line_text_view_display_info_get() run when an ASCII space is the
character that overflows the available width. That branch consumes the space
and any consecutive spaces without adding them to the row width, which is
correct, and then breaks. When the whitespace ran to the end of the source
line, the line terminator was left behind: the next call started on it, hit
the GX_KEY_LINE_FEED case immediately and returned a row of one byte and zero
width, which draws as a blank line that is not in the text.
The overflow branch now takes the line terminator with the whitespace when
nothing else separates them, handling a bare line feed and a carriage return /
line feed pair, and guarding the second byte on the remaining length -- unlike
the pre-existing GX_KEY_CARRIAGE_RETURN case earlier in the same loop, which
reads ch.gx_string_ptr[1] unchecked. gx_text_display_width is untouched, so the
issue #130 fix stands.
Two such rows appear in the guix_ml_text_view_32bpp fixture, at string offsets
2992 and 23988 of readme_guix_generic.txt: "...Improved internal logic." with
twelve trailing spaces, and "...cursor_pos_calculate.c" with one. Both were
confirmed with a conditional breakpoint on display_number == 1 and
display_width == 0 preceded by a space, which fires exactly twice on the
pre-fix code and never after.
The two extra rows are why 268 of that test's 300 frames and 144 of
guix_bidi_text_draw_32bpp's 429 frames have differed from their golden data
since June. Nothing inside GUIX reads gx_text_display_width -- every caller
uses only gx_text_display_number, to advance its index -- so the row count
alone governs where every row starts, and two extra rows change the
scrollbar's value-to-pixel mapping. Every scroll step then lands at a slightly
different pixel offset and the whole text block is drawn a few pixels up or
down. Of the 300 frames, 297 were a pure vertical shift of otherwise identical
text; only 3 were laid out differently, and those 3 are the two places above.
No golden data is regenerated. gx_multi_line_text_view_text_total_rows for the
long text view goes back from 2226 to 2224, and both tests pass against their
existing golden files.
guix_ml_text_view_word_wrap_no_output did not protect #159's fix: it passed on
the pre-#159 code as well. Its available_width was one pixel too generous --
a_width + space_width, so the over-wide row the old code produced measured
exactly available_width and still satisfied "width <= available_width". It is
now a_width + space_width - 1, which makes appending the space genuinely
overflow, and three cases are added: a line feed terminator, a carriage return
/ line feed terminator, and the total row count that
_gx_multi_line_text_view_string_total_rows_compute() derives from them. That
last one is the quantity the golden frames actually depend on, and the only
one of the three a unit test can pin without golden data.
The test was verified to discriminate in both directions by rebuilding against
each. Against the pre-#159 source it fails four width assertions, which is
issue #130. Against #159 as shipped it fails the line feed row (2 bytes, not
3), the carriage return / line feed row (2, not 4) and the row count (3, not
2). It passes only with both fixes in place.
Verified on Linux across all eighteen build configurations, 1847 tests, no
failures. default_build_coverage 733/733, dynamic_bidi_text_build 3/3
including guix_bidi_text_draw_32bpp, no_utf8_build_coverage 135/135.
One coverage boundary worth naming: the unit test builds against the
all_widgets demo, which is not in NO_UTF8_DEMOS, so it runs in
default_build_coverage and disable_error_check_build but not in the
GX_UTF8_SUPPORT-off configurations. The changed code is common to both paths
-- only the surrounding character advance differs -- and no_utf8_build_coverage
covers it through its 135 golden tests.
No documentation change is required. _gx_multi_line_text_view_display_info_get
is internal, and the GUIX documentation does not describe multi-line text view
wrapping behaviour for trailing whitespace.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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

@fdesbiens
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fixed word-wrapping: space at overflow no longer exceeds available_width - #159

Merged
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/issue-130-utf8-word-wrap
Jun 2, 2026
Merged

Fixed word-wrapping: space at overflow no longer exceeds available_width#159
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/issue-130-utf8-word-wrap

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

In _gx_multi_line_text_view_display_info_get() the overflow condition had a guard (ch.gx_string_ptr[0] != ' ') that prevented the overflow branch from executing when an ASCII space caused overflow. The space was instead added to gx_text_display_width, making it exceed available_width — the bug reported in issue #130.

Remove the guard and handle the space case explicitly: consume the overflowing space plus any immediately-following consecutive spaces in gx_text_display_number without adding to gx_text_display_width, then break. The trailing-spaces loop ensures that multiple spaces at the overflow boundary are all consumed so the next line starts at the next word (matching the behaviour of the old checkpoint-save path).

UTF-8 safety: ASCII 0x20 comparisons in the while loop are byte-safe because UTF-8 continuation bytes are always >= 0x80.

Files changed:

  • gx_multi_line_text_view_display_info_get.c

Regression test added:

  1. Space at overflow: gx_text_display_width <= available_width.
  2. Space at overflow: gx_text_display_number includes the trailing space (next line does not start with a space).
  3. Multiple consecutive spaces at overflow: all trailing spaces are consumed in gx_text_display_number.
  4. Normal word overflow (non-space char): backtrack to last word boundary still works correctly (no regression).

Closes#130

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

In _gx_multi_line_text_view_display_info_get() the overflow condition
had a guard (ch.gx_string_ptr[0] != ' ') that prevented the overflow
branch from executing when an ASCII space caused overflow. The space
was instead added to gx_text_display_width, making it exceed
available_width — the bug reported in issue eclipse-threadx#130.
Remove the guard and handle the space case explicitly: consume the
overflowing space plus any immediately-following consecutive spaces in
gx_text_display_number without adding to gx_text_display_width, then
break. The trailing-spaces loop ensures that multiple spaces at the
overflow boundary are all consumed so the next line starts at the next
word (matching the behaviour of the old checkpoint-save path).
UTF-8 safety: ASCII 0x20 comparisons in the while loop are byte-safe
because UTF-8 continuation bytes are always >= 0x80.
Files changed:
- gx_multi_line_text_view_display_info_get.c
Regression test added:
1. Space at overflow: gx_text_display_width <= available_width.
2. Space at overflow: gx_text_display_number includes the trailing
space (next line does not start with a space).
3. Multiple consecutive spaces at overflow: all trailing spaces are
consumed in gx_text_display_number.
4. Normal word overflow (non-space char): backtrack to last word
boundary still works correctly (no regression).
Closeseclipse-threadx#130
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens
fdesbiens merged commit b8bb23b into eclipse-threadx:devJun 2, 2026
1 check passed
@fdesbiens
fdesbiens deleted the fix/issue-130-utf8-word-wrap branch June 2, 2026 14:52
fdesbiens added a commit that referenced this pull request Aug 27, 2026
b8bb23b (#159) fixed issue #130 by letting the overflow branch of
_gx_multi_line_text_view_display_info_get() run when an ASCII space is the
character that overflows the available width. That branch consumes the space
and any consecutive spaces without adding them to the row width, which is
correct, and then breaks. When the whitespace ran to the end of the source
line, the line terminator was left behind: the next call started on it, hit
the GX_KEY_LINE_FEED case immediately and returned a row of one byte and zero
width, which draws as a blank line that is not in the text.
The overflow branch now takes the line terminator with the whitespace when
nothing else separates them, handling a bare line feed and a carriage return /
line feed pair, and guarding the second byte on the remaining length -- unlike
the pre-existing GX_KEY_CARRIAGE_RETURN case earlier in the same loop, which
reads ch.gx_string_ptr[1] unchecked. gx_text_display_width is untouched, so the
issue #130 fix stands.
Two such rows appear in the guix_ml_text_view_32bpp fixture, at string offsets
2992 and 23988 of readme_guix_generic.txt: "...Improved internal logic." with
twelve trailing spaces, and "...cursor_pos_calculate.c" with one. Both were
confirmed with a conditional breakpoint on display_number == 1 and
display_width == 0 preceded by a space, which fires exactly twice on the
pre-fix code and never after.
The two extra rows are why 268 of that test's 300 frames and 144 of
guix_bidi_text_draw_32bpp's 429 frames have differed from their golden data
since June. Nothing inside GUIX reads gx_text_display_width -- every caller
uses only gx_text_display_number, to advance its index -- so the row count
alone governs where every row starts, and two extra rows change the
scrollbar's value-to-pixel mapping. Every scroll step then lands at a slightly
different pixel offset and the whole text block is drawn a few pixels up or
down. Of the 300 frames, 297 were a pure vertical shift of otherwise identical
text; only 3 were laid out differently, and those 3 are the two places above.
No golden data is regenerated. gx_multi_line_text_view_text_total_rows for the
long text view goes back from 2226 to 2224, and both tests pass against their
existing golden files.
guix_ml_text_view_word_wrap_no_output did not protect #159's fix: it passed on
the pre-#159 code as well. Its available_width was one pixel too generous --
a_width + space_width, so the over-wide row the old code produced measured
exactly available_width and still satisfied "width <= available_width". It is
now a_width + space_width - 1, which makes appending the space genuinely
overflow, and three cases are added: a line feed terminator, a carriage return
/ line feed terminator, and the total row count that
_gx_multi_line_text_view_string_total_rows_compute() derives from them. That
last one is the quantity the golden frames actually depend on, and the only
one of the three a unit test can pin without golden data.
The test was verified to discriminate in both directions by rebuilding against
each. Against the pre-#159 source it fails four width assertions, which is
issue #130. Against #159 as shipped it fails the line feed row (2 bytes, not
3), the carriage return / line feed row (2, not 4) and the row count (3, not
2). It passes only with both fixes in place.
Verified on Linux across all eighteen build configurations, 1847 tests, no
failures. default_build_coverage 733/733, dynamic_bidi_text_build 3/3
including guix_bidi_text_draw_32bpp, no_utf8_build_coverage 135/135.
One coverage boundary worth naming: the unit test builds against the
all_widgets demo, which is not in NO_UTF8_DEMOS, so it runs in
default_build_coverage and disable_error_check_build but not in the
GX_UTF8_SUPPORT-off configurations. The changed code is common to both paths
-- only the surrounding character advance differs -- and no_utf8_build_coverage
covers it through its 135 golden tests.
No documentation change is required. _gx_multi_line_text_view_display_info_get
is internal, and the GUIX documentation does not describe multi-line text view
wrapping behaviour for trailing whitespace.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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

@fdesbiens
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fixed word-wrapping: space at overflow no longer exceeds available_width - #159

Merged
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/issue-130-utf8-word-wrap
Jun 2, 2026
Merged

Fixed word-wrapping: space at overflow no longer exceeds available_width#159
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/issue-130-utf8-word-wrap

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

In _gx_multi_line_text_view_display_info_get() the overflow condition had a guard (ch.gx_string_ptr[0] != ' ') that prevented the overflow branch from executing when an ASCII space caused overflow. The space was instead added to gx_text_display_width, making it exceed available_width — the bug reported in issue #130.

Remove the guard and handle the space case explicitly: consume the overflowing space plus any immediately-following consecutive spaces in gx_text_display_number without adding to gx_text_display_width, then break. The trailing-spaces loop ensures that multiple spaces at the overflow boundary are all consumed so the next line starts at the next word (matching the behaviour of the old checkpoint-save path).

UTF-8 safety: ASCII 0x20 comparisons in the while loop are byte-safe because UTF-8 continuation bytes are always >= 0x80.

Files changed:

  • gx_multi_line_text_view_display_info_get.c

Regression test added:

  1. Space at overflow: gx_text_display_width <= available_width.
  2. Space at overflow: gx_text_display_number includes the trailing space (next line does not start with a space).
  3. Multiple consecutive spaces at overflow: all trailing spaces are consumed in gx_text_display_number.
  4. Normal word overflow (non-space char): backtrack to last word boundary still works correctly (no regression).

Closes#130

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

In _gx_multi_line_text_view_display_info_get() the overflow condition
had a guard (ch.gx_string_ptr[0] != ' ') that prevented the overflow
branch from executing when an ASCII space caused overflow. The space
was instead added to gx_text_display_width, making it exceed
available_width — the bug reported in issue eclipse-threadx#130.
Remove the guard and handle the space case explicitly: consume the
overflowing space plus any immediately-following consecutive spaces in
gx_text_display_number without adding to gx_text_display_width, then
break. The trailing-spaces loop ensures that multiple spaces at the
overflow boundary are all consumed so the next line starts at the next
word (matching the behaviour of the old checkpoint-save path).
UTF-8 safety: ASCII 0x20 comparisons in the while loop are byte-safe
because UTF-8 continuation bytes are always >= 0x80.
Files changed:
- gx_multi_line_text_view_display_info_get.c
Regression test added:
1. Space at overflow: gx_text_display_width <= available_width.
2. Space at overflow: gx_text_display_number includes the trailing
space (next line does not start with a space).
3. Multiple consecutive spaces at overflow: all trailing spaces are
consumed in gx_text_display_number.
4. Normal word overflow (non-space char): backtrack to last word
boundary still works correctly (no regression).
Closeseclipse-threadx#130
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens
fdesbiens merged commit b8bb23b into eclipse-threadx:devJun 2, 2026
1 check passed
@fdesbiens
fdesbiens deleted the fix/issue-130-utf8-word-wrap branch June 2, 2026 14:52
fdesbiens added a commit that referenced this pull request Aug 27, 2026
b8bb23b (#159) fixed issue #130 by letting the overflow branch of
_gx_multi_line_text_view_display_info_get() run when an ASCII space is the
character that overflows the available width. That branch consumes the space
and any consecutive spaces without adding them to the row width, which is
correct, and then breaks. When the whitespace ran to the end of the source
line, the line terminator was left behind: the next call started on it, hit
the GX_KEY_LINE_FEED case immediately and returned a row of one byte and zero
width, which draws as a blank line that is not in the text.
The overflow branch now takes the line terminator with the whitespace when
nothing else separates them, handling a bare line feed and a carriage return /
line feed pair, and guarding the second byte on the remaining length -- unlike
the pre-existing GX_KEY_CARRIAGE_RETURN case earlier in the same loop, which
reads ch.gx_string_ptr[1] unchecked. gx_text_display_width is untouched, so the
issue #130 fix stands.
Two such rows appear in the guix_ml_text_view_32bpp fixture, at string offsets
2992 and 23988 of readme_guix_generic.txt: "...Improved internal logic." with
twelve trailing spaces, and "...cursor_pos_calculate.c" with one. Both were
confirmed with a conditional breakpoint on display_number == 1 and
display_width == 0 preceded by a space, which fires exactly twice on the
pre-fix code and never after.
The two extra rows are why 268 of that test's 300 frames and 144 of
guix_bidi_text_draw_32bpp's 429 frames have differed from their golden data
since June. Nothing inside GUIX reads gx_text_display_width -- every caller
uses only gx_text_display_number, to advance its index -- so the row count
alone governs where every row starts, and two extra rows change the
scrollbar's value-to-pixel mapping. Every scroll step then lands at a slightly
different pixel offset and the whole text block is drawn a few pixels up or
down. Of the 300 frames, 297 were a pure vertical shift of otherwise identical
text; only 3 were laid out differently, and those 3 are the two places above.
No golden data is regenerated. gx_multi_line_text_view_text_total_rows for the
long text view goes back from 2226 to 2224, and both tests pass against their
existing golden files.
guix_ml_text_view_word_wrap_no_output did not protect #159's fix: it passed on
the pre-#159 code as well. Its available_width was one pixel too generous --
a_width + space_width, so the over-wide row the old code produced measured
exactly available_width and still satisfied "width <= available_width". It is
now a_width + space_width - 1, which makes appending the space genuinely
overflow, and three cases are added: a line feed terminator, a carriage return
/ line feed terminator, and the total row count that
_gx_multi_line_text_view_string_total_rows_compute() derives from them. That
last one is the quantity the golden frames actually depend on, and the only
one of the three a unit test can pin without golden data.
The test was verified to discriminate in both directions by rebuilding against
each. Against the pre-#159 source it fails four width assertions, which is
issue #130. Against #159 as shipped it fails the line feed row (2 bytes, not
3), the carriage return / line feed row (2, not 4) and the row count (3, not
2). It passes only with both fixes in place.
Verified on Linux across all eighteen build configurations, 1847 tests, no
failures. default_build_coverage 733/733, dynamic_bidi_text_build 3/3
including guix_bidi_text_draw_32bpp, no_utf8_build_coverage 135/135.
One coverage boundary worth naming: the unit test builds against the
all_widgets demo, which is not in NO_UTF8_DEMOS, so it runs in
default_build_coverage and disable_error_check_build but not in the
GX_UTF8_SUPPORT-off configurations. The changed code is common to both paths
-- only the surrounding character advance differs -- and no_utf8_build_coverage
covers it through its 135 golden tests.
No documentation change is required. _gx_multi_line_text_view_display_info_get
is internal, and the GUIX documentation does not describe multi-line text view
wrapping behaviour for trailing whitespace.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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

@fdesbiens
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Fixed word-wrapping: space at overflow no longer exceeds available_width - #159

Merged
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/issue-130-utf8-word-wrap
Jun 2, 2026
Merged

Fixed word-wrapping: space at overflow no longer exceeds available_width#159
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/issue-130-utf8-word-wrap

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

In _gx_multi_line_text_view_display_info_get() the overflow condition had a guard (ch.gx_string_ptr[0] != ' ') that prevented the overflow branch from executing when an ASCII space caused overflow. The space was instead added to gx_text_display_width, making it exceed available_width — the bug reported in issue #130.

Remove the guard and handle the space case explicitly: consume the overflowing space plus any immediately-following consecutive spaces in gx_text_display_number without adding to gx_text_display_width, then break. The trailing-spaces loop ensures that multiple spaces at the overflow boundary are all consumed so the next line starts at the next word (matching the behaviour of the old checkpoint-save path).

UTF-8 safety: ASCII 0x20 comparisons in the while loop are byte-safe because UTF-8 continuation bytes are always >= 0x80.

Files changed:

  • gx_multi_line_text_view_display_info_get.c

Regression test added:

  1. Space at overflow: gx_text_display_width <= available_width.
  2. Space at overflow: gx_text_display_number includes the trailing space (next line does not start with a space).
  3. Multiple consecutive spaces at overflow: all trailing spaces are consumed in gx_text_display_number.
  4. Normal word overflow (non-space char): backtrack to last word boundary still works correctly (no regression).

Closes#130

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

In _gx_multi_line_text_view_display_info_get() the overflow condition
had a guard (ch.gx_string_ptr[0] != ' ') that prevented the overflow
branch from executing when an ASCII space caused overflow. The space
was instead added to gx_text_display_width, making it exceed
available_width — the bug reported in issue eclipse-threadx#130.
Remove the guard and handle the space case explicitly: consume the
overflowing space plus any immediately-following consecutive spaces in
gx_text_display_number without adding to gx_text_display_width, then
break. The trailing-spaces loop ensures that multiple spaces at the
overflow boundary are all consumed so the next line starts at the next
word (matching the behaviour of the old checkpoint-save path).
UTF-8 safety: ASCII 0x20 comparisons in the while loop are byte-safe
because UTF-8 continuation bytes are always >= 0x80.
Files changed:
- gx_multi_line_text_view_display_info_get.c
Regression test added:
1. Space at overflow: gx_text_display_width <= available_width.
2. Space at overflow: gx_text_display_number includes the trailing
space (next line does not start with a space).
3. Multiple consecutive spaces at overflow: all trailing spaces are
consumed in gx_text_display_number.
4. Normal word overflow (non-space char): backtrack to last word
boundary still works correctly (no regression).
Closeseclipse-threadx#130
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens
fdesbiens merged commit b8bb23b into eclipse-threadx:devJun 2, 2026
1 check passed
@fdesbiens
fdesbiens deleted the fix/issue-130-utf8-word-wrap branch June 2, 2026 14:52
fdesbiens added a commit that referenced this pull request Aug 27, 2026
b8bb23b (#159) fixed issue #130 by letting the overflow branch of
_gx_multi_line_text_view_display_info_get() run when an ASCII space is the
character that overflows the available width. That branch consumes the space
and any consecutive spaces without adding them to the row width, which is
correct, and then breaks. When the whitespace ran to the end of the source
line, the line terminator was left behind: the next call started on it, hit
the GX_KEY_LINE_FEED case immediately and returned a row of one byte and zero
width, which draws as a blank line that is not in the text.
The overflow branch now takes the line terminator with the whitespace when
nothing else separates them, handling a bare line feed and a carriage return /
line feed pair, and guarding the second byte on the remaining length -- unlike
the pre-existing GX_KEY_CARRIAGE_RETURN case earlier in the same loop, which
reads ch.gx_string_ptr[1] unchecked. gx_text_display_width is untouched, so the
issue #130 fix stands.
Two such rows appear in the guix_ml_text_view_32bpp fixture, at string offsets
2992 and 23988 of readme_guix_generic.txt: "...Improved internal logic." with
twelve trailing spaces, and "...cursor_pos_calculate.c" with one. Both were
confirmed with a conditional breakpoint on display_number == 1 and
display_width == 0 preceded by a space, which fires exactly twice on the
pre-fix code and never after.
The two extra rows are why 268 of that test's 300 frames and 144 of
guix_bidi_text_draw_32bpp's 429 frames have differed from their golden data
since June. Nothing inside GUIX reads gx_text_display_width -- every caller
uses only gx_text_display_number, to advance its index -- so the row count
alone governs where every row starts, and two extra rows change the
scrollbar's value-to-pixel mapping. Every scroll step then lands at a slightly
different pixel offset and the whole text block is drawn a few pixels up or
down. Of the 300 frames, 297 were a pure vertical shift of otherwise identical
text; only 3 were laid out differently, and those 3 are the two places above.
No golden data is regenerated. gx_multi_line_text_view_text_total_rows for the
long text view goes back from 2226 to 2224, and both tests pass against their
existing golden files.
guix_ml_text_view_word_wrap_no_output did not protect #159's fix: it passed on
the pre-#159 code as well. Its available_width was one pixel too generous --
a_width + space_width, so the over-wide row the old code produced measured
exactly available_width and still satisfied "width <= available_width". It is
now a_width + space_width - 1, which makes appending the space genuinely
overflow, and three cases are added: a line feed terminator, a carriage return
/ line feed terminator, and the total row count that
_gx_multi_line_text_view_string_total_rows_compute() derives from them. That
last one is the quantity the golden frames actually depend on, and the only
one of the three a unit test can pin without golden data.
The test was verified to discriminate in both directions by rebuilding against
each. Against the pre-#159 source it fails four width assertions, which is
issue #130. Against #159 as shipped it fails the line feed row (2 bytes, not
3), the carriage return / line feed row (2, not 4) and the row count (3, not
2). It passes only with both fixes in place.
Verified on Linux across all eighteen build configurations, 1847 tests, no
failures. default_build_coverage 733/733, dynamic_bidi_text_build 3/3
including guix_bidi_text_draw_32bpp, no_utf8_build_coverage 135/135.
One coverage boundary worth naming: the unit test builds against the
all_widgets demo, which is not in NO_UTF8_DEMOS, so it runs in
default_build_coverage and disable_error_check_build but not in the
GX_UTF8_SUPPORT-off configurations. The changed code is common to both paths
-- only the surrounding character advance differs -- and no_utf8_build_coverage
covers it through its 135 golden tests.
No documentation change is required. _gx_multi_line_text_view_display_info_get
is internal, and the GUIX documentation does not describe multi-line text view
wrapping behaviour for trailing whitespace.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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

@fdesbiens
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fixed word-wrapping: space at overflow no longer exceeds available_width - #159

Merged
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/issue-130-utf8-word-wrap
Jun 2, 2026
Merged

Fixed word-wrapping: space at overflow no longer exceeds available_width#159
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/issue-130-utf8-word-wrap

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

In _gx_multi_line_text_view_display_info_get() the overflow condition had a guard (ch.gx_string_ptr[0] != ' ') that prevented the overflow branch from executing when an ASCII space caused overflow. The space was instead added to gx_text_display_width, making it exceed available_width — the bug reported in issue #130.

Remove the guard and handle the space case explicitly: consume the overflowing space plus any immediately-following consecutive spaces in gx_text_display_number without adding to gx_text_display_width, then break. The trailing-spaces loop ensures that multiple spaces at the overflow boundary are all consumed so the next line starts at the next word (matching the behaviour of the old checkpoint-save path).

UTF-8 safety: ASCII 0x20 comparisons in the while loop are byte-safe because UTF-8 continuation bytes are always >= 0x80.

Files changed:

  • gx_multi_line_text_view_display_info_get.c

Regression test added:

  1. Space at overflow: gx_text_display_width <= available_width.
  2. Space at overflow: gx_text_display_number includes the trailing space (next line does not start with a space).
  3. Multiple consecutive spaces at overflow: all trailing spaces are consumed in gx_text_display_number.
  4. Normal word overflow (non-space char): backtrack to last word boundary still works correctly (no regression).

Closes#130

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

In _gx_multi_line_text_view_display_info_get() the overflow condition
had a guard (ch.gx_string_ptr[0] != ' ') that prevented the overflow
branch from executing when an ASCII space caused overflow. The space
was instead added to gx_text_display_width, making it exceed
available_width — the bug reported in issue eclipse-threadx#130.
Remove the guard and handle the space case explicitly: consume the
overflowing space plus any immediately-following consecutive spaces in
gx_text_display_number without adding to gx_text_display_width, then
break. The trailing-spaces loop ensures that multiple spaces at the
overflow boundary are all consumed so the next line starts at the next
word (matching the behaviour of the old checkpoint-save path).
UTF-8 safety: ASCII 0x20 comparisons in the while loop are byte-safe
because UTF-8 continuation bytes are always >= 0x80.
Files changed:
- gx_multi_line_text_view_display_info_get.c
Regression test added:
1. Space at overflow: gx_text_display_width <= available_width.
2. Space at overflow: gx_text_display_number includes the trailing
space (next line does not start with a space).
3. Multiple consecutive spaces at overflow: all trailing spaces are
consumed in gx_text_display_number.
4. Normal word overflow (non-space char): backtrack to last word
boundary still works correctly (no regression).
Closeseclipse-threadx#130
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens
fdesbiens merged commit b8bb23b into eclipse-threadx:devJun 2, 2026
1 check passed
@fdesbiens
fdesbiens deleted the fix/issue-130-utf8-word-wrap branch June 2, 2026 14:52
fdesbiens added a commit that referenced this pull request Aug 27, 2026
b8bb23b (#159) fixed issue #130 by letting the overflow branch of
_gx_multi_line_text_view_display_info_get() run when an ASCII space is the
character that overflows the available width. That branch consumes the space
and any consecutive spaces without adding them to the row width, which is
correct, and then breaks. When the whitespace ran to the end of the source
line, the line terminator was left behind: the next call started on it, hit
the GX_KEY_LINE_FEED case immediately and returned a row of one byte and zero
width, which draws as a blank line that is not in the text.
The overflow branch now takes the line terminator with the whitespace when
nothing else separates them, handling a bare line feed and a carriage return /
line feed pair, and guarding the second byte on the remaining length -- unlike
the pre-existing GX_KEY_CARRIAGE_RETURN case earlier in the same loop, which
reads ch.gx_string_ptr[1] unchecked. gx_text_display_width is untouched, so the
issue #130 fix stands.
Two such rows appear in the guix_ml_text_view_32bpp fixture, at string offsets
2992 and 23988 of readme_guix_generic.txt: "...Improved internal logic." with
twelve trailing spaces, and "...cursor_pos_calculate.c" with one. Both were
confirmed with a conditional breakpoint on display_number == 1 and
display_width == 0 preceded by a space, which fires exactly twice on the
pre-fix code and never after.
The two extra rows are why 268 of that test's 300 frames and 144 of
guix_bidi_text_draw_32bpp's 429 frames have differed from their golden data
since June. Nothing inside GUIX reads gx_text_display_width -- every caller
uses only gx_text_display_number, to advance its index -- so the row count
alone governs where every row starts, and two extra rows change the
scrollbar's value-to-pixel mapping. Every scroll step then lands at a slightly
different pixel offset and the whole text block is drawn a few pixels up or
down. Of the 300 frames, 297 were a pure vertical shift of otherwise identical
text; only 3 were laid out differently, and those 3 are the two places above.
No golden data is regenerated. gx_multi_line_text_view_text_total_rows for the
long text view goes back from 2226 to 2224, and both tests pass against their
existing golden files.
guix_ml_text_view_word_wrap_no_output did not protect #159's fix: it passed on
the pre-#159 code as well. Its available_width was one pixel too generous --
a_width + space_width, so the over-wide row the old code produced measured
exactly available_width and still satisfied "width <= available_width". It is
now a_width + space_width - 1, which makes appending the space genuinely
overflow, and three cases are added: a line feed terminator, a carriage return
/ line feed terminator, and the total row count that
_gx_multi_line_text_view_string_total_rows_compute() derives from them. That
last one is the quantity the golden frames actually depend on, and the only
one of the three a unit test can pin without golden data.
The test was verified to discriminate in both directions by rebuilding against
each. Against the pre-#159 source it fails four width assertions, which is
issue #130. Against #159 as shipped it fails the line feed row (2 bytes, not
3), the carriage return / line feed row (2, not 4) and the row count (3, not
2). It passes only with both fixes in place.
Verified on Linux across all eighteen build configurations, 1847 tests, no
failures. default_build_coverage 733/733, dynamic_bidi_text_build 3/3
including guix_bidi_text_draw_32bpp, no_utf8_build_coverage 135/135.
One coverage boundary worth naming: the unit test builds against the
all_widgets demo, which is not in NO_UTF8_DEMOS, so it runs in
default_build_coverage and disable_error_check_build but not in the
GX_UTF8_SUPPORT-off configurations. The changed code is common to both paths
-- only the surrounding character advance differs -- and no_utf8_build_coverage
covers it through its 135 golden tests.
No documentation change is required. _gx_multi_line_text_view_display_info_get
is internal, and the GUIX documentation does not describe multi-line text view
wrapping behaviour for trailing whitespace.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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

@fdesbiens
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fixed word-wrapping: space at overflow no longer exceeds available_width - #159

Merged
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/issue-130-utf8-word-wrap
Jun 2, 2026
Merged

Fixed word-wrapping: space at overflow no longer exceeds available_width#159
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/issue-130-utf8-word-wrap

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

In _gx_multi_line_text_view_display_info_get() the overflow condition had a guard (ch.gx_string_ptr[0] != ' ') that prevented the overflow branch from executing when an ASCII space caused overflow. The space was instead added to gx_text_display_width, making it exceed available_width — the bug reported in issue #130.

Remove the guard and handle the space case explicitly: consume the overflowing space plus any immediately-following consecutive spaces in gx_text_display_number without adding to gx_text_display_width, then break. The trailing-spaces loop ensures that multiple spaces at the overflow boundary are all consumed so the next line starts at the next word (matching the behaviour of the old checkpoint-save path).

UTF-8 safety: ASCII 0x20 comparisons in the while loop are byte-safe because UTF-8 continuation bytes are always >= 0x80.

Files changed:

  • gx_multi_line_text_view_display_info_get.c

Regression test added:

  1. Space at overflow: gx_text_display_width <= available_width.
  2. Space at overflow: gx_text_display_number includes the trailing space (next line does not start with a space).
  3. Multiple consecutive spaces at overflow: all trailing spaces are consumed in gx_text_display_number.
  4. Normal word overflow (non-space char): backtrack to last word boundary still works correctly (no regression).

Closes#130

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

In _gx_multi_line_text_view_display_info_get() the overflow condition
had a guard (ch.gx_string_ptr[0] != ' ') that prevented the overflow
branch from executing when an ASCII space caused overflow. The space
was instead added to gx_text_display_width, making it exceed
available_width — the bug reported in issue eclipse-threadx#130.
Remove the guard and handle the space case explicitly: consume the
overflowing space plus any immediately-following consecutive spaces in
gx_text_display_number without adding to gx_text_display_width, then
break. The trailing-spaces loop ensures that multiple spaces at the
overflow boundary are all consumed so the next line starts at the next
word (matching the behaviour of the old checkpoint-save path).
UTF-8 safety: ASCII 0x20 comparisons in the while loop are byte-safe
because UTF-8 continuation bytes are always >= 0x80.
Files changed:
- gx_multi_line_text_view_display_info_get.c
Regression test added:
1. Space at overflow: gx_text_display_width <= available_width.
2. Space at overflow: gx_text_display_number includes the trailing
space (next line does not start with a space).
3. Multiple consecutive spaces at overflow: all trailing spaces are
consumed in gx_text_display_number.
4. Normal word overflow (non-space char): backtrack to last word
boundary still works correctly (no regression).
Closeseclipse-threadx#130
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens
fdesbiens merged commit b8bb23b into eclipse-threadx:devJun 2, 2026
1 check passed
@fdesbiens
fdesbiens deleted the fix/issue-130-utf8-word-wrap branch June 2, 2026 14:52
fdesbiens added a commit that referenced this pull request Aug 27, 2026
b8bb23b (#159) fixed issue #130 by letting the overflow branch of
_gx_multi_line_text_view_display_info_get() run when an ASCII space is the
character that overflows the available width. That branch consumes the space
and any consecutive spaces without adding them to the row width, which is
correct, and then breaks. When the whitespace ran to the end of the source
line, the line terminator was left behind: the next call started on it, hit
the GX_KEY_LINE_FEED case immediately and returned a row of one byte and zero
width, which draws as a blank line that is not in the text.
The overflow branch now takes the line terminator with the whitespace when
nothing else separates them, handling a bare line feed and a carriage return /
line feed pair, and guarding the second byte on the remaining length -- unlike
the pre-existing GX_KEY_CARRIAGE_RETURN case earlier in the same loop, which
reads ch.gx_string_ptr[1] unchecked. gx_text_display_width is untouched, so the
issue #130 fix stands.
Two such rows appear in the guix_ml_text_view_32bpp fixture, at string offsets
2992 and 23988 of readme_guix_generic.txt: "...Improved internal logic." with
twelve trailing spaces, and "...cursor_pos_calculate.c" with one. Both were
confirmed with a conditional breakpoint on display_number == 1 and
display_width == 0 preceded by a space, which fires exactly twice on the
pre-fix code and never after.
The two extra rows are why 268 of that test's 300 frames and 144 of
guix_bidi_text_draw_32bpp's 429 frames have differed from their golden data
since June. Nothing inside GUIX reads gx_text_display_width -- every caller
uses only gx_text_display_number, to advance its index -- so the row count
alone governs where every row starts, and two extra rows change the
scrollbar's value-to-pixel mapping. Every scroll step then lands at a slightly
different pixel offset and the whole text block is drawn a few pixels up or
down. Of the 300 frames, 297 were a pure vertical shift of otherwise identical
text; only 3 were laid out differently, and those 3 are the two places above.
No golden data is regenerated. gx_multi_line_text_view_text_total_rows for the
long text view goes back from 2226 to 2224, and both tests pass against their
existing golden files.
guix_ml_text_view_word_wrap_no_output did not protect #159's fix: it passed on
the pre-#159 code as well. Its available_width was one pixel too generous --
a_width + space_width, so the over-wide row the old code produced measured
exactly available_width and still satisfied "width <= available_width". It is
now a_width + space_width - 1, which makes appending the space genuinely
overflow, and three cases are added: a line feed terminator, a carriage return
/ line feed terminator, and the total row count that
_gx_multi_line_text_view_string_total_rows_compute() derives from them. That
last one is the quantity the golden frames actually depend on, and the only
one of the three a unit test can pin without golden data.
The test was verified to discriminate in both directions by rebuilding against
each. Against the pre-#159 source it fails four width assertions, which is
issue #130. Against #159 as shipped it fails the line feed row (2 bytes, not
3), the carriage return / line feed row (2, not 4) and the row count (3, not
2). It passes only with both fixes in place.
Verified on Linux across all eighteen build configurations, 1847 tests, no
failures. default_build_coverage 733/733, dynamic_bidi_text_build 3/3
including guix_bidi_text_draw_32bpp, no_utf8_build_coverage 135/135.
One coverage boundary worth naming: the unit test builds against the
all_widgets demo, which is not in NO_UTF8_DEMOS, so it runs in
default_build_coverage and disable_error_check_build but not in the
GX_UTF8_SUPPORT-off configurations. The changed code is common to both paths
-- only the surrounding character advance differs -- and no_utf8_build_coverage
covers it through its 135 golden tests.
No documentation change is required. _gx_multi_line_text_view_display_info_get
is internal, and the GUIX documentation does not describe multi-line text view
wrapping behaviour for trailing whitespace.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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

@fdesbiens
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Fixed word-wrapping: space at overflow no longer exceeds available_width - #159

Merged
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/issue-130-utf8-word-wrap
Jun 2, 2026
Merged

Fixed word-wrapping: space at overflow no longer exceeds available_width#159
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/issue-130-utf8-word-wrap

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

In _gx_multi_line_text_view_display_info_get() the overflow condition had a guard (ch.gx_string_ptr[0] != ' ') that prevented the overflow branch from executing when an ASCII space caused overflow. The space was instead added to gx_text_display_width, making it exceed available_width — the bug reported in issue #130.

Remove the guard and handle the space case explicitly: consume the overflowing space plus any immediately-following consecutive spaces in gx_text_display_number without adding to gx_text_display_width, then break. The trailing-spaces loop ensures that multiple spaces at the overflow boundary are all consumed so the next line starts at the next word (matching the behaviour of the old checkpoint-save path).

UTF-8 safety: ASCII 0x20 comparisons in the while loop are byte-safe because UTF-8 continuation bytes are always >= 0x80.

Files changed:

  • gx_multi_line_text_view_display_info_get.c

Regression test added:

  1. Space at overflow: gx_text_display_width <= available_width.
  2. Space at overflow: gx_text_display_number includes the trailing space (next line does not start with a space).
  3. Multiple consecutive spaces at overflow: all trailing spaces are consumed in gx_text_display_number.
  4. Normal word overflow (non-space char): backtrack to last word boundary still works correctly (no regression).

Closes#130

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

In _gx_multi_line_text_view_display_info_get() the overflow condition
had a guard (ch.gx_string_ptr[0] != ' ') that prevented the overflow
branch from executing when an ASCII space caused overflow. The space
was instead added to gx_text_display_width, making it exceed
available_width — the bug reported in issue eclipse-threadx#130.
Remove the guard and handle the space case explicitly: consume the
overflowing space plus any immediately-following consecutive spaces in
gx_text_display_number without adding to gx_text_display_width, then
break. The trailing-spaces loop ensures that multiple spaces at the
overflow boundary are all consumed so the next line starts at the next
word (matching the behaviour of the old checkpoint-save path).
UTF-8 safety: ASCII 0x20 comparisons in the while loop are byte-safe
because UTF-8 continuation bytes are always >= 0x80.
Files changed:
- gx_multi_line_text_view_display_info_get.c
Regression test added:
1. Space at overflow: gx_text_display_width <= available_width.
2. Space at overflow: gx_text_display_number includes the trailing
space (next line does not start with a space).
3. Multiple consecutive spaces at overflow: all trailing spaces are
consumed in gx_text_display_number.
4. Normal word overflow (non-space char): backtrack to last word
boundary still works correctly (no regression).
Closeseclipse-threadx#130
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens
fdesbiens merged commit b8bb23b into eclipse-threadx:devJun 2, 2026
1 check passed
@fdesbiens
fdesbiens deleted the fix/issue-130-utf8-word-wrap branch June 2, 2026 14:52
fdesbiens added a commit that referenced this pull request Aug 27, 2026
b8bb23b (#159) fixed issue #130 by letting the overflow branch of
_gx_multi_line_text_view_display_info_get() run when an ASCII space is the
character that overflows the available width. That branch consumes the space
and any consecutive spaces without adding them to the row width, which is
correct, and then breaks. When the whitespace ran to the end of the source
line, the line terminator was left behind: the next call started on it, hit
the GX_KEY_LINE_FEED case immediately and returned a row of one byte and zero
width, which draws as a blank line that is not in the text.
The overflow branch now takes the line terminator with the whitespace when
nothing else separates them, handling a bare line feed and a carriage return /
line feed pair, and guarding the second byte on the remaining length -- unlike
the pre-existing GX_KEY_CARRIAGE_RETURN case earlier in the same loop, which
reads ch.gx_string_ptr[1] unchecked. gx_text_display_width is untouched, so the
issue #130 fix stands.
Two such rows appear in the guix_ml_text_view_32bpp fixture, at string offsets
2992 and 23988 of readme_guix_generic.txt: "...Improved internal logic." with
twelve trailing spaces, and "...cursor_pos_calculate.c" with one. Both were
confirmed with a conditional breakpoint on display_number == 1 and
display_width == 0 preceded by a space, which fires exactly twice on the
pre-fix code and never after.
The two extra rows are why 268 of that test's 300 frames and 144 of
guix_bidi_text_draw_32bpp's 429 frames have differed from their golden data
since June. Nothing inside GUIX reads gx_text_display_width -- every caller
uses only gx_text_display_number, to advance its index -- so the row count
alone governs where every row starts, and two extra rows change the
scrollbar's value-to-pixel mapping. Every scroll step then lands at a slightly
different pixel offset and the whole text block is drawn a few pixels up or
down. Of the 300 frames, 297 were a pure vertical shift of otherwise identical
text; only 3 were laid out differently, and those 3 are the two places above.
No golden data is regenerated. gx_multi_line_text_view_text_total_rows for the
long text view goes back from 2226 to 2224, and both tests pass against their
existing golden files.
guix_ml_text_view_word_wrap_no_output did not protect #159's fix: it passed on
the pre-#159 code as well. Its available_width was one pixel too generous --
a_width + space_width, so the over-wide row the old code produced measured
exactly available_width and still satisfied "width <= available_width". It is
now a_width + space_width - 1, which makes appending the space genuinely
overflow, and three cases are added: a line feed terminator, a carriage return
/ line feed terminator, and the total row count that
_gx_multi_line_text_view_string_total_rows_compute() derives from them. That
last one is the quantity the golden frames actually depend on, and the only
one of the three a unit test can pin without golden data.
The test was verified to discriminate in both directions by rebuilding against
each. Against the pre-#159 source it fails four width assertions, which is
issue #130. Against #159 as shipped it fails the line feed row (2 bytes, not
3), the carriage return / line feed row (2, not 4) and the row count (3, not
2). It passes only with both fixes in place.
Verified on Linux across all eighteen build configurations, 1847 tests, no
failures. default_build_coverage 733/733, dynamic_bidi_text_build 3/3
including guix_bidi_text_draw_32bpp, no_utf8_build_coverage 135/135.
One coverage boundary worth naming: the unit test builds against the
all_widgets demo, which is not in NO_UTF8_DEMOS, so it runs in
default_build_coverage and disable_error_check_build but not in the
GX_UTF8_SUPPORT-off configurations. The changed code is common to both paths
-- only the surrounding character advance differs -- and no_utf8_build_coverage
covers it through its 135 golden tests.
No documentation change is required. _gx_multi_line_text_view_display_info_get
is internal, and the GUIX documentation does not describe multi-line text view
wrapping behaviour for trailing whitespace.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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

@fdesbiens