...

Source file src/github.com/alecthomas/chroma/v2/registry.go

Documentation: github.com/alecthomas/chroma/v2

     1  package chroma
     2  
     3  import (
     4  	"path/filepath"
     5  	"sort"
     6  	"strings"
     7  )
     8  
     9  var (
    10  	ignoredSuffixes = [...]string{
    11  		// Editor backups
    12  		"~", ".bak", ".old", ".orig",
    13  		// Debian and derivatives apt/dpkg/ucf backups
    14  		".dpkg-dist", ".dpkg-old", ".ucf-dist", ".ucf-new", ".ucf-old",
    15  		// Red Hat and derivatives rpm backups
    16  		".rpmnew", ".rpmorig", ".rpmsave",
    17  		// Build system input/template files
    18  		".in",
    19  	}
    20  )
    21  
    22  // LexerRegistry is a registry of Lexers.
    23  type LexerRegistry struct {
    24  	Lexers  Lexers
    25  	byName  map[string]Lexer
    26  	byAlias map[string]Lexer
    27  }
    28  
    29  // NewLexerRegistry creates a new LexerRegistry of Lexers.
    30  func NewLexerRegistry() *LexerRegistry {
    31  	return &LexerRegistry{
    32  		byName:  map[string]Lexer{},
    33  		byAlias: map[string]Lexer{},
    34  	}
    35  }
    36  
    37  // Names of all lexers, optionally including aliases.
    38  func (l *LexerRegistry) Names(withAliases bool) []string {
    39  	out := []string{}
    40  	for _, lexer := range l.Lexers {
    41  		config := lexer.Config()
    42  		out = append(out, config.Name)
    43  		if withAliases {
    44  			out = append(out, config.Aliases...)
    45  		}
    46  	}
    47  	sort.Strings(out)
    48  	return out
    49  }
    50  
    51  // Get a Lexer by name, alias or file extension.
    52  func (l *LexerRegistry) Get(name string) Lexer {
    53  	if lexer := l.byName[name]; lexer != nil {
    54  		return lexer
    55  	}
    56  	if lexer := l.byAlias[name]; lexer != nil {
    57  		return lexer
    58  	}
    59  	if lexer := l.byName[strings.ToLower(name)]; lexer != nil {
    60  		return lexer
    61  	}
    62  	if lexer := l.byAlias[strings.ToLower(name)]; lexer != nil {
    63  		return lexer
    64  	}
    65  
    66  	candidates := PrioritisedLexers{}
    67  	// Try file extension.
    68  	if lexer := l.Match("filename." + name); lexer != nil {
    69  		candidates = append(candidates, lexer)
    70  	}
    71  	// Try exact filename.
    72  	if lexer := l.Match(name); lexer != nil {
    73  		candidates = append(candidates, lexer)
    74  	}
    75  	if len(candidates) == 0 {
    76  		return nil
    77  	}
    78  	sort.Sort(candidates)
    79  	return candidates[0]
    80  }
    81  
    82  // MatchMimeType attempts to find a lexer for the given MIME type.
    83  func (l *LexerRegistry) MatchMimeType(mimeType string) Lexer {
    84  	matched := PrioritisedLexers{}
    85  	for _, l := range l.Lexers {
    86  		for _, lmt := range l.Config().MimeTypes {
    87  			if mimeType == lmt {
    88  				matched = append(matched, l)
    89  			}
    90  		}
    91  	}
    92  	if len(matched) != 0 {
    93  		sort.Sort(matched)
    94  		return matched[0]
    95  	}
    96  	return nil
    97  }
    98  
    99  // Match returns the first lexer matching filename.
   100  func (l *LexerRegistry) Match(filename string) Lexer {
   101  	filename = filepath.Base(filename)
   102  	matched := PrioritisedLexers{}
   103  	// First, try primary filename matches.
   104  	for _, lexer := range l.Lexers {
   105  		config := lexer.Config()
   106  		for _, glob := range config.Filenames {
   107  			ok, err := filepath.Match(glob, filename)
   108  			if err != nil { // nolint
   109  				panic(err)
   110  			} else if ok {
   111  				matched = append(matched, lexer)
   112  			} else {
   113  				for _, suf := range &ignoredSuffixes {
   114  					ok, err := filepath.Match(glob+suf, filename)
   115  					if err != nil {
   116  						panic(err)
   117  					} else if ok {
   118  						matched = append(matched, lexer)
   119  						break
   120  					}
   121  				}
   122  			}
   123  		}
   124  	}
   125  	if len(matched) > 0 {
   126  		sort.Sort(matched)
   127  		return matched[0]
   128  	}
   129  	matched = nil
   130  	// Next, try filename aliases.
   131  	for _, lexer := range l.Lexers {
   132  		config := lexer.Config()
   133  		for _, glob := range config.AliasFilenames {
   134  			ok, err := filepath.Match(glob, filename)
   135  			if err != nil { // nolint
   136  				panic(err)
   137  			} else if ok {
   138  				matched = append(matched, lexer)
   139  			} else {
   140  				for _, suf := range &ignoredSuffixes {
   141  					ok, err := filepath.Match(glob+suf, filename)
   142  					if err != nil {
   143  						panic(err)
   144  					} else if ok {
   145  						matched = append(matched, lexer)
   146  						break
   147  					}
   148  				}
   149  			}
   150  		}
   151  	}
   152  	if len(matched) > 0 {
   153  		sort.Sort(matched)
   154  		return matched[0]
   155  	}
   156  	return nil
   157  }
   158  
   159  // Analyse text content and return the "best" lexer..
   160  func (l *LexerRegistry) Analyse(text string) Lexer {
   161  	var picked Lexer
   162  	highest := float32(0.0)
   163  	for _, lexer := range l.Lexers {
   164  		if analyser, ok := lexer.(Analyser); ok {
   165  			weight := analyser.AnalyseText(text)
   166  			if weight > highest {
   167  				picked = lexer
   168  				highest = weight
   169  			}
   170  		}
   171  	}
   172  	return picked
   173  }
   174  
   175  // Register a Lexer with the LexerRegistry.
   176  func (l *LexerRegistry) Register(lexer Lexer) Lexer {
   177  	lexer.SetRegistry(l)
   178  	config := lexer.Config()
   179  	l.byName[config.Name] = lexer
   180  	l.byName[strings.ToLower(config.Name)] = lexer
   181  	for _, alias := range config.Aliases {
   182  		l.byAlias[alias] = lexer
   183  		l.byAlias[strings.ToLower(alias)] = lexer
   184  	}
   185  	l.Lexers = append(l.Lexers, lexer)
   186  	return lexer
   187  }
   188  

View as plain text