Chroma Syntax Highlighter

repository·master·Indexed 26 days ago

https://github.com/alecthomas/chroma

A general-purpose syntax highlighter written in pure Go, inspired by Pygments. It converts source code and structured text into formats such as HTML, ANSI-colored text, JSON, and SVG. Chroma provides a Go library (v3), a CLI tool for highlighting files or stdin, and a web service (chromad) with a syntax highlighting playground and JSON API.

Tokens
9.3K
Snippets
26
Records
65
Agent score
82%

What's inside chroma

  1. Format syntax highlighted output manually

    master

    For full control, follow these steps to manually tokenize and format code:

    1. Get the Lexer, Style, and Formatter: Use lexers.Get, styles.Get, and formatters.Get. Always check for nil and use the respective Fallback if necessary.
    2. Tokenize: Call lexer.Tokenise(nil, content) to get an iterator.
    3. Format: Call formatter.Format(writer, style, iterator) to produce the final output.
    style := styles.Get("swapoff")
    if style == nil {
      style = styles.Fallback
    }
    formatter := formatters.Get("html")
    if formatter == nil {
      formatter = formatters.Fallback
    }
    
    contents, err := io.ReadAll(r)
    iterator, err := lexer.Tokenise(nil, string(contents))
    
    err := formatter.Format(w, style, iterator)
  2. Identify the language for syntax highlighting

    master

    To highlight code, you must first identify the language using one of three methods. If a method returns nil, you should use lexers.Fallback to ensure a lexer is available. You can also use chroma.Coalesce(lexer) to reduce the number of tokens by merging identical consecutive token types.

    1. From filename: Use lexers.Match(filename).
    2. By syntax ID: Use lexers.Get(syntaxID) (available IDs can be found via lexers.Names()).
    3. From content: Use lexers.Analyse(content).
    // 1. Match by filename
    lexer := lexers.Match("foo.go")
    
    // 2. Get by syntax ID
    lexer := lexers.Get("go")
    
    // 3. Analyse content
    lexer := lexers.Analyse("package main\n\nfunc main()\n{\n}\n")
    
    // Handle failed identification
    if lexer == nil {
      lexer = lexers.Fallback
    }
    
    // Optional: Coalesce tokens to reduce verbosity
    lexer = chroma.Coalesce(lexer)
  3. Run Chroma lexer tests

    master

    To verify the correctness of Chroma lexers, you can run the existing test suite. The tests work by feeding input files from testdata/<name>.actual into the parser and comparing the output against <name>.expected. You can also group multiple test inputs for a single parser by placing them in testdata/<name>/.

    go test ./lexers
  4. Configure Chroma as a `less` preprocessor

    master

    Chroma can be used as a preprocessor for less(1) via the LESSOPEN environment variable. Using the --fail flag allows the system to fall back to a different preprocessor (like cat) if Chroma cannot resolve a lexer for a specific file.

    To set this up, export the following environment variable:

    export LESSOPEN='| p() { chroma --fail "$1" || cat "$1"; }; p "%s"'

    Note: When invoked as a .lessfilter, the --fail flag is enabled automatically.

    export LESSOPEN='| p() { chroma --fail "$1" || cat "$1"; }; p "%s"'
  5. Test local lexer changes in the Playground

    master

    If you are developing or editing lexers and want to test them in a browser-based playground:

    1. Open a shell in cmd/chromad.
    2. Run the following command:
    go run . --csrf-key=securekey
    1. Open the printed link in your browser to use the Playground with your local changes.
    go run . --csrf-key=securekey
  6. Regenerate lexer test files

    master

    When adding new test data files (*.actual), you must regenerate the corresponding *.expected files. This is done by setting the RECORD environment variable to true before running the tests. This tells Chroma to output the test data into the expected files.

    RECORD=true go test ./lexers
  7. Regenerate lexer tests on Windows

    master

    The inline environment variable syntax RECORD=true go test ./lexers is not supported in standard Windows Command Prompt or PowerShell. You must set the environment variable in a separate step before running the test command.

    Command Prompt:

    set RECORD=true
    go test ./lexers

    PowerShell:

    $env:RECORD = 'true'
    go test ./lexers
  8. Quick start with Chroma

    master

    Use the quick.Highlight convenience function to format source text with minimal setup. It allows you to specify the output writer, the source code, the language syntax ID, the formatter name, and the style name in a single call.

    ```go
    err := quick.Highlight(os.Stdout, someSourceCode, "go", "html", "monokai")
    ```埋
  9. Convert Pygments lexers to Chroma XML

    master

    You can automatically convert lexers from Pygments to Chroma's XML format using the provided Python 3 script pygments2chroma_xml.py. This is useful for porting community-maintained lexers.

    Example conversion using uv:

    uv run --script _tools/pygments2chroma_xml.py \
      pygments.lexers.jvm.KotlinLexer \
      > lexers/embedded/kotlin.xml
    uv run --script _tools/pygments2chroma_xml.py \
      pygments.lexers.jvm.KotlinLexer \
      > lexers/embedded/kotlin.xml
  10. Use Chroma in the browser via WASM

    master

    The libchromawasm package provides an experimental WebAssembly (WASM) build of Chroma intended for use with TinyGO. When loaded in a browser environment, it registers a global highlight function on the JavaScript window object.

    JavaScript API Signature

    /**
     * @param {string} source - The source code text to highlight.
     * @param {string} lexer - The name of the lexer (e.g., 'go', 'python'). If unknown, Chroma attempts to autodetect the language.
     * @param {string} styleName - The name of the color style to use.
     * @param {boolean} classes - Whether to use CSS classes for styling instead of inline styles.
     * @returns {{html: string, language: string, background: string}} An object containing the highlighted HTML, detected language, and background color.
     */
    function highlight(source, lexer, styleName, classes) { ... }