@@ -10,6 +10,7 @@ import (
1010 "bytes"
1111 "fmt"
1212 gohtml "html"
13+ "io"
1314 "path/filepath"
1415 "strings"
1516 "sync"
@@ -26,7 +27,7 @@ import (
2627)
2728
2829// don't index files larger than this many bytes for performance purposes
29- const sizeLimit = 1000000
30+ const sizeLimit = 1024 * 1024
3031
3132var (
3233 // For custom user mapping
@@ -46,7 +47,6 @@ func NewContext() {
4647 highlightMapping [keys [i ].Name ()] = keys [i ].Value ()
4748 }
4849 }
49-
5050 // The size 512 is simply a conservative rule of thumb
5151 c , err := lru .New2Q (512 )
5252 if err != nil {
@@ -60,7 +60,7 @@ func NewContext() {
6060func Code (fileName , language , code string ) string {
6161 NewContext ()
6262
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
6464 // preserve literal newline in blame view
6565 if code == "" || code == "\n " {
6666 return "\n "
@@ -128,36 +128,32 @@ func CodeFromLexer(lexer chroma.Lexer, code string) string {
128128 return code
129129 }
130130
131- htmlw .Flush ()
131+ _ = htmlw .Flush ()
132132 // 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
134134 return strings .TrimSuffix (htmlbuf .String (), "\n " )
135135}
136136
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 ) {
139139 NewContext ()
140140
141141 if len (code ) > sizeLimit {
142- return plainText ( string ( code ), numLines )
142+ return PlainText ( code ), nil
143143 }
144+
144145 formatter := html .New (html .WithClasses (true ),
145146 html .WithLineNumbers (false ),
146147 html .PreventSurroundingPre (true ),
147148 )
148149
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 )
156152
157153 var lexer chroma.Lexer
158154
159155 // provided language overrides everything
160- if len ( language ) > 0 {
156+ if language != "" {
161157 lexer = lexers .Get (language )
162158 }
163159
@@ -168,9 +164,9 @@ func File(numLines int, fileName, language string, code []byte) []string {
168164 }
169165
170166 if lexer == nil {
171- language := analyze .GetCodeLanguage (fileName , code )
167+ guessLanguage := analyze .GetCodeLanguage (fileName , code )
172168
173- lexer = lexers .Get (language )
169+ lexer = lexers .Get (guessLanguage )
174170 if lexer == nil {
175171 lexer = lexers .Match (fileName )
176172 if lexer == nil {
@@ -181,54 +177,43 @@ func File(numLines int, fileName, language string, code []byte) []string {
181177
182178 iterator , err := lexer .Tokenise (nil , string (code ))
183179 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 )
186181 }
187182
188- err = formatter .Format (htmlw , styles .GitHub , iterator )
183+ err = formatter .Format (htmlWriter , styles .GitHub , iterator )
189184 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 )
192186 }
193187
194- htmlw .Flush ()
195- finalNewLine := false
196- if len (code ) > 0 {
197- finalNewLine = code [len (code )- 1 ] == '\n'
198- }
188+ _ = htmlWriter .Flush ()
199189
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 )
214198 }
215- if finalNewLine {
216- m = append (m , "<span class=\" w\" >\n </span>" )
217- }
218-
219- return m
199+ return m , nil
220200}
221201
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
230214 }
231- m = append (m , gohtml .EscapeString (content ))
215+ s := gohtml .EscapeString (content )
216+ m = append (m , s )
232217 }
233218 return m
234219}
0 commit comments