From 4274618525b15b2a5aff40ebc7fb527f0eb1b0f9 Mon Sep 17 00:00:00 2001 From: Catalin Constantin Mititiuc Date: Sat, 21 Jun 2025 13:01:31 -0700 Subject: [PATCH] Edit post draft --- posts/2025-06-20-chroma.md | 218 ++++++++++++++++++++++++------------- 1 file changed, 145 insertions(+), 73 deletions(-) diff --git a/posts/2025-06-20-chroma.md b/posts/2025-06-20-chroma.md index 2da98bc..14f4bb3 100644 --- a/posts/2025-06-20-chroma.md +++ b/posts/2025-06-20-chroma.md @@ -1,62 +1,74 @@ { - blurb: "Add a new lexer to chroma" + blurb: "Add a new lexer to Chroma" } $index -## Intro +## Introduction -Gitea uses Chroma for syntax highlighting. Chroma doesn't have a MoonScript -lexer. It does has a Python script that can convert Pygments lexers, though, -and Pygments has a MoonScript lexer. +[Gitea](https://github.com/go-gitea/gitea) uses [Chroma](https://github.com/alecthomas/chroma) for syntax highlighting. Chroma is based on the Python +syntax highlighter, [Pygments](https://github.com/pygments/pygments), and includes a [script](https://github.com/alecthomas/chroma/blob/484750a96fc430f49d6b69cc2a2a8b7a67691446/_tools/pygments2chroma_xml.py) to help convert Pygments +lexers for use with Chroma. This post describes that process. -## Run MoonScript lexer generation script +## Convert a Pygments lexer to a Chroma lexer with `pygments2chroma_xml.py` -To create the lexer, in the Chroma root directory run: +In the Chroma root directory, we run: ```console $ docker run --rm -it -w /opt -v $PWD:/opt python bash -c \ -"pip install pystache pygments \ +"pip install pystache pygments && pip list \ && python _tools/pygments2chroma_xml.py \ -pygments.lexers.scripting.MoonScriptLexer > lexers/embedded/moonscript.xml \ -&& pip list" +pygments.lexers.scripting.LuaLexer > lexers/embedded/lua.xml" ``` -## Use the Chroma MoonScript lexer to highlight some code +As output, we should see this in our terminal: -Create a file like this: +``` +Package Version +-------- ------- +pip 25.0.1 +Pygments 2.19.2 +pystache 0.6.8 +``` + +This just helps us know what version of Pygments we generated our lexer from. +The file `lexers/embedded/lua.xml` should now contain all the tokenization +rules for the [Lua](https://www.lua.org) language. ::: filename-for-code-block -`main.go` +`lexers/embedded/lua.xml` ::: -```go -package main - -import ( - "fmt" - "os" - - "github.com/alecthomas/chroma/v2/quick" -) - -func main() { - code := `package main - - func main() { } - ` - - fmt.Println(quick.Highlight(os.Stdout, code, "go", "html", "monokai")) -} +```xml + + + Lua + ... ``` -I did one of these: +## Highlight some code with our new lexer + +Chroma provides a [simple example test file][1] we can modify to see what syntax +highlighting with our new lexer looks like. First, though, we need to create a +new Go module by running `go mod init`: ```console $ docker run --rm -it -w /opt -v $PWD:/opt golang:tip-bookworm \ go mod init main +go: creating new go.mod: module main +go: to add module requirements and sums: + go mod tidy ``` -Which gave me the `go.mod` file. +We will need required modules, so let's go ahead and run `go mod tidy` as the +output suggests. + +```console +$ docker run --rm -it -w /opt -v $PWD:/opt golang:tip-bookworm \ +go mod tidy +``` + +We should now have 2 additional files, `go.mod` and `go.sum`. `go.sum` has some +package hashes while `go.mod` should look like this: ::: filename-for-code-block `go.mod` @@ -67,23 +79,55 @@ module main go 1.25 -require ( - github.com/alecthomas/chroma/v2 v2.18.0 // indirect - github.com/dlclark/regexp2 v1.11.5 // indirect -) +require github.com/alecthomas/chroma/v2 v2.18.0 + +require github.com/dlclark/regexp2 v1.11.5 // indirect ``` -Then I did one of these: +Now we can create a `main.go` file and copy over the code from Chroma's example +test file, but we update the `code` variable and the lexer we pass into the +`Highlight` function for Lua: + + +::: filename-for-code-block +`main.go` +::: + +```go +package main + +import ( + "log" + "os" + + "github.com/alecthomas/chroma/v2/quick" +) + +func main() { + code := `print("hello")` + + err := quick.Highlight(os.Stdout, code, "lua", "html", "monokai") + if err != nil { + log.Fatal(err) + } +} +``` + +Now we can try running our `main.go` like this: ```console -$ docker run --rm -it -w /opt -v $PWD:/opt golang:tip-bookworm \ -go run main.go +$ docker run --rm -it -w /opt -v $PWD:/opt golang:tip-bookworm go run main.go +go: downloading github.com/alecthomas/chroma/v2 v2.18.0 +go: downloading github.com/dlclark/regexp2 v1.11.5 + +