@@ -10,6 +10,7 @@ import (
10
10
"bytes"
11
11
"fmt"
12
12
gohtml "html"
13
+ "io"
13
14
"path/filepath"
14
15
"strings"
15
16
"sync"
@@ -26,7 +27,7 @@ import (
26
27
)
27
28
28
29
// don't index files larger than this many bytes for performance purposes
29
- const sizeLimit = 1000000
30
+ const sizeLimit = 1024 * 1024
30
31
31
32
var (
32
33
// For custom user mapping
@@ -46,7 +47,6 @@ func NewContext() {
46
47
highlightMapping [keys [i ].Name ()] = keys [i ].Value ()
47
48
}
48
49
}
49
-
50
50
// The size 512 is simply a conservative rule of thumb
51
51
c , err := lru .New2Q (512 )
52
52
if err != nil {
@@ -60,7 +60,7 @@ func NewContext() {
60
60
func Code (fileName , language , code string ) string {
61
61
NewContext ()
62
62
63
- // diff view newline will be passed as empty, change to literal \n so it can be copied
63
+ // diff view newline will be passed as empty, change to literal '\n' so it can be copied
64
64
// preserve literal newline in blame view
65
65
if code == "" || code == "\n " {
66
66
return "\n "
@@ -128,36 +128,32 @@ func CodeFromLexer(lexer chroma.Lexer, code string) string {
128
128
return code
129
129
}
130
130
131
- htmlw .Flush ()
131
+ _ = htmlw .Flush ()
132
132
// Chroma will add newlines for certain lexers in order to highlight them properly
133
- // Once highlighted, strip them here so they don't cause copy/paste trouble in HTML output
133
+ // Once highlighted, strip them here, so they don't cause copy/paste trouble in HTML output
134
134
return strings .TrimSuffix (htmlbuf .String (), "\n " )
135
135
}
136
136
137
- // File returns a slice of chroma syntax highlighted lines of code
138
- func File (numLines int , fileName , language string , code []byte ) []string {
137
+ // File returns a slice of chroma syntax highlighted HTML lines of code
138
+ func File (fileName , language string , code []byte ) ( []string , error ) {
139
139
NewContext ()
140
140
141
141
if len (code ) > sizeLimit {
142
- return plainText ( string ( code ), numLines )
142
+ return PlainText ( code ), nil
143
143
}
144
+
144
145
formatter := html .New (html .WithClasses (true ),
145
146
html .WithLineNumbers (false ),
146
147
html .PreventSurroundingPre (true ),
147
148
)
148
149
149
- if formatter == nil {
150
- log .Error ("Couldn't create chroma formatter" )
151
- return plainText (string (code ), numLines )
152
- }
153
-
154
- htmlbuf := bytes.Buffer {}
155
- htmlw := bufio .NewWriter (& htmlbuf )
150
+ htmlBuf := bytes.Buffer {}
151
+ htmlWriter := bufio .NewWriter (& htmlBuf )
156
152
157
153
var lexer chroma.Lexer
158
154
159
155
// provided language overrides everything
160
- if len ( language ) > 0 {
156
+ if language != "" {
161
157
lexer = lexers .Get (language )
162
158
}
163
159
@@ -168,9 +164,9 @@ func File(numLines int, fileName, language string, code []byte) []string {
168
164
}
169
165
170
166
if lexer == nil {
171
- language := analyze .GetCodeLanguage (fileName , code )
167
+ guessLanguage := analyze .GetCodeLanguage (fileName , code )
172
168
173
- lexer = lexers .Get (language )
169
+ lexer = lexers .Get (guessLanguage )
174
170
if lexer == nil {
175
171
lexer = lexers .Match (fileName )
176
172
if lexer == nil {
@@ -181,54 +177,43 @@ func File(numLines int, fileName, language string, code []byte) []string {
181
177
182
178
iterator , err := lexer .Tokenise (nil , string (code ))
183
179
if err != nil {
184
- log .Error ("Can't tokenize code: %v" , err )
185
- return plainText (string (code ), numLines )
180
+ return nil , fmt .Errorf ("can't tokenize code: %w" , err )
186
181
}
187
182
188
- err = formatter .Format (htmlw , styles .GitHub , iterator )
183
+ err = formatter .Format (htmlWriter , styles .GitHub , iterator )
189
184
if err != nil {
190
- log .Error ("Can't format code: %v" , err )
191
- return plainText (string (code ), numLines )
185
+ return nil , fmt .Errorf ("can't format code: %w" , err )
192
186
}
193
187
194
- htmlw .Flush ()
195
- finalNewLine := false
196
- if len (code ) > 0 {
197
- finalNewLine = code [len (code )- 1 ] == '\n'
198
- }
188
+ _ = htmlWriter .Flush ()
199
189
200
- m := make ([]string , 0 , numLines )
201
- for _ , v := range strings .SplitN (htmlbuf .String (), "\n " , numLines ) {
202
- content := v
203
- // need to keep lines that are only \n so copy/paste works properly in browser
204
- if content == "" {
205
- content = "\n "
206
- } else if content == `</span><span class="w">` {
207
- content += "\n </span>"
208
- } else if content == `</span></span><span class="line"><span class="cl">` {
209
- content += "\n "
210
- }
211
- content = strings .TrimSuffix (content , `<span class="w">` )
212
- content = strings .TrimPrefix (content , `</span>` )
213
- m = append (m , content )
190
+ // at the moment, Chroma generates stable output `<span class="line"><span class="cl">...\n</span></span>` for each line
191
+ htmlStr := htmlBuf .String ()
192
+ lines := strings .Split (htmlStr , `<span class="line"><span class="cl">` )
193
+ m := make ([]string , 0 , len (lines ))
194
+ for i := 1 ; i < len (lines ); i ++ {
195
+ line := lines [i ]
196
+ line = strings .TrimSuffix (line , "</span></span>" )
197
+ m = append (m , line )
214
198
}
215
- if finalNewLine {
216
- m = append (m , "<span class=\" w\" >\n </span>" )
217
- }
218
-
219
- return m
199
+ return m , nil
220
200
}
221
201
222
- // return unhiglighted map
223
- func plainText (code string , numLines int ) []string {
224
- m := make ([]string , 0 , numLines )
225
- for _ , v := range strings .SplitN (code , "\n " , numLines ) {
226
- content := v
227
- // need to keep lines that are only \n so copy/paste works properly in browser
228
- if content == "" {
229
- content = "\n "
202
+ // PlainText returns non-highlighted HTML for code
203
+ func PlainText (code []byte ) []string {
204
+ r := bufio .NewReader (bytes .NewReader (code ))
205
+ m := make ([]string , 0 , bytes .Count (code , []byte {'\n' })+ 1 )
206
+ for {
207
+ content , err := r .ReadString ('\n' )
208
+ if err != nil && err != io .EOF {
209
+ log .Error ("failed to read string from buffer: %v" , err )
210
+ break
211
+ }
212
+ if content == "" && err == io .EOF {
213
+ break
230
214
}
231
- m = append (m , gohtml .EscapeString (content ))
215
+ s := gohtml .EscapeString (content )
216
+ m = append (m , s )
232
217
}
233
218
return m
234
219
}
0 commit comments