Skip to content

fix(xdisp): mode-line multibyte identity follows inputs, not content (#470) - #473

Merged
eval-exec merged 2 commits into
mainfrom
fix-470-mode-line-multibyte-identity
Oct 4, 2026
Merged

eval-exec merged 2 commits into
mainfrom
fix-470-mode-line-multibyte-identity

Conversation

@eval-exec

Copy link
Copy Markdown
Owner

Closes #470.

Root cause

into_display_output derived the rendered mode-line string's multibyte flag from its content (any(code > 0xFF)). A mode line whose only non-ASCII characters sit in U+0080..U+00FF — e.g. the reported · (U+00B7 MIDDLE DOT) — has every code inside one byte, so each later re-evaluation re-encoded the accumulated text as a unibyte string of raw bytes. GNU's redisplay renders a raw byte as the octal escape \ + %03o of CHAR_TO_BYTE8 (src/xdisp.c:8649-8662): exactly the reported "renders correctly, then turns into a literal \267".

Fix

GNU never re-encodes: a string's multibyte identity follows its inputs (the concat rule — multibyte iff any argument is multibyte; substring keeps the source flag). ModeLineRendered now carries that input-driven flag through every append path — strings, chars, string slices, re-derived renders, truncations — and into_display_output uses it instead of the content heuristic.

The unibyte decode arm maps each high byte to its byte8 character (BYTE8_TO_CHAR, src/character.h), so the char-code domain itself carries byte identity: byte8 codes make unibyte→multibyte promotion lossless (char_string's overlong raw-byte form) and the unibyte arm's as u8 is exactly GNU's CHAR_TO_BYTE8.

Empirical GNU 31.1 probes that pinned the oracle behavior: (string 183) is multibyte holding U+00B7 (princ emits c2 b7); a PTY mode line (list "A" "·" "B" (string 183) "C") renders A·B·C — both elements are identity cases, not legitimate raw-byte escapes. Pre-fix neomacs degraded both to A\267B\267C.

Verification

  • Core unit (new mode_line_multibyte_identity, 5 tests, red pre-fix): dot, whole degrading band U+0080..00FF, re-derivation transition, unibyte raw-byte GNU-parity control, above-band guard — 5/5; mode-line families 133/133; xdisp/display 601/601.
  • GNU oracle (oracle_mode_line_flow.rs, 2 new cases): format-mode-line result identity follows inputs and survives re-derivation through a second format-mode-line. Expects blessed from live Xvfb GNU 31.1 (NEOVM_ORACLE_MODE=refresh); neomacs snapshot mode matches.
  • TUI PTY pair (issue_470.rs): real GNU/neomacs pair, forced force-mode-line-update t + redisplay × 5, exact full-screen parity — green post-fix, red pre-fix.
  • GUI smoke: minibuffer_line_gui green (identity is decided in core before any frontend).

cargo fmt --all + cargo check --workspace --all-targets clean.

Full TUI sweep note

A full-suite run surfaced 8 failures outside this change: all 8 reproduce identically against a pre-fix baseline binary (base commit built in an isolated worktree + CARGO_TARGET_DIR, rerun via NEOMACS_TUI_NEOMACS_BIN). Decomposition: one wrap-fragile test predicate (message row wrapping depends on test PID length; GNU evaluates in 0.02 s), five vertico face-background divergences (Rgb(179,179,179) vs default), and the TTY scroll-bar-mode application divergence — pre-existing candidates for separate issues.

Copilot AI balanced review requested due to automatic review settings October 4, 2026 12:25
@coderabbitai

coderabbitai Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: bf62c841-57d3-4930-a509-b91e1c6efce1
📥 Commits

Reviewing files that changed from the base of the PR and between d3df587 and 87d4a87.

📒 Files selected for processing (1)
  • crates/neovm-core/src/emacs_core/display/xdisp/mod.rs

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 2 remain after this review.


📝 Walkthrough

Walkthrough

Mode-line rendering now tracks multibyte identity from its inputs and preserves it through composition, slicing, and output encoding. Core and oracle tests cover Unicode content and unibyte bytes. A paired-session test compares GNU Emacs and neomacs after repeated mode-line updates.

Changes

Mode-line string identity

Layer / File(s) Summary
Track multibyte identity
crates/neovm-core/src/emacs_core/display/xdisp/mod.rs
ModeLineRendered tracks input string identity as content is appended or sliced. Final output uses the tracked identity rather than inferring it from character codes.
Test mode-line string identity
crates/neovm-core/src/emacs_core/display/xdisp/mod.rs, crates/neovm-core/src/emacs_core/display/xdisp/tests/mode_line_multibyte_identity.rs, crates/neovm-oracle-tests/tests/oracle_mode_line_flow.rs
Core and oracle tests check multibyte output, preserved bytes, re-evaluation, unibyte raw-byte input, and Unicode above U+00FF.
Check repeated paired-session redisplay
crates/neomacs-tui-tests/tests/issue_470.rs, crates/neomacs-tui-tests/tests/tui.rs
The TUI regression test runs five mode-line update rounds in GNU Emacs and neomacs, then checks for · and matching screen contents.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Low

Merge Risk: ⚪ Minimal · up to 87d4a

Mode-line output preserves input string identity through repeated rendering, and the inspected byte8 path retains unibyte raw bytes. The added regression coverage addresses the reported rendering behavior; no actionable issue remains before merge.

Architecture Summary

Architecture risk: 🔵 Low · up to 87d4a

The change affects 1 system.

Changed systems: crates

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — crates (service) was modified; 5 changed files map to changed impact.

Before / after behavior

  • observed — Modified behavior in crates/neomacs-tui-tests/tests/issue_470.rs: Adds a Unix-only test module, documents the reported Unicode-dot regression, and imports the paired-session helpers and types used by the test.
  • observed — Modified behavior in crates/neomacs-tui-tests/tests/issue_470.rs: Defines the mode-line expression and a helper that boots both sessions, settles them, and configures stable mode-line text.
  • observed — Modified behavior in crates/neomacs-tui-tests/tests/issue_470.rs: Adds a helper that installs the test mode line and, for the requested number of rounds, forces a mode-line update and redisplay on both sessions, with a 100 ms delay per round.
  • observed — Modified behavior in crates/neomacs-tui-tests/tests/issue_470.rs: Adds a regression test that runs five update rounds, then asserts that both screens contain · and that their complete contents are identical.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.85% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 26 functions across 5 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: mode-line multibyte identity now follows its inputs.
Description check ✅ Passed The description explains the root cause, fix, relevant tests, and reported verification for the mode-line multibyte identity change.
Linked Issues check ✅ Passed Issue [#470] requires the middle dot to remain Unicode text through mode-line updates and redisplay, and suggests coverage for non-Latin-1 text. ModeLineRendered tracks input multibyte identity, and…
Out of Scope Changes check ✅ Passed The implementation in xdisp/mod.rs and the added core, oracle, and PTY tests address mode-line Unicode identity and the regression in issue [#470]. The TUI module registration enables the related PT…
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

It changes core mode-line string-identity and unibyte byte-decoding semantics shared across all redisplay paths, so human review of the encoding behavior is warranted despite comprehensive tests.

Review effort: Balanced
Findings: 1 Low severity

Open (1)
What changed in this PR

This PR fixes issue #470, where a mode line containing a Latin-1-supplement character (e.g. · U+00B7) initially rendered correctly but later degraded into the literal octal escape \267. The root cause was that into_display_output derived the rendered string's multibyte flag from its content (any(code > 0xFF)); since U+0080..U+00FF codes fit in one byte, the string was re-encoded as unibyte raw bytes on re-evaluation. The fix makes ModeLineRendered carry an input-driven multibyte flag (GNU's concat/substring identity rule) through every append path, and decodes unibyte high bytes as byte8 characters so byte identity survives any later multibyte promotion. This touches a core redisplay/string-encoding path shared by all mode-line formatting.

Changes:

  • Add an input-driven multibyte field to ModeLineRendered, OR-ing it in across string/char/slice/truncation/append paths, and use it in into_display_output instead of the content heuristic.
  • Decode unibyte high bytes via byte8 (BYTE8_TO_CHAR) in mode_line_string_char_codes so raw bytes stay byte-faithful through promotion.
  • Add core unit, GNU-oracle, and TUI PTY regression tests covering dot identity, the full U+0080..00FF band, re-derivation stability, and a unibyte raw-byte parity control.
File Description
crates/​neovm-core/​src/​emacs_core/​display/​xdisp/​mod.rs Adds the multibyte field and input-driven threading; updates unibyte decoding to byte8; registers the new test module.
crates/​neovm-core/​src/​emacs_core/​display/​xdisp/​tests/​mode_line_multibyte_identity.rs New core unit tests for mode-line multibyte identity (dot, band, re-derivation, unibyte control, above-band guard).
crates/​neovm-oracle-tests/​tests/​oracle_mode_line_flow.rs Adds two GNU-oracle parity cases asserting identity follows inputs and survives re-derivation.
crates/​neomacs-tui-tests/​tests/​issue_470.rs New TUI PTY regression asserting the dot stays a dot across forced mode-line updates with exact GNU parity.
crates/​neomacs-tui-tests/​tests/​tui.rs Registers the new issue_470 test module.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread crates/neovm-core/src/emacs_core/display/xdisp/mod.rs
@eval-exec
eval-exec force-pushed the fix-470-mode-line-multibyte-identity branch from d3df587 to 57c5a6b Compare October 4, 2026 13:00
…470)

`into_display_output' derived the rendered mode-line string's multibyte
flag from the accumulated character codes ("any code > 0xFF"), so a mode
line whose only non-ASCII characters live in U+0080..U+00FF -- e.g. the
U+00B7 MIDDLE DOT from issue #470 -- was re-encoded as a UNIBYTE string
of raw bytes on every later re-evaluation.  A raw byte displays as GNU's
octal escape (`\` + `%03o` of CHAR_TO_BYTE8, src/xdisp.c:8649-8662),
which is exactly the reported "dot renders correctly, then turns into a
literal `\267`".

GNU never re-encodes: a string's multibyte flag follows its INPUTS (the
`concat' rule -- multibyte iff any argument is multibyte), and
`substring' keeps the source string's flag.  `ModeLineRendered' now
carries that input-driven flag through every append path (strings,
chars, slices, re-derived renders, truncations), and the unibyte decode
arm maps each high byte to its byte8 character (`BYTE8_TO_CHAR`) so the
unibyte raw-byte identity survives promotion losslessly and re-truncates
through CHAR_TO_BYTE8 exactly like GNU.

Tests: 5 new unit tests cover the dot, the whole degrading band, the
re-derivation transition, the unibyte raw-byte GNU-parity control, and
the above-band guard.
…entity

The PTY-pair regression boots a real GNU/neomacs pair, installs a mode
line holding both a literal U+00B7 and `(string 183)`, and forces five
full mode-line re-evaluations: neomacs must render `A·B·C` identical to
GNU every time (pre-fix it degraded to `A\267B\267C`).  Probed on real
GNU 31.1: `(string 183)` is a MULTIBYTE string holding U+00B7 (princ
emits c2 b7, the mode line shows the dot glyph), so both elements are
identity cases, not legitimate raw-byte escapes.

Two active-oracle parity cases in oracle_mode_line_flow.rs assert
`format-mode-line` result identity through the GNU harness: multibyte
iff its inputs were multibyte, surviving a re-derivation through a
second `format-mode-line`.  Expects blessed from Xvfb GNU 31.1
(NEOVM_ORACLE_MODE=refresh); neomacs snapshot mode matches.

Verified: neovm-core mode-line families 133/133, xdisp/display 601/601,
TUI pair green (red pre-fix), oracle refresh+snapshot 2/2,
minibuffer_line_gui GUI smoke green.
@eval-exec
eval-exec force-pushed the fix-470-mode-line-multibyte-identity branch from 57c5a6b to 87d4a87 Compare October 4, 2026 13:01
@eval-exec
eval-exec requested a balanced review from Copilot October 4, 2026 13:08

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

It alters core redisplay multibyte/unibyte encoding semantics for all mode-line strings, a subtle and high-impact path that warrants final human review despite the comprehensive tests.

Review effort: Balanced
Findings: None

Resolved since last review (1)

@eval-exec
eval-exec merged commit 3901b48 into main Oct 4, 2026
28 of 36 checks passed
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.

Mode-line Unicode dot changes to literal \267 after initially rendering correctly

2 participants