swatch 🎨
A CSS syntax highlighter for Gleam. Renders directly to HTML or ANSI-colored terminal output, or hands back a classified token stream for custom rendering.
Install
gleam add swatch@1
Quick start
import gleam/io
import swatch
pub fn main() {
let source =
"@media (min-width: 600px) {
.btn {
--brand: #f00;
color: var(--brand);
padding: 8px 12px;
}
.btn:hover {
color: rgb(255 0 0 / 0.8) !important;
}
}"
// ANSI colors for the terminal
swatch.to_ansi(source) |> io.println
// HTML with `<span>` wrappers per token kind
let html = swatch.to_html(source)
io.println("<pre><code>" <> html <> "</code></pre>")
// Raw tokens for custom rendering or analysis
let _tokens = swatch.to_tokens(source)
}
Further documentation can be found at https://hexdocs.pm/swatch.
HTML output
swatch.to_html wraps each token in a <span class="hl-…"> describing its
kind. Whitespace passes through unwrapped. Content is HTML-escaped.
| Token | Class | Token | Class |
|---|---|---|---|
Comment | hl-comment | String | hl-string |
Selector | hl-selector | Number | hl-number |
ClassSelector | hl-class | Unit | hl-unit |
IdSelector | hl-id | HexColor | hl-hex |
PseudoSelector | hl-pseudo | Function | hl-function |
AttributeName | hl-attribute | Keyword | hl-keyword |
AttributeValue | hl-attribute-value | Important | hl-important |
AttributeFlag | hl-attribute-flag | Operator | hl-operator |
AtRule | hl-at-rule | Punctuation | hl-punctuation |
Property | hl-property | Other | hl-other |
Variable | hl-variable |
A starter stylesheet:
pre code .hl-comment { color: #6a737d; font-style: italic }
pre code .hl-selector,
pre code .hl-at-rule,
pre code .hl-operator,
pre code .hl-important { color: #d73a49 }
pre code .hl-important { font-weight: bold }
pre code .hl-class,
pre code .hl-id,
pre code .hl-pseudo,
pre code .hl-attribute,
pre code .hl-attribute-flag,
pre code .hl-function { color: #6f42c1 }
pre code .hl-string,
pre code .hl-attribute-value { color: #032f62 }
pre code .hl-property,
pre code .hl-number,
pre code .hl-unit,
pre code .hl-hex { color: #005cc5 }
pre code .hl-variable { color: #e36209 }
pre code .hl-keyword { color: #22863a }
If you already have a token list, swatch.tokens_to_html renders it without re-tokenizing.
ANSI output
swatch.to_ansi renders for the terminal using
gleam_community_ansi.
| Color | Tokens |
|---|---|
| yellow | selectors (element, class, id, pseudo, attribute, flag), keywords |
| cyan | properties, custom properties |
| green | strings, numbers, units, hex colors, unquoted attribute values |
| blue | function names |
| magenta | at-rules, operators |
| bold red | !important |
| italic gray | comments |
| reset | whitespace, punctuation, fallback |
Structural tokens use ansi.reset so an unclosed attribute from upstream text can't bleed into characters like { and }.
If you already have a token list, swatch.tokens_to_ansi renders it without re-tokenizing.
Tokens
swatch.to_tokens returns a list of swatch.Token. Every variant carries a
single String, so concatenation
reproduces the input.
The full list: Whitespace, Comment, Selector, ClassSelector,
IdSelector, PseudoSelector, AttributeName, AttributeValue,
AttributeFlag, AtRule, Property, Variable, String, Number,
Unit, HexColor, Function, Keyword, Important, Operator,
Punctuation, Other.
Tokens are round-trip safe; concatenating each token's string payload reproduces the original source byte-for-byte, including whitespace, comments, escapes, and formatting.
Malformed input (unmatched brackets, invalid escapes, trailing identifiers
past the attribute-flag slot) surfaces as Other rather than being dropped,
so round-trip holds even on broken CSS.
CSS coverage
- CSS Syntax Level 3 — escapes, hex escapes with trailing
whitespace,
<urange>,<url-token>,<bad-string-token>recovery, CDO/CDC. - Selectors Level 4 — pseudo-elements (
::), all attribute matchers, case-sensitivity flags, namespace separator (ns|attr,*|attr), and the||column combinator. - CSS Nesting — bounded lookahead promotes property-position runs to selectors when they begin a nested rule.
- Media Queries Level 4 range comparisons (
<,<=,>=). @supports selector(…),@container style(…)/scroll-state(…), and@scope— all switch their argument into the right context.
Development
gleam build # Compile the project
gleam test # Run the tests
See CONTRIBUTING.md for the full workflow.