A Crystal reimplementation of the Pygments/Chroma syntax highlighters
Go to file
Roberto Alsina d1ce83a9c8
Some checks failed
Tests / build (push) Has been cancelled
fix: Don't log when falling back to ruby, it breaks stuff
2025-03-09 18:38:42 -03:00
.github/workflows chore: upgrade ci image 2025-01-21 15:11:06 -03:00
fonts feat: PNG writer based on Stumpy libs 2024-09-21 20:22:30 -03:00
lexers feat: Bumped to latest chroma release 2025-01-21 12:31:39 -03:00
scripts fix: Fix metadata to show crystal 2024-09-26 18:47:47 -03:00
spec chore: mark more mcfunction tests as bad 2025-01-21 14:37:10 -03:00
src fix: Don't log when falling back to ruby, it breaks stuff 2025-03-09 18:38:42 -03:00
styles feat: Bumped to latest chroma release 2025-01-21 12:31:39 -03:00
.ameba.yml feat: SVG formatter 2024-09-21 12:56:40 -03:00
.editorconfig Initial dumb stuff 2024-08-02 17:03:39 -03:00
.gitignore feat: Bumped to latest chroma release 2025-01-21 12:31:39 -03:00
.md.rb build: fix markdown check 2024-09-04 11:37:36 -03:00
.mdlrc build: fix markdown check 2024-09-04 11:37:36 -03:00
.pre-commit-config.yaml chore: force conventional commit messages 2024-08-26 21:27:38 -03:00
build_static.sh chore(build): strip static binary 2024-09-26 20:50:14 -03:00
CHANGELOG.md bump: Release v0.12.0 2025-01-21 14:37:49 -03:00
cliff.toml chore: clean 2024-09-21 14:00:13 -03:00
do_release.sh chore: build before tag 2024-09-26 20:47:58 -03:00
Dockerfile.static Added helper files 2024-08-09 10:32:15 -03:00
Hacefile.yml build: automate AUR release 2024-10-14 17:27:31 -03:00
LICENSE Initial dumb stuff 2024-08-02 17:03:39 -03:00
README.md feat: Support custom template for HTML standalone output 2025-02-21 19:43:09 -03:00
shard.yml bump: Release v0.12.0 2025-01-21 14:37:49 -03:00
TODO.md Load lexer by mimetype 2024-08-24 22:20:38 -03:00

TARTRAZINE

Tests codecov

Tartrazine is a library to syntax-highlight code. It is a port of Pygments to Crystal.

It also provides a CLI tool which can be used to highlight many things in many styles.

Currently Tartrazine supports 247 languages and has 331 themes (63 from Chroma, the rest are base16 themes via Sixteen

Installation

If you are using Arch: Use yay or your favourite AUR helper, package name is tartrazine.

From prebuilt binaries:

Each release provides statically-linked binaries that should work on any Linux. Get them from the releases page and put them in your PATH.

To build from source:

  1. Clone this repo
  2. Run make to build the tartrazine binary
  3. Copy the binary somewhere in your PATH.

Usage as a CLI tool

Show a syntax highlighted version of a C source file in your terminal:

tartrazine whatever.c -l c -t catppuccin-macchiato --line-numbers -f terminal

Generate a standalone HTML file from a C source file with the syntax highlighted:

$ tartrazine whatever.c -t catppuccin-macchiato --line-numbers \
  --standalone -f html -o whatever.html

Usage as a Library

Add to your shard.yml:

dependencies:
  tartrazine:
    github: ralsina/tartrazine

This is the high level API:

require "tartrazine"

html = Tartrazine.to_html(
  "puts \"Hello, world!\"",
  language: "crystal",
  theme: "catppuccin-macchiato",
  standalone: true,
  line_numbers: true
)

This does more or less the same thing, but more manually:

lexer = Tartrazine.lexer("crystal")
formatter = Tartrazine::Html.new(
  theme: Tartrazine.theme("catppuccin-macchiato"),
  line_numbers: true,
  standalone: true,
)
puts formatter.format("puts \"Hello, world!\"", lexer)

The reason you may want to use the manual version is to reuse the lexer and formatter objects for performance reasons.

Choosing what Lexers you want

By default Tartrazine will support all its lexers by embedding them in the binary. This makes the binary large. If you are using it as a library, you may want to just include a selection of lexers. To do that:

  • Pass the -Dnolexers flag to the compiler
  • Set the TT_LEXERS environment variable to a comma-separated list of lexers you want to include.

This builds a binary with only the python, markdown, bash and yaml lexers (enough to highlight this README.md):

> TT_LEXERS=python,markdown,bash,yaml shards build -Dnolexers -d --error-trace
Dependencies are satisfied
Building: tartrazine

Choosing what themes you want

Themes come from two places, tartrazine itself and Sixteen.

To only embed selected themes, build your project with the -Dnothemes option, and you can set two environment variables to control which themes are included:

  • TT_THEMES is a comma-separated list of themes to include from tartrazine (see the styles directory in the source)
  • SIXTEEN_THEMES is a comma-separated list of themes to include from Sixteen (see the base16 directory in the sixteen source)

For example (using the tartrazine CLI as the project):

$ TT_THEMES=colorful,autumn SIXTEEN_THEMES=pasque,pico shards build -Dnothemes
Dependencies are satisfied
Building: tartrazine

$ ./bin/tartrazine  --list-themes
autumn
colorful
pasque
pico

Be careful not to build without any themes at all, nothing will work.

Templates for standalone HTML output

If you are using the HTML formatter, you can pass a template to use for the output. The template is a string where the following placeholders will be replaced:

  • {{style_defs}} will be replaced by the CSS styles needed for the theme
  • {{code}} will be replaced by the highlighted code

This is an example template that changes the padding around the code:

<!DOCTYPE html>
<html>
  <head>
    <style>
      {{style_defs}}
      pre {
      padding: 1em;
      }
    </style>
  </head>
  <body>
    {{body}}
  </body>
</html>

Contributing

  1. Fork it (https://github.com/ralsina/tartrazine/fork)
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Contributors

A port of what, and why "kind of"

Pygments is a staple of the Python ecosystem, and it's great. It lets you highlight code in many languages, and it has many themes. Chroma is "Pygments for Go", it's actually a port of Pygments to Go, and it's great too.

I wanted that in Crystal, so I started this project. But I did not read much of the Pygments code. Or much of Chroma's.

Chroma has taken most of the Pygments lexers and turned them into XML descriptions. What I did was take those XML files from Chroma and a pile of test cases from Pygments, and I slapped them together until the tests passed and my code produced the same output as Chroma. Think of it as extreme TDD

Currently the pass rate for tests in the supported languages is 96.8%, which is not bad for a couple days hacking.

This only covers the RegexLexers, which are the most common ones, but it means the supported languages are a subset of Chroma's, which is a subset of Pygments' and DelegatingLexers (useful for things like template languages)

Then performance was bad, so I hacked and hacked and made it significantly faster than chroma which is fun.