cheat/vendor/github.com/alecthomas/chroma/v2/registry.go

211 lines
4.7 KiB
Go

package chroma
import (
"path/filepath"
"sort"
"strings"
)
var (
ignoredSuffixes = [...]string{
// Editor backups
"~", ".bak", ".old", ".orig",
// Debian and derivatives apt/dpkg/ucf backups
".dpkg-dist", ".dpkg-old", ".ucf-dist", ".ucf-new", ".ucf-old",
// Red Hat and derivatives rpm backups
".rpmnew", ".rpmorig", ".rpmsave",
// Build system input/template files
".in",
}
)
// LexerRegistry is a registry of Lexers.
type LexerRegistry struct {
Lexers Lexers
byName map[string]Lexer
byAlias map[string]Lexer
}
// NewLexerRegistry creates a new LexerRegistry of Lexers.
func NewLexerRegistry() *LexerRegistry {
return &LexerRegistry{
byName: map[string]Lexer{},
byAlias: map[string]Lexer{},
}
}
// Names of all lexers, optionally including aliases.
func (l *LexerRegistry) Names(withAliases bool) []string {
out := []string{}
for _, lexer := range l.Lexers {
config := lexer.Config()
out = append(out, config.Name)
if withAliases {
out = append(out, config.Aliases...)
}
}
sort.Strings(out)
return out
}
// Get a Lexer by name, alias or file extension.
func (l *LexerRegistry) Get(name string) Lexer {
if lexer := l.byName[name]; lexer != nil {
return lexer
}
if lexer := l.byAlias[name]; lexer != nil {
return lexer
}
if lexer := l.byName[strings.ToLower(name)]; lexer != nil {
return lexer
}
if lexer := l.byAlias[strings.ToLower(name)]; lexer != nil {
return lexer
}
candidates := PrioritisedLexers{}
// Try file extension.
if lexer := l.Match("filename." + name); lexer != nil {
candidates = append(candidates, lexer)
}
// Try exact filename.
if lexer := l.Match(name); lexer != nil {
candidates = append(candidates, lexer)
}
if len(candidates) == 0 {
return nil
}
sort.Sort(candidates)
return candidates[0]
}
// MatchMimeType attempts to find a lexer for the given MIME type.
func (l *LexerRegistry) MatchMimeType(mimeType string) Lexer {
matched := PrioritisedLexers{}
for _, l := range l.Lexers {
for _, lmt := range l.Config().MimeTypes {
if mimeType == lmt {
matched = append(matched, l)
}
}
}
if len(matched) != 0 {
sort.Sort(matched)
return matched[0]
}
return nil
}
// Match returns the first lexer matching filename.
//
// Note that this iterates over all file patterns in all lexers, so is not fast.
func (l *LexerRegistry) Match(filename string) Lexer {
filename = filepath.Base(filename)
matched := PrioritisedLexers{}
// First, try primary filename matches.
for _, lexer := range l.Lexers {
config := lexer.Config()
for _, glob := range config.Filenames {
ok, err := filepath.Match(glob, filename)
if err != nil { // nolint
panic(err)
} else if ok {
matched = append(matched, lexer)
} else {
for _, suf := range &ignoredSuffixes {
ok, err := filepath.Match(glob+suf, filename)
if err != nil {
panic(err)
} else if ok {
matched = append(matched, lexer)
break
}
}
}
}
}
if len(matched) > 0 {
sort.Sort(matched)
return matched[0]
}
matched = nil
// Next, try filename aliases.
for _, lexer := range l.Lexers {
config := lexer.Config()
for _, glob := range config.AliasFilenames {
ok, err := filepath.Match(glob, filename)
if err != nil { // nolint
panic(err)
} else if ok {
matched = append(matched, lexer)
} else {
for _, suf := range &ignoredSuffixes {
ok, err := filepath.Match(glob+suf, filename)
if err != nil {
panic(err)
} else if ok {
matched = append(matched, lexer)
break
}
}
}
}
}
if len(matched) > 0 {
sort.Sort(matched)
return matched[0]
}
return nil
}
// Analyse text content and return the "best" lexer..
func (l *LexerRegistry) Analyse(text string) Lexer {
var picked Lexer
highest := float32(0.0)
for _, lexer := range l.Lexers {
if analyser, ok := lexer.(Analyser); ok {
weight := analyser.AnalyseText(text)
if weight > highest {
picked = lexer
highest = weight
}
}
}
return picked
}
// Register a Lexer with the LexerRegistry. If the lexer is already registered
// it will be replaced.
func (l *LexerRegistry) Register(lexer Lexer) Lexer {
lexer.SetRegistry(l)
config := lexer.Config()
l.byName[config.Name] = lexer
l.byName[strings.ToLower(config.Name)] = lexer
for _, alias := range config.Aliases {
l.byAlias[alias] = lexer
l.byAlias[strings.ToLower(alias)] = lexer
}
l.Lexers = add(l.Lexers, lexer)
return lexer
}
// add adds a lexer to a slice of lexers if it doesn't already exist, or if found will replace it.
func add(lexers Lexers, lexer Lexer) Lexers {
for i, val := range lexers {
if val == nil {
continue
}
if val.Config().Name == lexer.Config().Name {
lexers[i] = lexer
return lexers
}
}
return append(lexers, lexer)
}