"
labels: ["bug"]
body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the bug you encountered.
options:
- label: I have searched the existing issues
required: true
- type: textarea
attributes:
label: Describe the bug
description: |
A clear and concise description of what the bug is. Screenshots are often helpful here.
Do *NOT* just paste a link to other issues on GitHub.
validations:
required: true
- type: textarea
attributes:
label: To Reproduce
description: |
1. Reproduce your issue in the [Chroma Playground](https://swapoff.org/chroma/playground/), then click the _copy_ icon to copy a shareable link for your issue. Consider using `[markdown links](URL)` to minimise the visual noise of the links.
2. Provide input text and a command-line invocation of `chroma` that reproduces your problem. eg. For Hugo this might be something like `chroma -s monokailight --html --html-lines --html-lines-table --html-inline-styles `
Do *NOT* provide configuration for another tool (eg. Hugo, Gitea). My time is limited and if you want me to fix your issue, help me help you.
validations:
required: true
chroma-2.23.1/.github/ISSUE_TEMPLATE/feature_request.yaml 0000664 0000000 0000000 00000001701 15134556571 0022675 0 ustar 00root root 0000000 0000000 name: Feature request
description: Suggest an idea for this project
title: ""
labels: ["feature request"]
body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the feature you're requesting.
options:
- label: I have searched the existing issues
required: true
- type: textarea
attributes:
label: What problem does this feature solve?
description: |
Please check the Chroma [README](https://github.com/alecthomas/chroma) and command-line tool to ensure this isn't an already solved problem.
validations:
required: true
- type: textarea
attributes:
label: What feature do you propose?
description: |
The feature should describe a change to Chroma's code, not lexers.
For lexers, fill out the "Lexer request" form.
validations:
required: true
chroma-2.23.1/.github/ISSUE_TEMPLATE/lexer_request.yaml 0000664 0000000 0000000 00000002146 15134556571 0022365 0 ustar 00root root 0000000 0000000 name: Lexer request
description: Suggest the addition of a lexer
title: ""
labels: ["help wanted", "lexer missing"]
body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the lexer you're requesting.
options:
- label: I have searched the existing issues
required: true
- type: textarea
attributes:
label: What is the missing lexer?
description: |
Please note that lexers are contributed by the community. Your best option is to contribute this yourself.
Lexers are defined in XML (see the [existing lexers](https://github.com/alecthomas/chroma/tree/master/lexers/embedded) for examples).
You can test your lexer with the Chroma command-line, `chroma --lexer=my-lexer.xml example-file.lang`
validations:
required: true
- type: textarea
attributes:
label: Links to existing syntax definitions
description: |
Provide links to existing syntax definitions in Textmate, etc.
validations:
required: true
chroma-2.23.1/.github/workflows/ 0000775 0000000 0000000 00000000000 15134556571 0016461 5 ustar 00root root 0000000 0000000 chroma-2.23.1/.github/workflows/ci.yml 0000664 0000000 0000000 00000001076 15134556571 0017603 0 ustar 00root root 0000000 0000000 on:
push:
branches:
- master
pull_request:
name: CI
jobs:
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1
- run: go test ./...
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1
- run: golangci-lint run
chroma-2.23.1/.github/workflows/release.yml 0000664 0000000 0000000 00000000564 15134556571 0020631 0 ustar 00root root 0000000 0000000 name: Release
on:
push:
tags:
- 'v*'
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
with:
fetch-depth: 0
- run: ./bin/hermit env --raw >> $GITHUB_ENV
- run: goreleaser release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
chroma-2.23.1/.gitignore 0000664 0000000 0000000 00000000646 15134556571 0015062 0 ustar 00root root 0000000 0000000 # Binaries for programs and plugins
.git
.idea
.vscode
.hermit
*.exe
*.dll
*.so
*.dylib
/cmd/chroma/chroma
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/
_models/
_examples/
*.min.*
build/
cmd/chromad/static/chroma.wasm
cmd/chromad/static/wasm_exec.js
chroma-2.23.1/.golangci.yml 0000664 0000000 0000000 00000003747 15134556571 0015463 0 ustar 00root root 0000000 0000000 run:
tests: true
output:
print-issued-lines: false
linters:
enable-all: true
disable:
- lll
- gocyclo
- dupl
- gochecknoglobals
- funlen
- godox
- wsl
- gocognit
- nolintlint
- testpackage
- godot
- nestif
- paralleltest
- nlreturn
- cyclop
- gci
- gofumpt
- errorlint
- exhaustive
- wrapcheck
- stylecheck
- thelper
- nonamedreturns
- revive
- dupword
- exhaustruct
- varnamelen
- forcetypeassert
- ireturn
- maintidx
- govet
- testableexamples
- musttag
- depguard
- goconst
- perfsprint
- mnd
- predeclared
- recvcheck
- tenv
- err113
linters-settings:
gocyclo:
min-complexity: 10
dupl:
threshold: 100
goconst:
min-len: 8
min-occurrences: 3
forbidigo:
#forbid:
# - (Must)?NewLexer$
exclude_godoc_examples: false
issues:
exclude-dirs:
- _examples
max-per-linter: 0
max-same: 0
exclude-use-default: false
exclude:
# Captured by errcheck.
- '^(G104|G204):'
# Very commonly not checked.
- 'Error return value of .(.*\.Help|.*\.MarkFlagRequired|(os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv). is not checked'
- 'exported method (.*\.MarshalJSON|.*\.UnmarshalJSON|.*\.EntityURN|.*\.GoString|.*\.Pos) should have comment or be unexported'
- 'composite literal uses unkeyed fields'
- 'declaration of "err" shadows declaration'
- 'should not use dot imports'
- 'Potential file inclusion via variable'
- 'should have comment or be unexported'
- 'comment on exported var .* should be of the form'
- 'at least one file in a package should have a package comment'
- 'string literal contains the Unicode'
- 'methods on the same type should have the same receiver name'
- '_TokenType_name should be _TokenTypeName'
- '`_TokenType_map` should be `_TokenTypeMap`'
- 'rewrite if-else to switch statement'
chroma-2.23.1/.goreleaser.yml 0000664 0000000 0000000 00000001342 15134556571 0016015 0 ustar 00root root 0000000 0000000 project_name: chroma
release:
github:
owner: alecthomas
name: chroma
brews:
- install: bin.install "chroma"
env:
- CGO_ENABLED=0
builds:
- goos:
- linux
- darwin
- windows
goarch:
- arm64
- amd64
- "386"
goarm:
- "6"
dir: ./cmd/chroma
main: .
ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
binary: chroma
archives:
- format: tar.gz
name_template: "{{ .Binary }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
files:
- COPYING
- README*
snapshot:
name_template: SNAPSHOT-{{ .Commit }}
checksum:
name_template: "{{ .ProjectName }}-{{ .Version }}-checksums.txt"
chroma-2.23.1/AGENTS.md 0000664 0000000 0000000 00000001542 15134556571 0014371 0 ustar 00root root 0000000 0000000 Chroma is a syntax highlighting library, tool and web playground for Go. It is based on Pygments and includes importers for it, so most of the same concepts from Pygments apply to Chroma.
This project is written in Go, uses Hermit to manage tooling, and Just for helper commands. Helper scripts are in ./scripts.
Language definitions are XML files defined in ./lexers/embedded/*.xml.
Styles/themes are defined in ./styles/*.xml.
The CLI can be run with `chroma`.
The web playground can be run with `chromad --csrf-key=moo`. It blocks, so should generally be run in the background. It also does not hot reload, so has to be manually restarted. The playground has two modes - for local development it uses the server itself to render, while for production running `just chromad` will compile ./cmd/libchromawasm into a WASM module that is bundled into `chromad`.
chroma-2.23.1/Bitfile 0000664 0000000 0000000 00000001262 15134556571 0014366 0 ustar 00root root 0000000 0000000 VERSION = %(git describe --tags --dirty --always)%
export CGOENABLED = 0
tokentype_enumer.go: types.go
build: go generate
# Regenerate the list of lexers in the README
README.md: lexers/*.go lexers/*/*.xml table.py
build: ./table.py
-clean
implicit %{1}%{2}.min.%{3}: **/*.{css,js}
build: esbuild --bundle %{IN} --minify --outfile=%{OUT}
implicit build/%{1}: cmd/*
cd cmd/%{1}
inputs: cmd/%{1}/**/* **/*.go
build: go build -ldflags="-X 'main.version=%{VERSION}'" -o ../../build/%{1} .
#upload: chromad
# build:
# scp chromad root@swapoff.org:
# ssh root@swapoff.org 'install -m755 ./chromad /srv/http/swapoff.org/bin && service chromad restart'
# touch upload
chroma-2.23.1/COPYING 0000664 0000000 0000000 00000002037 15134556571 0014121 0 ustar 00root root 0000000 0000000 Copyright (C) 2017 Alec Thomas
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
chroma-2.23.1/Dockerfile 0000664 0000000 0000000 00000002746 15134556571 0015067 0 ustar 00root root 0000000 0000000 # Multi-stage Dockerfile for chromad Go application using Hermit-managed tools
# Build stage
FROM ubuntu:24.04 AS builder
# Install system dependencies
RUN apt-get update && apt-get install -y \
curl \
git \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Set working directory
WORKDIR /app
# Copy the entire project (including bin directory with Hermit tools)
COPY . .
# Make Hermit tools executable and add to PATH
ENV PATH="/app/bin:${PATH}"
# Set Go environment variables for static compilation
ENV CGO_ENABLED=0
ENV GOOS=linux
ENV GOARCH=amd64
# Build the application using just
RUN just chromad
# Runtime stage
FROM alpine:3.23 AS runtime
# Install ca-certificates for HTTPS requests
RUN apk --no-cache add ca-certificates curl
# Create a non-root user
RUN addgroup -g 1001 chromad && \
adduser -D -s /bin/sh -u 1001 -G chromad chromad
# Set working directory
WORKDIR /app
# Copy the binary from build stage
COPY --from=builder /app/build/chromad /app/chromad
# Change ownership to non-root user
RUN chown chromad:chromad /app/chromad
# Switch to non-root user
USER chromad
# Expose port (default is 8080, but can be overridden via PORT env var)
EXPOSE 8080
# Set default environment variables
ENV PORT=8080
ENV CHROMA_CSRF_KEY="testtest"
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -fsSL http://127.0.0.1:8080/ > /dev/null
# Run the application
CMD ["sh", "-c", "./chromad --csrf-key=$CHROMA_CSRF_KEY --bind=0.0.0.0:$PORT"]
chroma-2.23.1/Justfile 0000664 0000000 0000000 00000004016 15134556571 0014575 0 ustar 00root root 0000000 0000000 set positional-arguments := true
set shell := ["bash", "-c"]
version := `git describe --tags --dirty --always`
export GOOS := env("GOOS", "linux")
export GOARCH := env("GOARCH", "amd64")
_help:
@just -l
# Generate README.md from lexer definitions
readme:
#!/usr/bin/env bash
GOOS= GOARCH= ./table.py
# Generate tokentype_string.go
tokentype-string:
go generate
# Format JavaScript files
format-js:
biome format --write cmd/chromad/static/index.js cmd/chromad/static/chroma.js
# Build chromad binary
chromad: wasm-exec chroma-wasm
#!/usr/bin/env bash
rm -rf build
mk cmd/chromad/static/index.min.js : cmd/chromad/static/{index,chroma}.js -- \
esbuild --platform=browser --format=esm --bundle cmd/chromad/static/index.js --minify --external:./wasm_exec.js --outfile=cmd/chromad/static/index.min.js
mk cmd/chromad/static/index.min.css : cmd/chromad/static/index.css -- \
esbuild --bundle cmd/chromad/static/index.css --minify --outfile=cmd/chromad/static/index.min.css
cd cmd/chromad && CGOENABLED=0 go build -ldflags="-X 'main.version={{ version }}'" -o ../../build/chromad .
# Copy wasm_exec.js from TinyGo
wasm-exec:
#!/usr/bin/env bash
tinygoroot=$(tinygo env TINYGOROOT)
mk cmd/chromad/static/wasm_exec.js : "$tinygoroot/targets/wasm_exec.js" -- \
install -m644 "$tinygoroot/targets/wasm_exec.js" cmd/chromad/static/wasm_exec.js
# Build WASM binary
chroma-wasm:
#!/usr/bin/env bash
if type tinygo > /dev/null 2>&1; then
mk cmd/chromad/static/chroma.wasm : cmd/libchromawasm/main.go -- \
tinygo build -no-debug -target wasm -o cmd/chromad/static/chroma.wasm cmd/libchromawasm/main.go
else
mk cmd/chromad/static/chroma.wasm : cmd/libchromawasm/main.go -- \
GOOS=js GOARCH=wasm go build -o cmd/chromad/static/chroma.wasm cmd/libchromawasm/main.go
fi
# Upload chromad to server
upload: chromad
scp build/chromad root@swapoff.org:
ssh root@swapoff.org 'install -m755 ./chromad /srv/http/swapoff.org/bin && service chromad restart'
chroma-2.23.1/README.md 0000664 0000000 0000000 00000031221 15134556571 0014342 0 ustar 00root root 0000000 0000000 
# A general purpose syntax highlighter in pure Go
[](https://pkg.go.dev/github.com/alecthomas/chroma/v2) [](https://github.com/alecthomas/chroma/actions/workflows/ci.yml) [](https://invite.slack.golangbridge.org/)
Chroma takes source code and other structured text and converts it into syntax
highlighted HTML, ANSI-coloured text, etc.
Chroma is based heavily on [Pygments](http://pygments.org/), and includes
translators for Pygments lexers and styles.
## Table of Contents
1. [Supported languages](#supported-languages)
2. [Try it](#try-it)
3. [Using the library](#using-the-library)
1. [Quick start](#quick-start)
2. [Identifying the language](#identifying-the-language)
3. [Formatting the output](#formatting-the-output)
4. [The HTML formatter](#the-html-formatter)
4. [More detail](#more-detail)
1. [Lexers](#lexers)
2. [Formatters](#formatters)
3. [Styles](#styles)
5. [Command-line interface](#command-line-interface)
6. [Testing lexers](#testing-lexers)
7. [What's missing compared to Pygments?](#whats-missing-compared-to-pygments)
## Supported languages
| Prefix | Language
| :----: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| A | ABAP, ABNF, ActionScript, ActionScript 3, Ada, Agda, AL, Alloy, Angular2, ANTLR, ApacheConf, APL, AppleScript, ArangoDB AQL, Arduino, ArmAsm, ATL, AutoHotkey, AutoIt, Awk
| B | Ballerina, Bash, Bash Session, Batchfile, Beef, BibTeX, Bicep, BlitzBasic, BNF, BQN, Brainfuck
| C | C, C#, C++, C3, Caddyfile, Caddyfile Directives, Cap'n Proto, Cassandra CQL, Ceylon, CFEngine3, cfstatement, ChaiScript, Chapel, Cheetah, Clojure, CMake, COBOL, CoffeeScript, Common Lisp, Coq, Core, Crystal, CSS, CSV, CUE, Cython
| D | D, Dart, Dax, Desktop file, Diff, Django/Jinja, dns, Docker, DTD, Dylan
| E | EBNF, Elixir, Elm, EmacsLisp, Erlang
| F | Factor, Fennel, Fish, Forth, Fortran, FortranFixed, FSharp
| G | GAS, GDScript, GDScript3, Gemtext, Genshi, Genshi HTML, Genshi Text, Gherkin, Gleam, GLSL, Gnuplot, Go, Go HTML Template, Go Template, Go Text Template, GraphQL, Groff, Groovy
| H | Handlebars, Hare, Haskell, Haxe, HCL, Hexdump, HLB, HLSL, HolyC, HTML, HTTP, Hy
| I | Idris, Igor, INI, Io, ISCdhcpd
| J | J, Janet, Java, JavaScript, JSON, JSONata, Jsonnet, Julia, Jungle
| K | Kakoune, Kotlin
| L | Lean4, Lighttpd configuration file, LLVM, lox, Lua
| M | Makefile, Mako, markdown, Markless, Mason, Materialize SQL dialect, Mathematica, Matlab, MCFunction, Meson, Metal, MiniZinc, MLIR, Modelica, Modula-2, Mojo, MonkeyC, MoonScript, MorrowindScript, Myghty, MySQL
| N | NASM, Natural, NDISASM, Newspeak, Nginx configuration file, Nim, Nix, NSIS, Nu
| O | Objective-C, ObjectPascal, OCaml, Octave, Odin, OnesEnterprise, OpenEdge ABL, OpenSCAD, Org Mode
| P | PacmanConf, Perl, PHP, PHTML, Pig, PkgConfig, PL/pgSQL, plaintext, Plutus Core, Pony, PostgreSQL SQL dialect, PostScript, POVRay, PowerQuery, PowerShell, Prolog, Promela, PromQL, properties, Protocol Buffer, Protocol Buffer Text Format, PRQL, PSL, Puppet, Python, Python 2
| Q | QBasic, QML
| R | R, Racket, Ragel, Raku, react, ReasonML, reg, Rego, reStructuredText, Rexx, RGBDS Assembly, Ring, RPGLE, RPMSpec, Ruby, Rust
| S | SAS, Sass, Scala, Scheme, Scilab, SCSS, Sed, Sieve, Smali, Smalltalk, Smarty, SNBT, Snobol, Solidity, SourcePawn, SPARQL, SQL, SquidConf, Standard ML, stas, Stylus, Svelte, Swift, SYSTEMD, systemverilog
| T | TableGen, Tal, TASM, Tcl, Tcsh, Termcap, Terminfo, Terraform, TeX, Thrift, TOML, TradingView, Transact-SQL, Turing, Turtle, Twig, TypeScript, TypoScript, TypoScriptCssData, TypoScriptHtmlData, Typst
| U | ucode
| V | V, V shell, Vala, VB.net, verilog, VHDL, VHS, VimL, vue
| W | WDTE, WebAssembly Text Format, WebGPU Shading Language, WebVTT, Whiley
| X | XML, Xorg
| Y | YAML, YANG
| Z | Z80 Assembly, Zed, Zig
_I will attempt to keep this section up to date, but an authoritative list can be
displayed with `chroma --list`._
## Try it
Try out various languages and styles on the [Chroma Playground](https://swapoff.org/chroma/playground/).
## Using the library
This is version 2 of Chroma, use the import path:
```go
import "github.com/alecthomas/chroma/v2"
```
Chroma, like Pygments, has the concepts of
[lexers](https://github.com/alecthomas/chroma/tree/master/lexers),
[formatters](https://github.com/alecthomas/chroma/tree/master/formatters) and
[styles](https://github.com/alecthomas/chroma/tree/master/styles).
Lexers convert source text into a stream of tokens, styles specify how token
types are mapped to colours, and formatters convert tokens and styles into
formatted output.
A package exists for each of these, containing a global `Registry` variable
with all of the registered implementations. There are also helper functions
for using the registry in each package, such as looking up lexers by name or
matching filenames, etc.
In all cases, if a lexer, formatter or style can not be determined, `nil` will
be returned. In this situation you may want to default to the `Fallback`
value in each respective package, which provides sane defaults.
### Quick start
A convenience function exists that can be used to simply format some source
text, without any effort:
```go
err := quick.Highlight(os.Stdout, someSourceCode, "go", "html", "monokai")
```
### Identifying the language
To highlight code, you'll first have to identify what language the code is
written in. There are three primary ways to do that:
1. Detect the language from its filename.
```go
lexer := lexers.Match("foo.go")
```
2. Explicitly specify the language by its Chroma syntax ID (a full list is available from `lexers.Names()`).
```go
lexer := lexers.Get("go")
```
3. Detect the language from its content.
```go
lexer := lexers.Analyse("package main\n\nfunc main()\n{\n}\n")
```
In all cases, `nil` will be returned if the language can not be identified.
```go
if lexer == nil {
lexer = lexers.Fallback
}
```
At this point, it should be noted that some lexers can be extremely chatty. To
mitigate this, you can use the coalescing lexer to coalesce runs of identical
token types into a single token:
```go
lexer = chroma.Coalesce(lexer)
```
### Formatting the output
Once a language is identified you will need to pick a formatter and a style (theme).
```go
style := styles.Get("swapoff")
if style == nil {
style = styles.Fallback
}
formatter := formatters.Get("html")
if formatter == nil {
formatter = formatters.Fallback
}
```
Then obtain an iterator over the tokens:
```go
contents, err := ioutil.ReadAll(r)
iterator, err := lexer.Tokenise(nil, string(contents))
```
And finally, format the tokens from the iterator:
```go
err := formatter.Format(w, style, iterator)
```
### The HTML formatter
By default the `html` registered formatter generates standalone HTML with
embedded CSS. More flexibility is available through the `formatters/html` package.
Firstly, the output generated by the formatter can be customised with the
following constructor options:
- `Standalone()` - generate standalone HTML with embedded CSS.
- `WithClasses()` - use classes rather than inlined style attributes.
- `ClassPrefix(prefix)` - prefix each generated CSS class.
- `TabWidth(width)` - Set the rendered tab width, in characters.
- `WithLineNumbers()` - Render line numbers (style with `LineNumbers`).
- `WithLinkableLineNumbers()` - Make the line numbers linkable and be a link to themselves.
- `HighlightLines(ranges)` - Highlight lines in these ranges (style with `LineHighlight`).
- `LineNumbersInTable()` - Use a table for formatting line numbers and code, rather than spans.
If `WithClasses()` is used, the corresponding CSS can be obtained from the formatter with:
```go
formatter := html.New(html.WithClasses(true))
err := formatter.WriteCSS(w, style)
```
## More detail
### Lexers
See the [Pygments documentation](http://pygments.org/docs/lexerdevelopment/)
for details on implementing lexers. Most concepts apply directly to Chroma,
but see existing lexer implementations for real examples.
In many cases lexers can be automatically converted directly from Pygments by
using the included Python 3 script `pygments2chroma_xml.py`. I use something like
the following:
```sh
uv run --script _tools/pygments2chroma_xml.py \
pygments.lexers.jvm.KotlinLexer \
> lexers/embedded/kotlin.xml
```
A list of all lexers available in Pygments can be found in [pygments-lexers.txt](https://github.com/alecthomas/chroma/blob/master/pygments-lexers.txt).
### Formatters
Chroma supports HTML output, as well as terminal output in 8 colour, 256 colour, and true-colour.
A `noop` formatter is included that outputs the token text only, and a `tokens`
formatter outputs raw tokens. The latter is useful for debugging lexers.
### Styles
Chroma styles are defined in XML. The style entries use the
[same syntax](http://pygments.org/docs/styles/) as Pygments.
All Pygments styles have been converted to Chroma using the `_tools/style.py`
script.
When you work with one of [Chroma's styles](https://github.com/alecthomas/chroma/tree/master/styles),
know that the `Background` token type provides the default style for tokens. It does so
by defining a foreground color and background color.
For example, this gives each token name not defined in the style a default color
of `#f8f8f8` and uses `#000000` for the highlighted code block's background:
```xml
```
Also, token types in a style file are hierarchical. For instance, when `CommentSpecial` is not defined, Chroma uses the token style from `Comment`. So when several comment tokens use the same color, you'll only need to define `Comment` and override the one that has a different color.
For a quick overview of the available styles and how they look, check out the [Chroma Style Gallery](https://xyproto.github.io/splash/docs/).
## Command-line interface
A command-line interface to Chroma is included.
Binaries are available to install from [the releases page](https://github.com/alecthomas/chroma/releases).
The CLI can be used as a preprocessor to colorise output of `less(1)`,
see documentation for the `LESSOPEN` environment variable.
The `--fail` flag can be used to suppress output and return with exit status
1 to facilitate falling back to some other preprocessor in case chroma
does not resolve a specific lexer to use for the given file. For example:
```shell
export LESSOPEN='| p() { chroma --fail "$1" || cat "$1"; }; p "%s"'
```
Replace `cat` with your favourite fallback preprocessor.
When invoked as `.lessfilter`, the `--fail` flag is automatically turned
on under the hood for easy integration with [lesspipe shipping with
Debian and derivatives](https://manpages.debian.org/lesspipe#USER_DEFINED_FILTERS);
for that setup the `chroma` executable can be just symlinked to `~/.lessfilter`.
## Projects using Chroma
* [`moor`](https://github.com/walles/moor) is a full-blown pager that colorizes
its input using Chroma
* [Hugo](https://gohugo.io/) is a static site generator that [uses Chroma for syntax
highlighting code examples](https://gohugo.io/content-management/syntax-highlighting/)
## Testing lexers
If you edit some lexers and want to try it, open a shell in `cmd/chromad` and run:
```shell
go run . --csrf-key=securekey
```
A Link will be printed. Open it in your Browser. Now you can test on the Playground with your local changes.
If you want to run the tests and the lexers, open a shell in the root directory and run:
```shell
go test ./lexers
```
When updating or adding a lexer, please add tests. See [lexers/README.md](lexers/README.md) for more.
## What's missing compared to Pygments?
- Quite a few lexers, for various reasons (pull-requests welcome):
- Pygments lexers for complex languages often include custom code to
handle certain aspects, such as Raku's ability to nest code inside
regular expressions. These require time and effort to convert.
- I mostly only converted languages I had heard of, to reduce the porting cost.
- Some more esoteric features of Pygments are omitted for simplicity.
- Though the Chroma API supports content detection, very few languages support them.
I have plans to implement a statistical analyser at some point, but not enough time.
chroma-2.23.1/_tools/ 0000775 0000000 0000000 00000000000 15134556571 0014363 5 ustar 00root root 0000000 0000000 chroma-2.23.1/_tools/css2style/ 0000775 0000000 0000000 00000000000 15134556571 0016316 5 ustar 00root root 0000000 0000000 chroma-2.23.1/_tools/css2style/main.go 0000664 0000000 0000000 00000013303 15134556571 0017571 0 ustar 00root root 0000000 0000000 package main
import (
"io/ioutil"
"os"
"strings"
"text/template"
"github.com/aymerick/douceur/css"
"github.com/aymerick/douceur/parser"
"gopkg.in/alecthomas/kingpin.v3-unstable"
"github.com/alecthomas/chroma/v2"
)
const (
outputTemplate = `package styles
import (
"github.com/alecthomas/chroma/v2"
)
// {{.Name}} style.
var {{.Name}} = Register(chroma.MustNewStyle("{{.Name|Lower}}", chroma.StyleEntries{
{{- range .Rules}}
{{- if .Prelude|TokenType}}
chroma.{{.Prelude|TokenType}}: "{{.Declarations|TranslateDecls}}",
{{- end}}
{{- end}}
}))
`
)
var (
typeByClass = map[string]chroma.TokenType{
".hll": chroma.Background,
}
cssNamedColours = map[string]string{
"black": "#000000", "silver": "#c0c0c0", "gray": "#808080", "white": "#ffffff",
"maroon": "#800000", "red": "#ff0000", "purple": "#800080", "fuchsia": "#ff00ff",
"green": "#008000", "lime": "#00ff00", "olive": "#808000", "yellow": "#ffff00",
"navy": "#000080", "blue": "#0000ff", "teal": "#008080", "aqua": "#00ffff",
"orange": "#ffa500", "aliceblue": "#f0f8ff", "antiquewhite": "#faebd7", "aquamarine": "#7fffd4",
"azure": "#f0ffff", "beige": "#f5f5dc", "bisque": "#ffe4c4", "blanchedalmond": "#ffebcd",
"blueviolet": "#8a2be2", "brown": "#a52a2a", "burlywood": "#deb887", "cadetblue": "#5f9ea0",
"chartreuse": "#7fff00", "chocolate": "#d2691e", "coral": "#ff7f50", "cornflowerblue": "#6495ed",
"cornsilk": "#fff8dc", "crimson": "#dc143c", "cyan": "#00ffff", "darkblue": "#00008b",
"darkcyan": "#008b8b", "darkgoldenrod": "#b8860b", "darkgray": "#a9a9a9", "darkgreen": "#006400",
"darkgrey": "#a9a9a9", "darkkhaki": "#bdb76b", "darkmagenta": "#8b008b", "darkolivegreen": "#556b2f",
"darkorange": "#ff8c00", "darkorchid": "#9932cc", "darkred": "#8b0000", "darksalmon": "#e9967a",
"darkseagreen": "#8fbc8f", "darkslateblue": "#483d8b", "darkslategray": "#2f4f4f", "darkslategrey": "#2f4f4f",
"darkturquoise": "#00ced1", "darkviolet": "#9400d3", "deeppink": "#ff1493", "deepskyblue": "#00bfff",
"dimgray": "#696969", "dimgrey": "#696969", "dodgerblue": "#1e90ff", "firebrick": "#b22222",
"floralwhite": "#fffaf0", "forestgreen": "#228b22", "gainsboro": "#dcdcdc", "ghostwhite": "#f8f8ff",
"gold": "#ffd700", "goldenrod": "#daa520", "greenyellow": "#adff2f", "grey": "#808080",
"honeydew": "#f0fff0", "hotpink": "#ff69b4", "indianred": "#cd5c5c", "indigo": "#4b0082",
"ivory": "#fffff0", "khaki": "#f0e68c", "lavender": "#e6e6fa", "lavenderblush": "#fff0f5",
"lawngreen": "#7cfc00", "lemonchiffon": "#fffacd", "lightblue": "#add8e6", "lightcoral": "#f08080",
"lightcyan": "#e0ffff", "lightgoldenrodyellow": "#fafad2", "lightgray": "#d3d3d3", "lightgreen": "#90ee90",
"lightgrey": "#d3d3d3", "lightpink": "#ffb6c1", "lightsalmon": "#ffa07a", "lightseagreen": "#20b2aa",
"lightskyblue": "#87cefa", "lightslategray": "#778899", "lightslategrey": "#778899", "lightsteelblue": "#b0c4de",
"lightyellow": "#ffffe0", "limegreen": "#32cd32", "linen": "#faf0e6", "magenta": "#ff00ff",
"mediumaquamarine": "#66cdaa", "mediumblue": "#0000cd", "mediumorchid": "#ba55d3", "mediumpurple": "#9370db",
"mediumseagreen": "#3cb371", "mediumslateblue": "#7b68ee", "mediumspringgreen": "#00fa9a", "mediumturquoise": "#48d1cc",
"mediumvioletred": "#c71585", "midnightblue": "#191970", "mintcream": "#f5fffa", "mistyrose": "#ffe4e1",
"moccasin": "#ffe4b5", "navajowhite": "#ffdead", "oldlace": "#fdf5e6", "olivedrab": "#6b8e23",
"orangered": "#ff4500", "orchid": "#da70d6", "palegoldenrod": "#eee8aa", "palegreen": "#98fb98",
"paleturquoise": "#afeeee", "palevioletred": "#db7093", "papayawhip": "#ffefd5", "peachpuff": "#ffdab9",
"peru": "#cd853f", "pink": "#ffc0cb", "plum": "#dda0dd", "powderblue": "#b0e0e6",
"rosybrown": "#bc8f8f", "royalblue": "#4169e1", "saddlebrown": "#8b4513", "salmon": "#fa8072",
"sandybrown": "#f4a460", "seagreen": "#2e8b57", "seashell": "#fff5ee", "sienna": "#a0522d",
"skyblue": "#87ceeb", "slateblue": "#6a5acd", "slategray": "#708090", "slategrey": "#708090",
"snow": "#fffafa", "springgreen": "#00ff7f", "steelblue": "#4682b4", "tan": "#d2b48c",
"thistle": "#d8bfd8", "tomato": "#ff6347", "turquoise": "#40e0d0", "violet": "#ee82ee",
"wheat": "#f5deb3", "whitesmoke": "#f5f5f5", "yellowgreen": "#9acd32", "rebeccapurple": "#663399",
}
nameArg = kingpin.Arg("name", "Name of output style.").Required().String()
fileArg = kingpin.Arg("stylesheets", ".css file to import").Required().ExistingFile()
)
func init() {
for tt, str := range chroma.StandardTypes {
typeByClass["."+str] = tt
}
}
func translateDecls(decls []*css.Declaration) string {
out := []string{}
for _, decl := range decls {
switch decl.Property {
case "color":
clr := decl.Value
if c, ok := cssNamedColours[clr]; ok {
clr = c
}
out = append(out, clr)
case "background-color":
out = append(out, "bg:"+decl.Value)
case "font-style":
if strings.Contains(decl.Value, "italic") {
out = append(out, "italic")
}
case "font-weight":
if strings.Contains(decl.Value, "bold") {
out = append(out, "bold")
}
case "text-decoration":
if strings.Contains(decl.Value, "underline") {
out = append(out, "underline")
}
}
}
return strings.Join(out, " ")
}
func main() {
kingpin.Parse()
source, err := ioutil.ReadFile(*fileArg)
kingpin.FatalIfError(err, "")
css, err := parser.Parse(string(source))
kingpin.FatalIfError(err, "")
context := map[string]interface{}{
"Name": *nameArg,
"Rules": css.Rules,
}
tmpl := template.Must(template.New("style").Funcs(template.FuncMap{
"Lower": strings.ToLower,
"TranslateDecls": translateDecls,
"TokenType": func(s string) chroma.TokenType { return typeByClass[s] },
}).Parse(outputTemplate))
err = tmpl.Execute(os.Stdout, context)
kingpin.FatalIfError(err, "")
}
chroma-2.23.1/_tools/exercise/ 0000775 0000000 0000000 00000000000 15134556571 0016172 5 ustar 00root root 0000000 0000000 chroma-2.23.1/_tools/exercise/main.go 0000664 0000000 0000000 00000001771 15134556571 0017453 0 ustar 00root root 0000000 0000000 package main
import (
"fmt"
"io/ioutil"
"os"
"github.com/alecthomas/chroma/v2/formatters"
"github.com/alecthomas/chroma/v2/lexers"
"github.com/alecthomas/chroma/v2/styles"
"gopkg.in/alecthomas/kingpin.v3-unstable"
)
var (
filesArgs = kingpin.Arg("file", "Files to use to exercise lexers.").Required().ExistingFiles()
)
func main() {
kingpin.CommandLine.Help = "Exercise linters against a list of files."
kingpin.Parse()
for _, file := range *filesArgs {
lexer := lexers.Match(file)
if lexer == nil {
fmt.Printf("warning: could not find lexer for %q\n", file)
continue
}
fmt.Printf("%s: ", file)
os.Stdout.Sync()
text, err := ioutil.ReadFile(file)
kingpin.FatalIfError(err, "")
it, err := lexer.Tokenise(nil, string(text))
kingpin.FatalIfError(err, "%s failed to tokenise %q", lexer.Config().Name, file)
err = formatters.NoOp.Format(ioutil.Discard, styles.SwapOff, it)
kingpin.FatalIfError(err, "%s failed to format %q", lexer.Config().Name, file)
fmt.Printf("ok\n")
}
}
chroma-2.23.1/_tools/format_supported_langs.py 0000775 0000000 0000000 00000004150 15134556571 0021521 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
import re
import sys
from collections import defaultdict
def parse_lexers(lines: list[str]) -> list[str]:
"""Parse the output of chroma --list and return a list of lexer names"""
lexer_name_re: re.Pattern[str] = re.compile(r"^ ([^:\s].*?)\s*$")
lexers: list[str] = []
in_lexers = False
for line in lines:
line = line.rstrip()
if line.startswith("lexers:"):
in_lexers = True
continue
if not in_lexers:
continue
# stop when we hit styles/formatters/etc
if line.startswith("styles:") or line.startswith("formatters:"):
break
match: re.Match[str] | None = lexer_name_re.match(line)
if match:
name: str | None = match.group(1)
if name:
lexers.append(name)
return lexers
def group_by_prefix(lexers: list[str]) -> dict[str, list[str]]:
"""Given a list of lexer names, return a dictionary mapping prefixes
to lists of lexers that begin with that prefix"""
groups: defaultdict[str, list[str]] = defaultdict(list[str])
for name in lexers:
prefix: str = name[0].upper()
groups[prefix].append(name)
# sort alphabetically
for k in groups:
groups[k] = sorted(groups[k], key=lambda s: s.lower())
return dict(sorted(groups.items()))
def emit_markdown(groups: dict[str, list[str]]) -> str:
lines: list[str] = []
longest = 0
for prefix, lexers in groups.items():
joined: str = ", ".join(lexers)
l: int = len(joined)
if l > longest:
longest: int = l
lines.append(f"| {prefix} | {joined}")
splitter = f"| :----: | {longest * '-'}"
markdown: list[str] = ["| Prefix | Language", splitter]
markdown.extend(lines)
return "\n".join(markdown)
if __name__ == "__main__":
if sys.stdin.isatty():
print(
"This script parses chroma --list piped from stdin and emits a markdown table for the README"
)
print("Recommended usage (from repo root):")
print(
"env -C cmd/chroma go run . --list | uv run _tools/format_supported_langs.py"
)
exit(1)
lines: list[str] | None = sys.stdin.readlines()
if lines:
lexers: list[str] = parse_lexers(lines)
groups: dict[str, list[str]] = group_by_prefix(lexers)
print(emit_markdown(groups))
else:
exit(1)
chroma-2.23.1/_tools/pygments2chroma.hlb 0000664 0000000 0000000 00000001360 15134556571 0020174 0 ustar 00root root 0000000 0000000 fs default() {
gofmt fs { chromaLexer "pygments.lexers.hlb.HlbLexer"; }
}
fs script() {
local "." with option {
includePatterns "pygments2chroma.py"
}
}
fs runChromaPython(string package) {
image "python:alpine" with option { resolve; }
run "apk add -U git"
run "pip install -U pystache"
run "pip install -U -e git+https://github.com/hinshun/pygments.git@hlb-lexer#egg=pygments"
run string { format "python pygments2chroma.py %s > /out/lexer.go" package; } with option {
dir "/chroma"
mount script "/chroma"
mount fs { scratch; } "/out" as chromaLexer
}
}
fs runGoFormat(fs goFiles) {
image "golang:alpine" with option { resolve; }
run "gofmt -s -w /gofmt/*.go" with option {
dir "/gofmt"
mount goFiles "/gofmt" as gofmt
}
}
chroma-2.23.1/_tools/pygments2chroma_xml.py 0000775 0000000 0000000 00000014733 15134556571 0020752 0 ustar 00root root 0000000 0000000 #!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.13"
# dependencies = [
# "pygments",
# "pystache",
# ]
# ///
import argparse
import functools
import importlib
import re
import sys
import types
import html
import pystache
from pygments import lexer as pygments_lexer
from pygments.token import _TokenType
TEMPLATE = r'''
{{name}}
{{#aliases}}
{{alias}}
{{/aliases}}
{{#filenames}}
{{filename}}
{{/filenames}}
{{#mimetypes}}
{{mimetype}}
{{/mimetypes}}
{{#re_ignorecase}}
true
{{/re_ignorecase}}
{{#re_dotall}}
true
{{/re_dotall}}
{{#re_not_multiline}}
true
{{/re_not_multiline}}
{{#tokens}}
{{#rules}}
{{{.}}}
{{/rules}}
{{/tokens}}
'''
def xml_regex(s):
return xml_string(s)
def xml_string(s):
s = html.escape(s)
return '"' + s + '"'
def to_camel_case(snake_str):
components = snake_str.split('_')
return ''.join(x.title() for x in components)
def warning(message):
print('warning: ' + message, file=sys.stderr)
def resolve_emitter(emitter):
if isinstance(emitter, types.FunctionType):
if repr(emitter).startswith('' % '" state="'.join(rule[2])
else:
raise ValueError('unsupported modifier %r' % (rule[2],))
out.append('{}{}'.format(regex, emitter, modifier))
elif isinstance(rule, pygments_lexer.include):
out.append(''.format(rule))
elif isinstance(rule, pygments_lexer.default):
process_state_action(rule.state)
out.append('{}'.format(''.join(process_state_action(rule.state))))
else:
raise ValueError('unsupported rule %r' % (rule,))
return out
class TemplateView(object):
def __init__(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
def re_not_multiline(self):
return not (self.regex_flags & re.MULTILINE)
def re_dotall(self):
return self.regex_flags & re.DOTALL
def re_ignorecase(self):
return self.regex_flags & re.IGNORECASE
def main():
parser = argparse.ArgumentParser( prog='pygments2chroma_xml.py', description='Converts pygments RegexLexer classes to chroma xml grammar definitions.')
parser.add_argument('lexer_class', type=str, help="The class name of the pygments lexer, like: 'pygments.lexers.jvm.KotlinLexer'.")
args = parser.parse_args()
package_name, symbol_name = args.lexer_class.rsplit(sep=".", maxsplit=1)
package = importlib.import_module(package_name)
lexer_cls = getattr(package, symbol_name)
assert issubclass(lexer_cls, pygments_lexer.RegexLexer), 'can only translate from RegexLexer'
print(pystache.render(TEMPLATE, TemplateView(
name=lexer_cls.name,
regex_flags=lexer_cls.flags,
aliases=[{'alias': alias} for alias in lexer_cls.aliases],
filenames=[{'filename': filename} for filename in lexer_cls.filenames],
mimetypes=[{'mimetype': mimetype} for mimetype in lexer_cls.mimetypes],
tokens=[{'state': state, 'rules': translate_rules(rules)} for (state, rules) in lexer_cls.get_tokendefs().items()],
)))
if __name__ == '__main__':
main()
chroma-2.23.1/_tools/pyproject.toml 0000664 0000000 0000000 00000000315 15134556571 0017276 0 ustar 00root root 0000000 0000000 [project]
name = "chromatools"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"pygments>=2.19.1",
"pystache>=0.6.8",
]
chroma-2.23.1/_tools/style.py 0000775 0000000 0000000 00000002740 15134556571 0016103 0 ustar 00root root 0000000 0000000 #!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.13"
# dependencies = [
# "pygments",
# "pystache",
# ]
# ///
import importlib
import sys
import pystache
from pygments.style import Style
from pygments.token import Token
TEMPLATE = r'''
package styles
import (
"github.com/alecthomas/chroma/v2"
)
// {{upper_name}} style.
var {{upper_name}} = Register(chroma.MustNewStyle("{{name}}", chroma.StyleEntries{
{{#styles}}
chroma.{{type}}: "{{style}}",
{{/styles}}
}))
'''
def to_camel_case(snake_str):
components = snake_str.split('_')
return ''.join(x.title() for x in components)
def translate_token_type(t):
if t == Token:
t = Token.Background
return "".join(map(str, t))
def main():
name = sys.argv[1]
package_name, symbol_name = sys.argv[2].rsplit(sep=".", maxsplit=1)
package = importlib.import_module(package_name)
style_cls = getattr(package, symbol_name)
assert issubclass(style_cls, Style), 'can only translate from Style subclass'
styles = dict(style_cls.styles)
bg = "bg:" + style_cls.background_color
if Token in styles:
styles[Token] += " " + bg
else:
styles[Token] = bg
context = {
'upper_name': style_cls.__name__[:-5],
'name': name,
'styles': [{'type': translate_token_type(t), 'style': s}
for t, s in styles.items() if s],
}
print(pystache.render(TEMPLATE, context))
if __name__ == '__main__':
main()
chroma-2.23.1/_tools/uv.lock 0000664 0000000 0000000 00000003313 15134556571 0015667 0 ustar 00root root 0000000 0000000 version = 1
revision = 2
requires-python = ">=3.13"
[[package]]
name = "chromatools"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "pygments" },
{ name = "pystache" },
]
[package.metadata]
requires-dist = [
{ name = "pygments", specifier = ">=2.19.1" },
{ name = "pystache", specifier = ">=0.6.8" },
]
[[package]]
name = "pygments"
version = "2.19.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" },
]
[[package]]
name = "pystache"
version = "0.6.8"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/85/89/0a712ca22930b8c71bced8703e5bb45669c31690ea81afe15f6cb284550c/pystache-0.6.8.tar.gz", hash = "sha256:3707518e6a4d26dd189b07c10c669b1fc17df72684617c327bd3550e7075c72c", size = 101892, upload-time = "2025-03-18T11:54:47.595Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fa/78/ffd13a516219129cef6a754a11ba2a1c0d69f1e281af4f6bca9ed5327219/pystache-0.6.8-py3-none-any.whl", hash = "sha256:7211e000974a6e06bce2d4d5cad8df03bcfffefd367209117376e4527a1c3cb8", size = 82051, upload-time = "2025-03-18T11:54:45.813Z" },
]
chroma-2.23.1/bin/ 0000775 0000000 0000000 00000000000 15134556571 0013634 5 ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.binaryen-125.pkg 0000777 0000000 0000000 00000000000 15134556571 0017737 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.biome-2.3.10.pkg 0000777 0000000 0000000 00000000000 15134556571 0017435 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.bit-0.5.2.pkg 0000777 0000000 0000000 00000000000 15134556571 0017041 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.caddy-2.10.2.pkg 0000777 0000000 0000000 00000000000 15134556571 0017425 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.enumer-1.6.1.pkg 0000777 0000000 0000000 00000000000 15134556571 0017557 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.esbuild-0.27.2.pkg 0000777 0000000 0000000 00000000000 15134556571 0017776 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.go-1.25.5.pkg 0000777 0000000 0000000 00000000000 15134556571 0016756 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.golangci-lint-1.64.6.pkg 0000777 0000000 0000000 00000000000 15134556571 0021104 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.goreleaser-1.26.2.pkg 0000777 0000000 0000000 00000000000 15134556571 0020477 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.hlb-0.4.0.pkg 0000777 0000000 0000000 00000000000 15134556571 0017025 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.hyperfine-1.20.0.pkg 0000777 0000000 0000000 00000000000 15134556571 0020330 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.just-1.46.0.pkg 0000777 0000000 0000000 00000000000 15134556571 0017334 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.mk-0.10.1.pkg 0000777 0000000 0000000 00000000000 15134556571 0016745 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.python3-3.13.2.pkg 0000777 0000000 0000000 00000000000 15134556571 0017751 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.reflex-0.3.1.pkg 0000777 0000000 0000000 00000000000 15134556571 0017545 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.svu-3.3.0.pkg 0000777 0000000 0000000 00000000000 15134556571 0017077 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.tinygo-0.40.1.pkg 0000777 0000000 0000000 00000000000 15134556571 0017652 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.typescript-7.0.0-dev.20250629.1.pkg 0000777 0000000 0000000 00000000000 15134556571 0022314 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.uv-0.9.18.pkg 0000777 0000000 0000000 00000000000 15134556571 0017010 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/.watchexec-2.3.2.pkg 0000777 0000000 0000000 00000000000 15134556571 0020236 2hermit ustar 00root root 0000000 0000000 chroma-2.23.1/bin/README.hermit.md 0000664 0000000 0000000 00000000416 15134556571 0016403 0 ustar 00root root 0000000 0000000 # Hermit environment
This is a [Hermit](https://github.com/cashapp/hermit) bin directory.
The symlinks in this directory are managed by Hermit and will automatically
download and install Hermit itself as well as packages. These packages are
local to this environment.
chroma-2.23.1/bin/activate-hermit 0000775 0000000 0000000 00000001062 15134556571 0016647 0 ustar 00root root 0000000 0000000 #!/bin/bash
# This file must be used with "source bin/activate-hermit" from bash or zsh.
# You cannot run it directly
if [ "${BASH_SOURCE-}" = "$0" ]; then
echo "You must source this script: \$ source $0" >&2
exit 33
fi
BIN_DIR="$(dirname "${BASH_SOURCE[0]:-${(%):-%x}}")"
if "${BIN_DIR}/hermit" noop > /dev/null; then
eval "$("${BIN_DIR}/hermit" activate "${BIN_DIR}/..")"
if [ -n "${BASH-}" ] || [ -n "${ZSH_VERSION-}" ]; then
hash -r 2>/dev/null
fi
echo "Hermit environment $("${HERMIT_ENV}"/bin/hermit env HERMIT_ENV) activated"
fi
chroma-2.23.1/bin/binaryen-unittests 0000777 0000000 0000000 00000000000 15134556571 0022316 2.binaryen-125.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/biome 0000777 0000000 0000000 00000000000 15134556571 0017240 2.biome-2.3.10.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/bit 0000777 0000000 0000000 00000000000 15134556571 0016327 2.bit-0.5.2.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/caddy 0000777 0000000 0000000 00000000000 15134556571 0017221 2.caddy-2.10.2.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/chroma 0000775 0000000 0000000 00000000147 15134556571 0015035 0 ustar 00root root 0000000 0000000 #!/bin/bash
set -euo pipefail
go build -C cmd/chroma -o $TMPDIR/chroma . && exec $TMPDIR/chroma "$@"
chroma-2.23.1/bin/chromad 0000775 0000000 0000000 00000000152 15134556571 0015175 0 ustar 00root root 0000000 0000000 #!/bin/bash
set -euo pipefail
go build -C cmd/chromad -o $TMPDIR/chromad . && exec $TMPDIR/chromad "$@"
chroma-2.23.1/bin/enumer 0000777 0000000 0000000 00000000000 15134556571 0017562 2.enumer-1.6.1.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/esbuild 0000777 0000000 0000000 00000000000 15134556571 0020135 2.esbuild-0.27.2.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/go 0000777 0000000 0000000 00000000000 15134556571 0016073 2.go-1.25.5.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/gofmt 0000777 0000000 0000000 00000000000 15134556571 0016602 2.go-1.25.5.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/golangci-lint 0000777 0000000 0000000 00000000000 15134556571 0022343 2.golangci-lint-1.64.6.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/goreleaser 0000777 0000000 0000000 00000000000 15134556571 0021337 2.goreleaser-1.26.2.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/hermit 0000775 0000000 0000000 00000001361 15134556571 0015053 0 ustar 00root root 0000000 0000000 #!/bin/bash
set -eo pipefail
if [ -z "${HERMIT_STATE_DIR}" ]; then
case "$(uname -s)" in
Darwin)
export HERMIT_STATE_DIR="${HOME}/Library/Caches/hermit"
;;
Linux)
export HERMIT_STATE_DIR="${XDG_CACHE_HOME:-${HOME}/.cache}/hermit"
;;
esac
fi
export HERMIT_DIST_URL="${HERMIT_DIST_URL:-https://github.com/cashapp/hermit/releases/download/stable}"
HERMIT_CHANNEL="$(basename "${HERMIT_DIST_URL}")"
export HERMIT_CHANNEL
export HERMIT_EXE=${HERMIT_EXE:-${HERMIT_STATE_DIR}/pkg/hermit@${HERMIT_CHANNEL}/hermit}
if [ ! -x "${HERMIT_EXE}" ]; then
echo "Bootstrapping ${HERMIT_EXE} from ${HERMIT_DIST_URL}" 1>&2
curl -fsSL "${HERMIT_DIST_URL}/install.sh" | /bin/bash 1>&2
fi
exec "${HERMIT_EXE}" --level=fatal exec "$0" -- "$@"
chroma-2.23.1/bin/hermit.hcl 0000664 0000000 0000000 00000000000 15134556571 0015602 0 ustar 00root root 0000000 0000000 chroma-2.23.1/bin/hlb 0000777 0000000 0000000 00000000000 15134556571 0016302 2.hlb-0.4.0.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/hyperfine 0000777 0000000 0000000 00000000000 15134556571 0021031 2.hyperfine-1.20.0.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/just 0000777 0000000 0000000 00000000000 15134556571 0017031 2.just-1.46.0.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/mk 0000777 0000000 0000000 00000000000 15134556571 0016064 2.mk-0.10.1.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/pip 0000777 0000000 0000000 00000000000 15134556571 0017251 2.python3-3.13.2.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/pip3 0000777 0000000 0000000 00000000000 15134556571 0017334 2.python3-3.13.2.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/pip3.13 0000777 0000000 0000000 00000000000 15134556571 0017556 2.python3-3.13.2.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/pydoc3 0000777 0000000 0000000 00000000000 15134556571 0017662 2.python3-3.13.2.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/pydoc3.13 0000777 0000000 0000000 00000000000 15134556571 0020104 2.python3-3.13.2.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/python 0000777 0000000 0000000 00000000000 15134556571 0020002 2.python3-3.13.2.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/python3 0000777 0000000 0000000 00000000000 15134556571 0020065 2.python3-3.13.2.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/python3-config 0000777 0000000 0000000 00000000000 15134556571 0021330 2.python3-3.13.2.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/python3.13 0000777 0000000 0000000 00000000000 15134556571 0020307 2.python3-3.13.2.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/python3.13-config 0000777 0000000 0000000 00000000000 15134556571 0021552 2.python3-3.13.2.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/reflex 0000777 0000000 0000000 00000000000 15134556571 0017542 2.reflex-0.3.1.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/svu 0000777 0000000 0000000 00000000000 15134556571 0016424 2.svu-3.3.0.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/tinygo 0000777 0000000 0000000 00000000000 15134556571 0017673 2.tinygo-0.40.1.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/tsc 0000777 0000000 0000000 00000000000 15134556571 0021615 2.typescript-7.0.0-dev.20250629.1.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/uv 0000777 0000000 0000000 00000000000 15134556571 0016152 2.uv-0.9.18.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/uvx 0000777 0000000 0000000 00000000000 15134556571 0016342 2.uv-0.9.18.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/wasm-as 0000777 0000000 0000000 00000000000 15134556571 0020017 2.binaryen-125.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/wasm-ctor-eval 0000777 0000000 0000000 00000000000 15134556571 0021310 2.binaryen-125.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/wasm-dis 0000777 0000000 0000000 00000000000 15134556571 0020173 2.binaryen-125.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/wasm-emscripten-finalize 0000777 0000000 0000000 00000000000 15134556571 0023364 2.binaryen-125.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/wasm-fuzz-lattices 0000777 0000000 0000000 00000000000 15134556571 0022220 2.binaryen-125.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/wasm-fuzz-types 0000777 0000000 0000000 00000000000 15134556571 0021554 2.binaryen-125.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/wasm-merge 0000777 0000000 0000000 00000000000 15134556571 0020513 2.binaryen-125.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/wasm-metadce 0000777 0000000 0000000 00000000000 15134556571 0021016 2.binaryen-125.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/wasm-opt 0000777 0000000 0000000 00000000000 15134556571 0020216 2.binaryen-125.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/wasm-reduce 0000777 0000000 0000000 00000000000 15134556571 0020663 2.binaryen-125.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/wasm-shell 0000777 0000000 0000000 00000000000 15134556571 0020523 2.binaryen-125.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/wasm-split 0000777 0000000 0000000 00000000000 15134556571 0020547 2.binaryen-125.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/wasm2js 0000777 0000000 0000000 00000000000 15134556571 0020035 2.binaryen-125.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/bin/watchexec 0000777 0000000 0000000 00000000000 15134556571 0020721 2.watchexec-2.3.2.pkg ustar 00root root 0000000 0000000 chroma-2.23.1/biome.json 0000664 0000000 0000000 00000000155 15134556571 0015053 0 ustar 00root root 0000000 0000000 {
"$schema": "https://biomejs.dev/schemas/2.0.5/schema.json",
"formatter": {
"indentStyle": "space"
}
}
chroma-2.23.1/chroma.jpg 0000664 0000000 0000000 00000236066 15134556571 0015054 0 ustar 00root root 0000000 0000000 Exif MM * V ^( i f H H 0221 0100 @ "
} !1AQa"q2#BR$3br
%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz
w !1AQaq"2B #3Rbr
$4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ? n
Npy?
Lm?~TEjtoҝ@^ӠJ.Z
Z~Cӵ,k11REv R4E rǪNOn=)A8큊5v?ҫO\zg9^2M r21YZ3ejכy܈+F0)P{Үp7 *)~T^F3Js1V:cA)Hc*1{TkB3>ʧHw|v##SⵉFb.NX?Ʈc=*o!Oҭ#H9jGJ 8=3t#Lmyֆo']69$v-[O5QPҷ<