chroma-css.go RawHistoryFolder
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3//go:build ignore
4
5// chroma-css writes internal/adapters/web/static/css/56-chroma.css: the
6// chroma token classes mapped to the --syn-* custom properties of the design
7// tokens (the Despair hues, dark and light). Colours are not in the file, so
8// the theme follows the colour scheme; only bold and italic come from chroma
9// (its "bw" style, as in the mockup).
10//
11// go run scripts/chroma-css.go > internal/adapters/web/static/css/56-chroma.css
12package main
13
14import (
15 "fmt"
16 "os"
17 "sort"
18 "strings"
19
20 "github.com/alecthomas/chroma/v2"
21 "github.com/alecthomas/chroma/v2/formatters/html"
22 "github.com/alecthomas/chroma/v2/styles"
23)
24
25// synVar maps a token type to the name of a --syn-* property, "" for none.
26func synVar(t chroma.TokenType) string {
27 switch {
28 case t == chroma.KeywordType, t == chroma.NameClass, t == chroma.NameBuiltin, t == chroma.NameBuiltinPseudo,
29 t == chroma.NameException, t == chroma.NameNamespace:
30 return "type"
31 case t.InCategory(chroma.Keyword):
32 return "keyword"
33 case t.InSubCategory(chroma.LiteralString):
34 return "string"
35 case t.InCategory(chroma.Comment):
36 return "comment"
37 case t.InSubCategory(chroma.LiteralNumber):
38 return "number"
39 case t.InSubCategory(chroma.NameFunction), t == chroma.NameDecorator:
40 return "func"
41 case t.InCategory(chroma.Punctuation), t.InCategory(chroma.Operator):
42 return "punct"
43 }
44 return ""
45}
46
47func main() {
48 // Learn the classes chroma emits, so that every one is covered.
49 var learned strings.Builder
50 if err := html.New(html.WithClasses(true)).WriteCSS(&learned, styles.Get("bw")); err != nil {
51 fmt.Fprintln(os.Stderr, err)
52 os.Exit(1)
53 }
54 types := map[string]chroma.TokenType{}
55 for t, c := range chroma.StandardTypes {
56 if c != "" && t > 0 {
57 types[c] = t
58 }
59 }
60 bw := styles.Get("bw")
61 var classes []string
62 for _, l := range strings.Split(learned.String(), "\n") {
63 i := strings.Index(l, ".chroma .")
64 if i < 0 {
65 continue
66 }
67 c := l[i+len(".chroma ."):]
68 c = c[:strings.IndexAny(c, " {")]
69 if t, ok := types[c]; ok && synVar(t) != "" {
70 classes = append(classes, c)
71 }
72 }
73 sort.Strings(classes)
74
75 fmt.Println("/* Syntax colours of the code view. Generated by scripts/chroma-css.go from")
76 fmt.Println(" chroma's token classes; the colours are the --syn-* properties of")
77 fmt.Println(" 00-tokens.css (the Despair hues, dark and light), none is defined here. */")
78 fmt.Println("@layer components {")
79 fmt.Println(" .chroma { color: var(--syn-plain); }")
80 for _, c := range classes {
81 t := types[c]
82 decl := "color: var(--syn-" + synVar(t) + ")"
83 e := bw.Get(t)
84 if e.Bold == chroma.Yes {
85 decl += "; font-weight: bold"
86 }
87 if e.Italic == chroma.Yes {
88 decl += "; font-style: italic"
89 }
90 fmt.Printf(" .chroma .%s { %s }\n", c, decl)
91 }
92 fmt.Println(" .chroma .line { display: block; }")
93 fmt.Println(`
94 /* an invisible character in code, shown instead of applied (Trojan Source) */
95 .chroma .ctl {
96 color: var(--red); font-weight: bold; font-style: normal; font-size: var(--fs-s);
97 outline: 1px solid var(--red); outline-offset: -1px; padding: 0 .25ch;
98 }
99 .img-view { margin-top: var(--lh); & img { max-width: 100%; height: auto; } }
100}`)
101}