Treat \r as logical-line boundary and swallow stray padding spaces#36
Conversation
|
Updated based on review: The user-visible diff narrows to one row in this render, but it's the one Melissa originally hit:
So in a real terminal session the visible diff is just the dropped padding-space. The Raw before/after PNGs live on a separate host-only branch |
2dccf8c to
846de16
Compare
Follow-up to adafruit#32. While that fix preserved \r-based progress updates end-to-end, two cosmetic glitches remained when running real apt / pip installs through run_command: 1. apt's progress UI sometimes emits a stray padding space after a \n, e.g. 'Fetched 52.4 MB in 30s (1,729 kB/s)\n Selecting...'. The previous logic treated the trailing space as the start of a fresh logical line, wrote the group prefix, then the space, then the real content -- producing output like: PITFT Fetched 52.4 MB in 30s (1,729 kB/s) PITFT Selecting previously unselected package ... ^ stray space, prefix pushed one column right 2. A bare \r-only line (e.g. apt's 'erase-progress-line' sequence) was being treated as 'still on the same logical line', so the next chunk's content would be concatenated onto the previous line's tail in pipe/log capture, and the prefix bookkeeping for the *next* \n boundary could drift. This change: * Splits chunks on either \n or runs of \r (\r+), so cursor-at-col-0 is the actual boundary, not just newline. * Treats only \n as a *prefix-re-emission* boundary. Bare \r is cursor-return: subsequent redraw frames are written without the prefix, which is how pip/apt progress UIs are designed to animate on a real terminal (each redraw overwrites the previous frame, including the prefix, so the terminal naturally shows the latest frame with no stale prefix dangling at column 0). * Strips leading horizontal whitespace (spaces and tabs) immediately after a \n boundary, so padding from the source process doesn't push the prefix right. * Suppresses the prefix entirely when a logical line is pure padding, but keeps the terminator (\r or \n) so the terminal still sees the cursor motion. Verified end-to-end via a deterministic harness that simulates terminal CR/LF cursor semantics against captured output, including the exact apt+pip patterns Melissa saw during the PiTFT install. ruff check + ruff format clean.
846de16 to
3517fcb
Compare
|
Refreshed screenshot after the Option E redesign (commit 3517fcb): What changed in this redesign:
Reading the comparison: The only visible textual change between panels is row 3 — Rows 0 ( |

Follow-up to #32. That PR preserved
\r-based progress updates end-to-end (no more piles of staleDownloading 12%lines scrolling past), but two cosmetic glitches remained, both surfaced during real-worldapt+pipruns viaadafruit-pitft.py.Symptoms Melissa hit during a fresh PiTFT install
and, separately, lines like:
Root causes
Both reduce to the same modeling mistake:
_emit_stream_chunktreated only\nas a logical-line boundary. On a real terminal "logical line start" means "cursor at column 0", which is true after either\nor\r. And once the splitter was wrong, two failure modes followed:aptemits a stray padding space after\n(its progress UI flushes a\r…clear sequence and sometimes leaves a single space dangling on the next line). The old code:\n→ flipat_line_start=True→ next segment starts with" "+ real content → writePITFT␣+␣Selecting…. Result: visible double-space pushing the prefix off-column.aptalso emits bare\r-only "erase progress line" sequences. The old code didn't recognize\ras a boundary, so the next chunk inheritedat_line_start=Falsefrom the prior write — the prefix on the next real line got dropped entirely.A third bug fell out of the same model: pip-style
\r-only progress bars (10%\r25%\r50%\r100%\nDone) only showed the group prefix on the first frame, because subsequent frames weren't recognized as new logical lines.What this changes
\nor runs of\r(\r+), so the splitter matches real terminal semantics, not just newline semantics.\ror\n) so the terminal still sees cursor motion.Popenconfig and the rest of the streaming machinery from #32 are unchanged.Verification
Deterministic harness that simulates terminal CR/LF cursor semantics against captured output. Six scenarios, all pass:
PITFT line one/PITFT line two/PITFT line three✅\r-progressPITFT Downloading 100%/PITFT Done✅PITFT first half second half✅PITFT Fetched 52.4 MB …/PITFT Selecting previously unselected …✅\r-pad-\rthen new linePITFT Selecting previously unselected …✅\r-only progressPITFT 100%/PITFT Done✅Plus the no-group raw-passthrough regression still passes (
plain one/plain two, no prefix bytes injected).ruff checkandruff formatclean. Tested end-to-end on a Pi Zero W with the realadafruit-pitft.py --display=st7789v_bonnet_240x240install where the original artifact was first observed.cc @makermelissa — this is the cosmetic follow-up we discussed while testing #341 / adafruit/Raspberry-Pi-Installer-Scripts#379.