Skip to content

Commit 465a27c

Browse files
authored
cmd: --fail earlier without reading entire input files (#502)
1 parent e87e5b2 commit 465a27c

File tree

1 file changed

+75
-14
lines changed

1 file changed

+75
-14
lines changed

Diff for: cmd/chroma/main.go

+75-14
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"bufio"
5+
"errors"
56
"fmt"
67
"io"
78
"io/ioutil"
@@ -82,6 +83,54 @@ type nopFlushableWriter struct{ io.Writer }
8283

8384
func (n *nopFlushableWriter) Flush() error { return nil }
8485

86+
// prepareLenient prepares contents and lexer for input, using fallback lexer if no specific one is available for it.
87+
func prepareLenient(ctx *kong.Context, r io.Reader, filename string) (string, chroma.Lexer) {
88+
data, err := ioutil.ReadAll(r)
89+
ctx.FatalIfErrorf(err)
90+
91+
contents := string(data)
92+
lexer := selexer(filename, contents)
93+
if lexer == nil {
94+
lexer = lexers.Fallback
95+
}
96+
97+
return contents, lexer
98+
}
99+
100+
// prepareSpecific prepares contents and lexer for input, exiting if there is no specific lexer available for it.
101+
// Input is consumed only up to peekSize for lexer selection. With fullSize -1, consume r until EOF.
102+
func prepareSpecific(ctx *kong.Context, r io.Reader, filename string, peekSize, fullSize int) (string, chroma.Lexer) {
103+
data := make([]byte, peekSize)
104+
n, err := io.ReadFull(r, data)
105+
if err != nil && !errors.Is(err, io.ErrUnexpectedEOF) {
106+
ctx.FatalIfErrorf(err)
107+
}
108+
109+
lexer := selexer(filename, string(data[:n]))
110+
if lexer == nil {
111+
ctx.Exit(1)
112+
}
113+
114+
if n < peekSize {
115+
return string(data[:n]), lexer
116+
}
117+
var ndata []byte
118+
if fullSize == -1 {
119+
rest, err := io.ReadAll(r)
120+
ctx.FatalIfErrorf(err)
121+
ndata = make([]byte, n + len(rest))
122+
copy(ndata, data[:n])
123+
copy(ndata[n:], rest)
124+
} else {
125+
ndata = make([]byte, fullSize)
126+
copy(ndata, data[:n])
127+
_, err = io.ReadFull(r, ndata[n:])
128+
ctx.FatalIfErrorf(err)
129+
}
130+
131+
return string(ndata), lexer
132+
}
133+
85134
func main() {
86135
ctx := kong.Parse(&cli, kong.Description(description), kong.Vars{
87136
"version": fmt.Sprintf("%s-%s-%s", version, commit, date),
@@ -160,18 +209,37 @@ func main() {
160209
configureHTMLFormatter(ctx)
161210
}
162211
if len(cli.Files) == 0 {
163-
contents, err := ioutil.ReadAll(os.Stdin)
164-
ctx.FatalIfErrorf(err)
165-
format(ctx, w, style, lex(ctx, cli.Filename, string(contents)))
212+
var contents string
213+
var lexer chroma.Lexer
214+
if cli.Fail {
215+
contents, lexer = prepareSpecific(ctx, os.Stdin, cli.Filename, 1024, -1)
216+
} else {
217+
contents, lexer = prepareLenient(ctx, os.Stdin, cli.Filename)
218+
}
219+
format(ctx, w, style, lex(ctx, lexer, contents))
166220
} else {
167221
for _, filename := range cli.Files {
168-
contents, err := ioutil.ReadFile(filename)
222+
file, err := os.Open(filename)
169223
ctx.FatalIfErrorf(err)
224+
170225
if cli.Check {
171-
check(filename, lex(ctx, filename, string(contents)))
226+
contents, lexer := prepareLenient(ctx, file, filename)
227+
check(filename, lex(ctx, lexer, contents))
172228
} else {
173-
format(ctx, w, style, lex(ctx, filename, string(contents)))
229+
var contents string
230+
var lexer chroma.Lexer
231+
if cli.Fail {
232+
fi, err := file.Stat()
233+
ctx.FatalIfErrorf(err)
234+
contents, lexer = prepareSpecific(ctx, file, filename, 1024, int(fi.Size()))
235+
} else {
236+
contents, lexer = prepareLenient(ctx, file, filename)
237+
}
238+
format(ctx, w, style, lex(ctx, lexer, contents))
174239
}
240+
241+
err = file.Close()
242+
ctx.FatalIfErrorf(err)
175243
}
176244
}
177245
}
@@ -241,14 +309,7 @@ func listAll() {
241309
fmt.Println()
242310
}
243311

244-
func lex(ctx *kong.Context, path string, contents string) chroma.Iterator {
245-
lexer := selexer(path, contents)
246-
if lexer == nil {
247-
if cli.Fail {
248-
ctx.Exit(1)
249-
}
250-
lexer = lexers.Fallback
251-
}
312+
func lex(ctx *kong.Context, lexer chroma.Lexer, contents string) chroma.Iterator {
252313
if rel, ok := lexer.(*chroma.RegexLexer); ok {
253314
rel.Trace(cli.Trace)
254315
}

0 commit comments

Comments
 (0)