fix(cli): unicode-safe rendering across TUI and commands (3.2.4)#53
Merged
fix(cli): unicode-safe rendering across TUI and commands (3.2.4)#53
Conversation
Follow-up to 3.2.3. The UTF-8 panic fix in `wrap_cell_text()` exposed the same byte-vs-visual-column confusion scattered across the rest of the CLI. This patch removes the class of bugs, not just the specific instance, by introducing shared visual-width helpers and routing every layout site through them. TUI: - `explore` scrollbar no longer leaks the document text through the track: the paragraph now renders in a reserved body column and the scrollbar gets its own. `ScrollbarState::viewport_content_length` is set so the thumb has the correct proportional size. - `doc_viewer` measures line width with `UnicodeWidthStr::width` to estimate wrapped row count (previously summed `.len()` in bytes). - `nav_tree` compact-date extraction is now char-safe (no byte slicing on the `created` field), and `title_budget` is computed in visual columns so CJK titles truncate correctly. - `metadata_panel` uses a shared `truncate_visual` for related links. - `status_bar` right-aligned padding uses visual width, so projects in directories with non-ASCII names stay aligned. - `markdown.rs` code blocks pad by visual columns; fixed alignment when a block contains CJK / emoji / accented characters. Commands: - `validate` filename-date parsing (`NAMING-001`, `META-004`, auto-fix path) no longer slices by bytes; non-ASCII in the date component fails cleanly with a validation error instead of risking a panic. - `analyze` path/function truncation uses visual width with a leading ellipsis; padding in the report table is correct under any input. - `status` project, structure, and documentation tables all compute column widths and padding in visual columns. - `new` slug truncation and sequence-number scan switched from byte slices to `chars().take(N)`. Shared helpers in `utils.rs`: - `visual_width(&str) -> usize` - `truncate_visual(&str, max_cols) -> String` - `pad_right_visual(&str, cols) -> String` - 12 unit tests covering ASCII, accents, CJK, em-dash, emoji, and zero-width edge cases. Dependency change: `unicode-width` is now a direct always-compiled dep (previously optional under feature `tui`). It was already transitive via `ratatui`; promoting it lets non-TUI commands measure visually. Bump CLI to 3.2.4. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6 tasks
montfort
added a commit
that referenced
this pull request
May 7, 2026
…#112) Documents the follow-ups backlog convention contributed by the Sentinel adopter via issue #111. Empirically validated in StrangeDaysTech/sentinel CHARTER-12 (47 AILOGs across CHARTER-08 → CHARTER-11). Adopters reaching ~20+ AILOGs benefit from a central registry + per-AILOG drift detection script + agent integration block. This release is docs only — no CLI changes, no schema changes, no audit flow changes. Cristalization as a `devtrail followups` subcommand is deferred until a second adopter validates the pattern. Adds: - dist/.devtrail/00-governance/FOLLOW-UPS-BACKLOG-PATTERN.md (EN, ES, zh-CN) documenting the registry shape, 5 buckets, per-entry schema, drift detection (3 modes), agent integration, adoption walkthrough, reference implementation (Sentinel CHARTER-12 PRs #53/#54), and v0 open questions. - "Patterns" sections in AGENT-RULES.md and QUICK-REFERENCE.md (3 langs) pointing to the new document. Bumps: - dist/dist-manifest.yml to 4.10.0. - Footer versions and adopter doc references from v4.9.0 to v4.10.0 (skill version markers preserved as historical "since" annotations). Closes the upstream side of issue #111 (option A: docs-only adoption). Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #52. That PR fixed a UTF-8 panic in
wrap_cell_text(); this one removes the byte-vs-visual-column confusion that was scattered across the rest of the CLI — the same anti-pattern that caused the original crash.All layout sites now route through three new helpers in
utils.rs:visual_width(&str) -> usizetruncate_visual(&str, max_cols) -> Stringpad_right_visual(&str, cols) -> StringTUI fixes
explore's scrollbar no longer shows the document text through its track. The paragraph renders in a reserved body column and the scrollbar owns the rightmost column.ScrollbarState::viewport_content_lengthis now set, so the thumb has the correct proportional size.doc_viewermeasures line width withUnicodeWidthStr::width, not bytes — scroll position is accurate for CJK/emoji content.2026-04-12→04-12) is char-safe (no byte slicing on arbitrarycreatedstrings); title budget computed in visual columns.truncate_visual.Command fixes
validate:NAMING-001,META-004, and the auto-fix path no longer byte-slice the filename date. Non-ASCII where ASCII was expected produces a clean validation error instead of risking a panic.analyze: path/function truncation uses visual width with a leading ellipsis; padding is correct under any input.status: the Project, Structure, and Documentation tables compute column widths and padding in visual columns.new: slug truncation and sequence-number scan usechars().take(N)instead of byte slices.Dependency change
unicode-widthmoved from optional (featuretui) to a direct always-compiled dep. It was already transitive viaratatui, so no new compile cost; promoting it lets non-TUI commands measure visually too.Test plan
cargo test— 76 library tests passing (48 pre-existing + 16 markdown regression + 12 newutils::tests::*).cargo build --no-default-features— compiles cleanly.cargo build --all-features— compiles cleanly.cargo build --release— compiles cleanly;devtrail aboutreportscli-3.2.4.cargo clippy --all-features— no new warnings (the 4 remaining are pre-existing inaudit_engine.rs,app.rs,index.rs,markdown.rs:flush_spans)../target/release/devtrail statustable borders align correctly.exploreand check nav tree / metadata / code block alignment.🤖 Generated with Claude Code