Skip to content

refactor(render): colors in colors.rs, escape codes and sanitize in printer.rs - #1889

Merged
o2sh merged 9 commits into
mainfrom
refactor/render-layers
Oct 16, 2026
Merged

o2sh merged 9 commits into
mainfrom
refactor/render-layers

Conversation

@o2sh

@o2sh o2sh commented Oct 14, 2026 •

Copy link
Copy Markdown
Owner

Follow-up to #1888. On main, color and escape-code logic was spread across render:

  • Two places wrote colored text: style::render for the info lines, and logo.rs, which wrote its own escape codes and skipped sanitize.
  • printer.rs combined get_ascii_colors and TextColors by hand, with no_bold passed alongside.
  • The language chips picked their own colors in fields/languages.rs.

Design

render/
  printer.rs   picks the output, puts the ascii art or image beside the info, writes it
  info.rs      the info: title, "Key: value" lines, palette row      (was lines.rs)
  fields/      the value lines of each field
  format.rs    numbers and dates
  ascii.rs     ascii art template -> lines                           (was logo.rs)
  image/       sixel, kitty, iterm
  style.rs     Line, Segment, Style
  colors.rs    Colors: what each Style looks like (color and bold)

Style names everything that can be colored, as the command line names it: the six parts of --text-colors (Title, Tilde, Underline, Key, Separator, Value), the {n} parts of the ascii art (AsciiArt(n), for --ascii-colors), the language chips and the languages bar (LanguageChip, LanguageBar), and the palette row (Palette(n)). It holds no colors.

  • Only colors.rs decides how each Style looks: its color, from the language, --ascii-language, --ascii-colors, --text-colors and --true-color, and whether it is bold (--no-bold). The rest of render only says which Style a piece of text has.
  • Only printer.rs writes escape codes (apart from the image protocols), so it sanitizes everything it prints, the ascii art included.
  • ARCHITECTURE.md describes this layout and the two rules.

Options

InfoOptions and RenderOptions stay where they are on main, in data/mod.rs and render/mod.rs. This branch briefly moved them into options.rs (802fda3), but that made a loop: data and render imported options, which imports cli, which imports data and render types. da7dfc8 reverts it.

Behavior

The visible output is the same as main. Two differences in the bytes written:

  • The ascii art no longer writes an empty escape pair (\e[…m\e[0m) before each {n} token.
  • --ascii-input now goes through sanitize like all other text, so control characters in it (tabs, escape codes) show as �. None of the built-in ascii art contains control characters.

Testing

  • cargo fmt, cargo clippy --all-targets: clean.
  • cargo test: 155 unit tests, 12 integration tests and the doc test pass. New tests cover Colors::style (including the chip and palette styles), the chip colors, paint, sanitize and ascii_beside_info. The ascii tests now check Lines.
  • Compared main and this branch on two repos (onefetch, and a repo whose manifest description contains an OSC escape sequence). I used 18 flag sets: default, --no-bold, -c, -t (full and partial), --true-color always/never, --ascii-language (alone and with --no-bold -c), --ascii-input (with and without {n} tokens), --no-art, --nerd-fonts, --no-color-palette, --no-title, --number-of-languages, -o json and -o yaml.
    • With escape codes stripped, the output is identical in all 36 runs.
    • The raw bytes are identical once main's empty escape pairs are removed (checked on 16 of the runs).
    • The escape sequence in the manifest description prints as �.
    • Churn and last change were disabled for the comparison, because they vary between two runs of the same binary.

🤖 Generated with Claude Code

…writing in printer.rs

`Style` names everything that can be colored, as the command line names it:
the six parts of --text-colors, the `{n}` parts of the ascii art
(`Ascii(n)`, for --ascii-colors), and the fixed colors of the language chips
and the palette row.

- colors.rs: `Colors` says what each `Style` looks like (language,
  --ascii-language, --ascii-colors, --text-colors, --true-color, --no-bold),
  and `chip_color` picks the language chips' colors. It is the only file
  that picks colors.
- printer.rs: the only place that writes escape codes, so it sanitizes
  everything it prints, the ascii art included.
- ascii.rs (was logo.rs): returns lines styled `Ascii(n)` instead of writing
  its own escape codes.
- info.rs (was lines.rs): the info lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@o2sh
o2sh force-pushed the refactor/render-layers branch from f94fb18 to 4ae0c19 Compare October 15, 2026 21:46
@o2sh o2sh changed the title refactor(render): styled text, theme and terminal layers refactor(render): colors in colors.rs, escape codes and sanitize in printer.rs Oct 15, 2026
`data` and `render` read their options whichever file defines them, so
defining `InfoOptions` in data/mod.rs and `RenderOptions` in render/mod.rs
kept no dependency out. options.rs now holds both structs, the defaults the
command line uses, and how `Cli` fills them in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
o2sh and others added 3 commits October 16, 2026 01:03
This reverts commit 802fda3. With the structs in options.rs, `data` and
`render` imported `options`, which imports `cli`, which imports `data` and
`render` types: a loop. Defining each stage's options in the stage keeps
the dependencies one way: cli -> options -> {data, render}.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s every color

`Style::Color` and `Style::Background` carried finished colors, so the
languages field picked chip colors itself (reading `true_color`) and
info.rs looped over the palette. `Style::Chip`, `Style::ChipBar` and
`Style::Palette` say which language or palette entry a segment is, and
`Colors` resolves them. `Style` holds no colors anymore.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The image path pads the info with the same `center_pad()` segment as the
  ascii path, before painting.
- printer.rs module doc: "ascii art or image", not "logo".
- `Style::Ascii`: documents the fallback to the default color.
- colors.rs decides bold as well as color; the docs say so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…geBar

- `Style::Ascii` -> `Style::AsciiLogo`
- `Style::Chip` -> `Style::LanguageChip`
- `Style::ChipBar` -> `Style::LanguageBar`
- the struct both language styles carry, `Chip` -> `LanguageColor`

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…uageEntry

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…color

The color of a `LanguageEntry` is used for the languages bar as well as the
chip, so `Colors::chip_color` is now `language_color`, and the field, test
helpers and bindings holding a `LanguageEntry` are named `entry`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@o2sh
o2sh merged commit 263dd10 into main Oct 16, 2026
4 checks passed

This branch was successfully deployed

1 active deployment
Preview — 6b8c9628 Deployed Oct 15, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant