Repository navigation
feat: terminal sanitizing, wrapping and diff painting - #12
Merged
Merged
Conversation
What swctl still did by hand, generalized: - term.Sanitize and SanitizeLines make untrusted text, such as CI job logs or mail, safe to write to a terminal: colours and a safe set of SGR attributes stay, every other escape sequence and control character goes (no clipboard writes, disguised links or title changes), tabs expand to tab stops, and a carriage return keeps what a terminal would show. - term.Wrap word-wraps to a width with a hanging indent, ignoring the width of escape sequences. - EscapeLen counts ESC ( B (tput sgr0) and ESC X strings whole and never splits a UTF-8 character after a lone ESC, so StripANSI, VisibleWidth and Truncate no longer leave stray bytes. - theme: Added, Removed, DiffHeader and DiffHunk roles, Theme.For, DiffScanner, which reads a unified diff the way patch does, and PaintDiff / PaintDiffLine. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Sanitize expanded tabs counting cells per rune, so a joined emoji such as a ZWJ sequence counted four cells instead of the two a terminal draws, and the tab stop came out short. The column is now measured with VisibleWidth. - Wrap treated an escape sequence standing alone, such as a trailing reset, as a word whose preceding spaces could break the line, leaving the reset on a line of its own. It now stays on the line it follows, and its spaces go before the next visible word. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…apes in Wrap - Sanitize and SanitizeLines split into lines before reading escape sequences, so an OSC, DCS, SOS, PM or APC string containing a newline left the rest of its payload behind as text. Escape strings are now dropped from the whole text first, to their terminator or the end. - Every tab measured the line so far again, which made a long line of tabs quadratic. The column is now kept as the tabs go, still counting grapheme clusters. - A style sequence opening a line took the first word's place in Wrap, so the line could break before any visible word. Co-Authored-By: Claude Opus 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.
The terminal code swctl still did by hand, generalized.
term
Sanitize(s)/SanitizeLines(s): make untrusted text (CI job logs, mail, server-provided strings) safe to write to a terminal. Colours (16, 256, 24-bit) and safe SGR attributes stay; every other escape sequence (OSC 52 clipboard writes, OSC 8 links, title changes, cursor movement) and every C0/C1 control character except newline goes; tabs expand to 8-column tab stops; on each line only the text after the last carriage return stays, as a terminal shows it; invalid UTF-8 becomes U+FFFD.SanitizeLinesmakes every line stand alone (colours carried over, reset at the end). Fuzzed.Wrap(s, width, indent): word wrap at spaces with a hanging indent; escape sequences have no width.EscapeLenfix (alsoStripANSI,VisibleWidth,Truncate,live):ESC ( B(whattput sgr0emits) is one sequence,ESC Xstrings are recognised, and a lone ESC no longer swallows half a UTF-8 character.theme
Added,Removed,DiffHeader,DiffHunk(Default: 114, 203, bold, 117 — Success and Error's tones, laid out like git).Theme.For(w): the theme wherewtakes colour,Plainotherwise.DiffScanner+DiffKind: reads a unified diff the waypatchdoes (hunk line counts decide whether--- xis a removed line or a file header).Theme.PaintDiff(text)/PaintDiffLine(kind, line).Compatibility
No API removed or changed.
Themehas four more fields (an unkeyedTheme{…}literal would no longer compile; none exist in our repos).EscapeLenresults change only for the sequences it mis-measured.swctl, atoss-cli and mittwald-outlook-bridge build and pass their tests against this branch.
🤖 Generated with Claude Code