GOX / LIBRARY
Examples
Go libraries. GOX components. Code for your next project.
Code
Display source code with syntax highlighting.
Source
1package main
2
3import "fmt"
4
5func main() {
6 fmt.Println("Hello, GOX!")
7}
Result
1package main
2
3import "fmt"
4
5func main() {
6 fmt.Println("Hello, GOX!")
7}
1. Add the Go library
Run this command from your project root.
gox get github.com/alecthomas/chroma/[email protected]
2. Copy the component
Save the complete GOX source from the Code tab as pages/@components/code.gox.
Use it in your page
module index
import (
"github.com/gox-lang/gox"
highlighted "@components/code.gox"
)
const greeting = `package main
import "fmt"
func main() {
fmt.Println("Hello, GOX!")
}`
func GET(ctx *gox.Context) gox.Page {
return <main>
<&highlighted.Code source={{ greeting }} language="go" />
</main>
}
Chroma escapes the source and renders highlighted HTML on the server. Unknown languages fall back to plain text. Light and dark styles are included; the dark style follows data-theme=dark on the root element. Styles are written once to public/generated/code, which must be writable. The memory cache is intended for a finite set of project examples.
pages/@components/code.gox
This is the complete component used by the live preview. Copy this single GOX file into your project.
module highlightedcode
import (
"bytes"
"crypto/sha256"
"fmt"
"os"
"path/filepath"
"log"
"strings"
"sync"
"github.com/alecthomas/chroma/v2"
chromahtml "github.com/alecthomas/chroma/v2/formatters/html"
"github.com/alecthomas/chroma/v2/lexers"
"github.com/alecthomas/chroma/v2/styles"
"github.com/gox-lang/gox"
)
type CodeKey struct {
Source string
Language string
}
// Intended for a finite set of project examples, not arbitrary user submissions.
var cache map[CodeKey]string = make(map[CodeKey]string)
var cacheMu sync.RWMutex
var cssOnce sync.Once
var stylesheetURL string
var stylesheetError error
func Code(source string, language string) gox.Component {
rendered, err := Render(source, language)
if err != nil {
log.Printf("Code: %v", err)
return <pre><code>{{ source }}</code></pre>
}
cssOnce.Do(func() {
formatter := chromahtml.New(chromahtml.WithClasses(true))
var light bytes.Buffer
var dark bytes.Buffer
formatter.WriteCSS(&light, styles.Get("github"))
formatter.WriteCSS(&dark, styles.Get("dracula"))
lightCSS := strings.ReplaceAll(light.String(), ".bg", ":root:not([data-theme=dark]) .gox-code .bg")
darkCSS := strings.ReplaceAll(dark.String(), ".bg", ":root[data-theme=dark] .gox-code .bg")
css := strings.ReplaceAll(lightCSS, ".chroma", ":root:not([data-theme=dark]) .gox-code .chroma") +
strings.ReplaceAll(darkCSS, ".chroma", ":root[data-theme=dark] .gox-code .chroma")
stylesheetURL, stylesheetError = WriteStylesheet(css)
})
if stylesheetError != nil {
log.Printf("Code stylesheet: %v", stylesheetError)
return <pre><code>{{ source }}</code></pre>
}
return <div class="gox-code" data-language={{ language }}>
<link rel="stylesheet" href={{ stylesheetURL }} />
{{< rendered >}}
</div>
}
func Render(source string, language string) (string, error) {
key := CodeKey{Source: source, Language: language}
cacheMu.RLock()
rendered, ready := cache[key]
cacheMu.RUnlock()
if ready {
return rendered, nil
}
cacheMu.Lock()
defer cacheMu.Unlock()
if rendered, ready := cache[key]; ready {
return rendered, nil
}
lexer := lexers.Get(language)
if lexer == nil {
lexer = lexers.Fallback
}
tokens, err := lexer.Tokenise(nil, source)
if err != nil {
return "", err
}
if language == "typescript" || language == "ts" {
items := tokens.Tokens()
for index, item := range items {
if item.Type != chroma.NameOther {
continue
}
next := index + 1
for next < len(items) && strings.TrimSpace(items[next].Value) == "" {
next++
}
if next < len(items) && items[next].Value == "(" {
items[index].Type = chroma.NameFunction
} else if next + 1 < len(items) && items[next].Value == "<" && items[next+1].Type == chroma.NameTag {
// Chroma marks TypeScript generic types as NameTag.
items[index].Type = chroma.NameFunction
}
}
tokens = chroma.Literator(items...)
}
var output bytes.Buffer
formatter := chromahtml.New(chromahtml.WithClasses(true), chromahtml.WithLineNumbers(true))
if err := formatter.Format(&output, styles.Get("github"), tokens); err != nil {
return "", err
}
rendered = output.String()
cache[key] = rendered
return rendered, nil
}
// Publish styles once per module, before the browser requests them.
func WriteStylesheet(css string) (string, error) {
name := fmt.Sprintf("%x.css", sha256.Sum256([]byte(css)))
directory := filepath.Join("public", "generated", "code")
if err := os.MkdirAll(directory, 0755); err != nil {
return "", err
}
file, err := os.CreateTemp(directory, ".styles-*")
if err != nil {
return "", err
}
defer os.Remove(file.Name())
defer file.Close()
if _, err := file.WriteString(css); err != nil {
return "", err
}
if err := file.Chmod(0644); err != nil {
return "", err
}
if err := file.Close(); err != nil {
return "", err
}
if err := os.Rename(file.Name(), filepath.Join(directory, name)); err != nil {
return "", err
}
return "/generated/code/" + name, nil
}
Live exampleGOX / Go