Skip to content

Commit 9cb2777

Browse files
alecthomasclaude
andcommitted
refactor: share playground rendering between chromad and WASM
The chromad server and the WASM library duplicated the same lexer-select -> coalesce -> format pipeline and had already diverged on error handling (panic vs propagate). internal/playground.Highlight now implements it once; each binary keeps only its transport-specific marshalling. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent e4eafee commit 9cb2777

3 files changed

Lines changed: 71 additions & 75 deletions

File tree

cmd/chromad/main.go

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818

1919
"github.com/alecthomas/chroma/v3"
2020
"github.com/alecthomas/chroma/v3/formatters/html"
21+
"github.com/alecthomas/chroma/v3/internal/playground"
2122
"github.com/alecthomas/chroma/v3/lexers"
2223
"github.com/alecthomas/chroma/v3/styles"
2324
)
@@ -110,45 +111,14 @@ func renderHandler(w http.ResponseWriter, r *http.Request) {
110111
}
111112

112113
func render(req *renderRequest) (*renderResponse, error) {
113-
language := lexers.Get(req.Language)
114-
if language == nil {
115-
language = lexers.Analyse(req.Text)
116-
if language != nil {
117-
req.Language = language.Config().Name
118-
}
119-
}
120-
if language == nil {
121-
language = lexers.Fallback
122-
}
123-
124-
tokens, err := chroma.Coalesce(language).Tokenise(nil, req.Text)
125-
if err != nil {
126-
return nil, err
127-
}
128-
129-
style := styles.Get(req.Style)
130-
if style == nil {
131-
style = styles.Fallback
132-
}
133-
134-
buf := &strings.Builder{}
135-
options := []html.Option{}
136-
if req.Classes {
137-
options = append(options, html.WithClasses(true), html.Standalone(true))
138-
}
139-
formatter := html.New(options...)
140-
err = formatter.Format(buf, style, tokens)
114+
res, err := playground.Highlight(req.Text, req.Language, req.Style, req.Classes)
141115
if err != nil {
142116
return nil, err
143117
}
144-
lang := language.Config().Name
145-
if language == lexers.Fallback {
146-
lang = ""
147-
}
148118
return &renderResponse{
149-
Language: lang,
150-
HTML: buf.String(),
151-
Background: html.StyleEntryToCSS(style.Get(chroma.Background)),
119+
Language: res.Language,
120+
HTML: res.HTML,
121+
Background: res.Background,
152122
}, nil
153123
}
154124

cmd/libchromawasm/main.go

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,9 @@
44
package main
55

66
import (
7-
"strings"
87
"syscall/js"
98

10-
"github.com/alecthomas/chroma/v3"
11-
"github.com/alecthomas/chroma/v3/formatters/html"
12-
"github.com/alecthomas/chroma/v3/lexers"
13-
"github.com/alecthomas/chroma/v3/styles"
9+
"github.com/alecthomas/chroma/v3/internal/playground"
1410
)
1511

1612
func main() {
@@ -34,44 +30,13 @@ func highlight(this js.Value, args []js.Value) any {
3430
styleName := args[2].String()
3531
classes := args[3].Bool()
3632

37-
language := lexers.Get(lexer)
38-
if language == nil {
39-
language = lexers.Analyse(source)
40-
if language != nil {
41-
lexer = language.Config().Name
42-
}
43-
}
44-
if language == nil {
45-
language = lexers.Fallback
46-
}
47-
48-
tokens, err := chroma.Coalesce(language).Tokenise(nil, source)
33+
res, err := playground.Highlight(source, lexer, styleName, classes)
4934
if err != nil {
5035
panic(err)
5136
}
52-
53-
style := styles.Get(styleName)
54-
if style == nil {
55-
style = styles.Fallback
56-
}
57-
58-
buf := &strings.Builder{}
59-
options := []html.Option{}
60-
if classes {
61-
options = append(options, html.WithClasses(true), html.Standalone(true))
62-
}
63-
formatter := html.New(options...)
64-
err = formatter.Format(buf, style, tokens)
65-
if err != nil {
66-
panic(err)
67-
}
68-
lang := language.Config().Name
69-
if language == lexers.Fallback {
70-
lang = ""
71-
}
7237
return js.ValueOf(map[string]any{
73-
"html": buf.String(),
74-
"language": lang,
75-
"background": html.StyleEntryToCSS(style.Get(chroma.Background)),
38+
"html": res.HTML,
39+
"language": res.Language,
40+
"background": res.Background,
7641
})
7742
}

internal/playground/playground.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Package playground implements the highlighting pipeline shared by the
2+
// chromad server and the WASM playground library.
3+
package playground
4+
5+
import (
6+
"strings"
7+
8+
"github.com/alecthomas/chroma/v3"
9+
"github.com/alecthomas/chroma/v3/formatters/html"
10+
"github.com/alecthomas/chroma/v3/lexers"
11+
"github.com/alecthomas/chroma/v3/styles"
12+
)
13+
14+
// Result of highlighting a playground snippet.
15+
type Result struct {
16+
HTML string
17+
// Language actually used, or empty if the fallback lexer was applied.
18+
Language string
19+
Background string
20+
}
21+
22+
// Highlight source as HTML with the named lexer and style, autodetecting the
23+
// language if lexerName is unknown.
24+
func Highlight(source, lexerName, styleName string, classes bool) (*Result, error) {
25+
language := lexers.Get(lexerName)
26+
if language == nil {
27+
language = lexers.Analyse(source)
28+
}
29+
if language == nil {
30+
language = lexers.Fallback
31+
}
32+
33+
tokens, err := chroma.Coalesce(language).Tokenise(nil, source)
34+
if err != nil {
35+
return nil, err
36+
}
37+
38+
style := styles.Get(styleName)
39+
if style == nil {
40+
style = styles.Fallback
41+
}
42+
43+
options := []html.Option{}
44+
if classes {
45+
options = append(options, html.WithClasses(true), html.Standalone(true))
46+
}
47+
buf := &strings.Builder{}
48+
if err := html.New(options...).Format(buf, style, tokens); err != nil {
49+
return nil, err
50+
}
51+
52+
lang := language.Config().Name
53+
if language == lexers.Fallback {
54+
lang = ""
55+
}
56+
return &Result{
57+
HTML: buf.String(),
58+
Language: lang,
59+
Background: html.StyleEntryToCSS(style.Get(chroma.Background)),
60+
}, nil
61+
}

0 commit comments

Comments
 (0)