ultraworkers / ultraworkers/claw-code
Fix markdown formatting issues in TUI streaming: block-level element newline omission and consecutive empty line accumulation
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 195k
- Forks
- 108k
- PR merge metrics
- No merged PRs in 30d
Description
Describe the bug
When rendering Markdown text in TUI streaming mode (specifically in non-compact mode):
- Newline omission / output stickiness: When a text description is immediately followed by a block-level element (e.g., a fenced code block),
pulldown-cmarkdoes not emit any line-break or soft-break events between them. This results in the code block top border rendering immediately after the text (e.g.,2. Enter directory:╭─ code), causing layout stickiness. - Consecutive empty line accumulation: Multiple block closing events (such as code block end + list item end + list end) consecutively append newlines unconditionally. This leads to redundant empty lines stacking up in the terminal (e.g., 3-4 consecutive empty lines), which wastes screen space.
Solution / Implementation
We solved this by introducing an idempotent, smart newline-ensuring helper:
fn ensure_newlines(output: &mut String, count: usize) {
if output.is_empty() {
return;
}
let current = output.chars().rev().take_while(|&c| c == '\n').count();
if current < count {
output.push_str(&"\n".repeat(count - current));
}
}
And applied it defensively to block-level start/end event handlers in render.rs:
- Code Block Start / Item Start / Blockquote Start: Call
ensure_newlines(output, 1)to prevent inline stickiness. - Heading Start: Call
ensure_newlines(output, 2)to ensure space before headers. - Block End Events: Replace unconditional newline pushing with
ensure_newlines(output, 2)(for paragraphs, headings, lists, table closings) orensure_newlines(output, 1)(for items, blockquotes), which prevents consecutive newlines from accumulating beyond 1 empty line.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in render.rs, focusing on the Markdown event handlers used by TUI streaming in non-compact mode and the block-level start and end events described in the issue. Verify the result with descriptions followed by fenced code blocks and nested list content: borders should not stick to preceding text, and block endings should leave no more than one empty line.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100