Repository navigation
fix(tui): keep the indent of a paragraph nested in a list - #7146
Merged
Merged
Conversation
A paragraph indented under a list item, such as a bullet's second paragraph or the note after a numbered step's code block, rendered flush left: the word wrapper drops spaces at the start of a row. The item then looks finished and the paragraph reads as top-level text. The parser now carries whether a list is open: a list item opens it, blank lines, code and indented paragraphs keep it open, and anything else closes it. A paragraph keeps its indent only while a list is open, so indented rows of command notes such as /status and /cost render as before. The decision is made at parse time because streaming renders the text between code blocks separately, so a look-back in the renderer would not match the final render. The kept indent is drawn on every row, capped at half the width like a list item's. As with list items, the first row copies with its indent and wrapped rows strip it. Signed-off-by: Lstarsky0 <59827030+Lstarsky0@users.noreply.github.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Hmbown
approved these changes
Oct 30, 2026
Hmbown
left a comment
Collaborator
There was a problem hiding this comment.
thank you!! this is great
1 of 3 tasks
Hmbown
pushed a commit
that referenced
this pull request
Oct 31, 2026
fix(tui): render ~~~ fences as code blocks Conflict with #7146 resolved in the ParseState doc comment only: the carry is now `open_fence`, `code_language`, `code_block_id`, `in_list`. All code hunks merged cleanly.
Hmbown
pushed a commit
that referenced
this pull request
Oct 31, 2026
…urfaces Changelog lines for #7147, #7146, #7156, #7157, #7158, #7152 and #7150, and credit for the contributors across CHANGELOG `### Contributors`, docs/CONTRIBUTORS.md and UNRELEASED_CONTRIBUTORS (adds @luochen211, whose #7150 and #7149 landed). #7149 is a dead-code chore and has no changelog line. Verified: `python3 scripts/check-contributor-credit.py` reports every contributor in the window credited on all three surfaces; `scripts/preflight.sh --check` passes; `sh scripts/sync-changelog.sh` regenerated crates/tui/CHANGELOG.md. Co-Authored-By: Claude Sonnet 5.5 <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.
What and why
A paragraph indented under a list item renders flush left: the word wrapper drops spaces at the start of a row, so the indent never reaches the screen. Models write these often, as a bullet's second paragraph or a note after a numbered step's code block. At 60 columns, before:
The code under step 1 keeps its indent but the note after it doesn't, so step 1 looks finished and the note reads as top-level text. After:
The parser now carries whether a list is open, next to its code-fence state: a list item opens it, blank lines, code and indented paragraphs keep it open, and anything else closes it. While a list is open, a paragraph keeps its leading spaces, and
render_paragraph_taggedwraps the text in the remaining width and draws the indent on every row, capped at half the width like a list item's indent (#7030); links shift with it. The decision is made when the line is parsed rather than in the renderer, because streaming renders the text between code blocks separately and a look-back there would not match the final render. Copy follows list items: the first row copies with its indent, as written, and wrapped rows strip it.Command notes go through the same renderer, and some have indented rows that aren't under a list item, such as
/status's key/value rows and part of/cost. Those render as before: I ran/status,/cost,/context,/hooks,/mcp,/skills,/tools,/memory,/doctor,/version,/usage,/agents,/workspace,/permissions,/sandbox,/todo,/goal,/diff,/statsand/profilein one session on both builds, and the screens match once the session id is masked. A first version that kept every indent did shift/statusand/cost, which is why the decision follows the list.Issue
No-Issue: a paragraph indented under a list item renders flush left; I searched and found no issue for it
How I tested it
mainat 588426d in a pseudo-terminal at 60 columns with an empty HOME and a local mock OpenAI-compatible server replying with the steps and bullets above; the rows above come from those runs.1. Installfollowed by an indented paragraph, and- itemfollowed by an indented line, at 24 columns and callsselection_to_text, this change copies both as written ("1. Install\n\n alpha beta … kappa");maincopies them without the indent ("1. Install\n\nalpha beta … kappa").cargo nextest run -p codewhale-tui -p codewhale-tui-kit --lib: 13880 of 13886 passed, with the 427 tests whose names matchmarkdown,paragraph,selectionortranscriptamong them. The 6 failures (status_public_output_and_read_only_state_match_baseline,golden_turn_events_match,model_visible_prefix_bytes_match_goldens,interrupted_session_deletion_keeps_recovery_incomplete_and_can_finish,worker_compacts_past_its_context_window_and_keeps_working,reasoning_effort_uses_one_strict_alias_table_and_legacy_fallback) also fail onmainat 588426d without this change.cargo fmt --all -- --check,cargo clippy -p codewhale-tui -p codewhale-tui-kitwith CI's flags (also on 1.99),cargo check -p codewhale-tui -p codewhale-tui-kit --all-targetsandcargo +1.89.0 check -p codewhale-tui -p codewhale-tui-kit: clean.Checklist
maincargo fmt --allpasses, and tests cover new or changed behavior —cargo fmtpasses; no new test, per AGENTS.md, so the runs above stand in for onedocs/features.toml(cargo test -p codewhale-tui --test feature_registrychecks it) — n/a