forked from alecthomas/chroma
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapi.go
More file actions
131 lines (119 loc) · 3.21 KB
/
Copy pathapi.go
File metadata and controls
131 lines (119 loc) · 3.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package styles
import (
"embed"
"io/fs"
"slices"
"strings"
"sync"
"github.com/alecthomas/chroma/v3"
)
//go:embed *.xml
var embedded embed.FS
var (
registryMu sync.Mutex
// registry holds user-registered styles plus embedded styles that have
// already been parsed. Embedded styles are parsed lazily by Lookup so
// that importing this package does not pay for parsing every style;
// see TestEmbeddedStyleNamesMatchFilenames for the invariant that makes
// the lazy filename-based lookup possible.
registry = map[string]*chroma.Style{}
)
// embeddedNames returns the lowercased names of the embedded styles, which
// by convention are also their file names.
var embeddedNames = sync.OnceValue(func() []string {
files, err := fs.ReadDir(embedded, ".")
if err != nil {
panic(err)
}
names := make([]string, 0, len(files))
for _, file := range files {
if file.IsDir() || !strings.HasSuffix(file.Name(), ".xml") {
continue
}
names = append(names, strings.TrimSuffix(file.Name(), ".xml"))
}
return names
})
// Fallback style. Reassign to change the default fallback style.
var Fallback = func() *chroma.Style {
fallback, ok := Lookup("swapoff")
if !ok {
panic(`chroma/styles: default fallback style "swapoff" is missing`)
}
return fallback
}()
// Register a chroma.Style.
func Register(style *chroma.Style) *chroma.Style {
registryMu.Lock()
defer registryMu.Unlock()
registry[strings.ToLower(style.Name)] = style
return style
}
// Names of all available styles.
func Names() []string {
registryMu.Lock()
defer registryMu.Unlock()
names := slices.Clone(embeddedNames())
for name := range registry {
if !slices.Contains(names, name) {
names = append(names, name)
}
}
slices.Sort(names)
return names
}
// Lookup a named style, returning false if not found. Embedded styles are
// parsed on first lookup.
func Lookup(name string) (*chroma.Style, bool) {
name = strings.ToLower(name)
registryMu.Lock()
defer registryMu.Unlock()
if style, ok := registry[name]; ok {
return style, true
}
f, err := embedded.Open(name + ".xml")
if err != nil {
return nil, false
}
defer f.Close()
style, err := chroma.NewXMLStyle(f)
if err != nil {
panic(err)
}
registry[name] = style
return style, true
}
// Get named style, or Fallback.
func Get(name string) *chroma.Style {
if style, ok := Lookup(name); ok {
return style
}
return Fallback
}
// GetForMode returns the named style if it already matches mode, otherwise its
// registered counterpart if one exists and matches mode. If neither matches,
// the originally-requested style is returned (or Fallback if the name is
// unknown), so callers always get something usable.
func GetForMode(name string, mode chroma.Mode) *chroma.Style {
style := Get(name)
if style.Mode() == mode {
return style
}
if style.Counterpart == "" {
return style
}
counterpart, ok := Lookup(style.Counterpart)
if !ok || counterpart.Mode() != mode {
return style
}
return counterpart
}
// RegisterPair links two styles as light/dark counterparts of each other.
//
// Both styles are also registered if they are not already present.
func RegisterPair(a, b *chroma.Style) {
Register(a)
Register(b)
a.Counterpart = strings.ToLower(b.Name)
b.Counterpart = strings.ToLower(a.Name)
}