Skip to content

Commit

Permalink
Allow custom XML lexers and styles to be loaded from the command-line.
Browse files Browse the repository at this point in the history
  • Loading branch information
alecthomas committed Mar 16, 2023
1 parent 0d91785 commit 7e30655
Showing 1 changed file with 51 additions and 20 deletions.
71 changes: 51 additions & 20 deletions cmd/chroma/main.go
Expand Up @@ -50,8 +50,8 @@ command, for Go.
Fail bool `help:"Exit silently with status 1 if no specific lexer was found."`
XML string `hidden:"" help:"Generate XML lexer definitions." type:"existingdir" placeholder:"DIR"`

Lexer string `group:"select" help:"Lexer to use when formatting." default:"autodetect" short:"l" enum:"${lexers}"`
Style string `group:"select" help:"Style to use for formatting." default:"swapoff" short:"s" enum:"${styles}"`
Lexer string `group:"select" help:"Lexer to use when formatting or path to an XML file to load." default:"autodetect" short:"l"`
Style string `group:"select" help:"Style to use for formatting or path to an XML file to load." default:"swapoff" short:"s"`

Formatter string `group:"format" help:"Formatter to use." default:"terminal" short:"f" enum:"${formatters}"`
JSON bool `group:"format" help:"Convenience flag to use JSON formatter."`
Expand Down Expand Up @@ -87,17 +87,22 @@ type nopFlushableWriter struct{ io.Writer }
func (n *nopFlushableWriter) Flush() error { return nil }

// prepareLenient prepares contents and lexer for input, using fallback lexer if no specific one is available for it.
func prepareLenient(ctx *kong.Context, r io.Reader, filename string) (string, chroma.Lexer) {
func prepareLenient(r io.Reader, filename string) (string, chroma.Lexer, error) {
data, err := ioutil.ReadAll(r)
ctx.FatalIfErrorf(err)
if err != nil {
return "", nil, err
}

contents := string(data)
lexer := selexer(filename, contents)
lexer, err := selexer(filename, contents)
if err != nil {
return "", nil, err
}
if lexer == nil {
lexer = lexers.Fallback
}

return contents, lexer
return contents, lexer, nil
}

// prepareSpecific prepares contents and lexer for input, exiting if there is no specific lexer available for it.
Expand All @@ -109,7 +114,10 @@ func prepareSpecific(ctx *kong.Context, r io.Reader, filename string, peekSize,
ctx.FatalIfErrorf(err)
}

lexer := selexer(filename, string(data[:n]))
lexer, err := selexer(filename, string(data[:n]))
if err != nil {
ctx.FatalIfErrorf(err)
}
if lexer == nil {
ctx.Exit(1)
}
Expand Down Expand Up @@ -195,7 +203,9 @@ func main() {
}

// Retrieve user-specified style, clone it, and add some overrides.
builder := styles.Get(cli.Style).Builder()
selectedStyle, err := selectStyle()
ctx.FatalIfErrorf(err)
builder := selectedStyle.Builder()
if cli.HTMLHighlightStyle != "" {
builder.Add(chroma.LineHighlight, cli.HTMLHighlightStyle)
}
Expand Down Expand Up @@ -223,7 +233,8 @@ func main() {
if cli.Fail {
contents, lexer = prepareSpecific(ctx, os.Stdin, cli.Filename, 1024, -1)
} else {
contents, lexer = prepareLenient(ctx, os.Stdin, cli.Filename)
contents, lexer, err = prepareLenient(os.Stdin, cli.Filename)
ctx.FatalIfErrorf(err)
}
format(ctx, w, style, lex(ctx, lexer, contents))
} else {
Expand All @@ -232,7 +243,8 @@ func main() {
ctx.FatalIfErrorf(err)

if cli.Check {
contents, lexer := prepareLenient(ctx, file, filename)
contents, lexer, err := prepareLenient(file, filename)
ctx.FatalIfErrorf(err)
check(filename, lex(ctx, lexer, contents))
} else {
var contents string
Expand All @@ -242,7 +254,8 @@ func main() {
ctx.FatalIfErrorf(err)
contents, lexer = prepareSpecific(ctx, file, filename, 1024, int(fi.Size()))
} else {
contents, lexer = prepareLenient(ctx, file, filename)
contents, lexer, err = prepareLenient(file, filename)
ctx.FatalIfErrorf(err)
}
format(ctx, w, style, lex(ctx, lexer, contents))
}
Expand All @@ -253,6 +266,19 @@ func main() {
}
}

func selectStyle() (*chroma.Style, error) {
style, ok := styles.Registry[cli.Style]
if ok {
return style, nil
}
r, err := os.Open(cli.Style)
if err != nil {
return nil, err
}
defer r.Close()
return chroma.NewXMLStyle(r)
}

func configureHTMLFormatter(ctx *kong.Context) {
options := []html.Option{
html.TabWidth(cli.HTMLTabWidth),
Expand Down Expand Up @@ -329,17 +355,22 @@ func lex(ctx *kong.Context, lexer chroma.Lexer, contents string) chroma.Iterator
return it
}

func selexer(path, contents string) (lexer chroma.Lexer) {
if cli.Lexer != "autodetect" {
return lexers.Get(cli.Lexer)
}
if path != "" {
lexer := lexers.Match(path)
if lexer != nil {
return lexer
func selexer(path, contents string) (lexer chroma.Lexer, err error) {
if cli.Lexer == "autodetect" {
if path != "" {
lexer := lexers.Match(path)
if lexer != nil {
return lexer, nil
}
}
return lexers.Analyse(contents), nil
}

if lexer := lexers.Get(cli.Lexer); lexer != nil {
return lexer, nil
}
return lexers.Analyse(contents)
lexerPath, err := filepath.Abs(cli.Lexer)
return chroma.NewXMLLexer(os.DirFS("/"), lexerPath)
}

func format(ctx *kong.Context, w io.Writer, style *chroma.Style, it chroma.Iterator) {
Expand Down

0 comments on commit 7e30655

Please sign in to comment.