@@ -259,15 +259,67 @@ func Print(s *scanner.Scanner, w io.Writer, p Printer, m mode.Mode) error {
259259 }
260260 }
261261 inComment := false
262+ isCFamily := m == mode .C || m == mode .Cpp || m == mode .ObjC || m == mode .Arduino
263+ inPreproc := false // true after # in C-family, until the directive word
264+ inInclude := false // true after #include, expecting <...>
265+ inAngle := false // true inside <...> of an #include path
266+ if isCFamily {
267+ s .Mode &^= scanner .ScanChars
268+ }
262269 for tok := s .Scan (); tok != scanner .EOF ; tok = s .Scan () {
263270 tokText := s .TokenText ()
264- if err := p .Print (w , tokenKind (tok , tokText , & inComment , m ), tokText ); err != nil {
271+ kind := tokenKind (tok , tokText , & inComment , m )
272+ if isCFamily {
273+ switch {
274+ case tok == '\n' :
275+ inPreproc = false
276+ inInclude = false
277+ inAngle = false
278+ case tok == '#' && ! inComment :
279+ inPreproc = true
280+ kind = Literal
281+ case inPreproc && tok == scanner .Ident :
282+ kind = Literal
283+ inPreproc = false
284+ if tokText == "include" {
285+ inInclude = true
286+ }
287+ case inInclude && unicode .IsSpace (tok ):
288+ // skip whitespace after #include, but keep inInclude true
289+ case inInclude && tok == '<' :
290+ inAngle = true
291+ kind = AngleBracket
292+ case inInclude :
293+ // Some other token after #include, reset inInclude
294+ inInclude = false
295+ case inAngle :
296+ if tok == '>' {
297+ inAngle = false
298+ inInclude = false
299+ }
300+ kind = AngleBracket
301+ }
302+ }
303+ if err := p .Print (w , kind , tokText ); err != nil {
265304 return err
266305 }
267306 }
268307 return nil
269308}
270309
310+ // AsText returns src highlighted for mode m, using the editor's theme.
311+ func (e * Editor ) AsText (src []byte , m mode.Mode , options ... Option ) ([]byte , error ) {
312+ cfg := * e .Theme .TextConfig ()
313+ for _ , opt := range options {
314+ opt (& cfg )
315+ }
316+ var buf bytes.Buffer
317+ if err := Print (NewScanner (src ), & buf , TextPrinter (cfg ), m ); err != nil {
318+ return nil , err
319+ }
320+ return buf .Bytes (), nil
321+ }
322+
271323// AsText returns src highlighted for mode m, applying options to TextConfig.
272324func AsText (src []byte , m mode.Mode , options ... Option ) ([]byte , error ) {
273325 cfg := DefaultTextConfig
@@ -488,7 +540,7 @@ func (e *Editor) WriteLines(c *vt.Canvas, fromline, toline LineIndex, cx, cy uin
488540 if e .syntaxHighlight && ! envNoColor {
489541 // Output a syntax highlighted line. Escape any tags in the input line.
490542 // textWithTags must be unescaped if there is not an error.
491- if textWithTags , err = AsText ([]byte (escapeFunction (line )), e .mode ); err != nil {
543+ if textWithTags , err = e . AsText ([]byte (escapeFunction (line )), e .mode ); err != nil {
492544 // Only output the line up to the width of the canvas
493545 screenLine = e .ChopLine (line , int (cw ))
494546 // TODO: Check if just "fmt.Print" works here, for several terminal emulators
@@ -582,7 +634,7 @@ func (e *Editor) WriteLines(c *vt.Canvas, fromline, toline LineIndex, cx, cy uin
582634 // Inline Lua comment, e.g. "local x = 42 -- set x to 42"
583635 parts := strings .SplitN (line , "--" , 2 )
584636 // Highlight the code portion before the comment
585- if newTextWithTags , err = AsText ([]byte (escapeFunction (parts [0 ])), e .mode ); err != nil {
637+ if newTextWithTags , err = e . AsText ([]byte (escapeFunction (parts [0 ])), e .mode ); err != nil {
586638 coloredString = unEscapeFunction (tout .DarkTags (string (textWithTags )))
587639 } else {
588640 // Append the comment portion highlighted as a comment
@@ -637,14 +689,14 @@ func (e *Editor) WriteLines(c *vt.Canvas, fromline, toline LineIndex, cx, cy uin
637689 coloredString = unEscapeFunction (e .MultiLineComment .Start (line ))
638690 } else if doubleSemiCount == 1 {
639691 parts = strings .SplitN (line , ";;" , 2 )
640- if newTextWithTags , err = AsText ([]byte (escapeFunction (parts [0 ])), e .mode ); err != nil {
692+ if newTextWithTags , err = e . AsText ([]byte (escapeFunction (parts [0 ])), e .mode ); err != nil {
641693 coloredString = unEscapeFunction (tout .DarkTags (string (textWithTags )))
642694 } else {
643695 coloredString = unEscapeFunction (tout .DarkTags (string (newTextWithTags )) + e .MultiLineComment .Get (";;" + parts [1 ]))
644696 }
645697 } else if strings .Count (trimmedLine , ";" ) == 1 {
646698 parts = strings .SplitN (line , ";" , 2 )
647- if newTextWithTags , err = AsText ([]byte (escapeFunction (parts [0 ])), e .mode ); err != nil {
699+ if newTextWithTags , err = e . AsText ([]byte (escapeFunction (parts [0 ])), e .mode ); err != nil {
648700 coloredString = unEscapeFunction (tout .DarkTags (string (textWithTags )))
649701 } else {
650702 coloredString = unEscapeFunction (tout .DarkTags (string (newTextWithTags )) + e .MultiLineComment .Start (";" + parts [1 ]))
@@ -663,7 +715,7 @@ func (e *Editor) WriteLines(c *vt.Canvas, fromline, toline LineIndex, cx, cy uin
663715 coloredString = unEscapeFunction (e .MultiLineComment .Start (line ))
664716 } else {
665717 parts = strings .SplitN (line , "\" " , 2 )
666- if newTextWithTags , err = AsText ([]byte (escapeFunction (parts [0 ])), e .mode ); err != nil {
718+ if newTextWithTags , err = e . AsText ([]byte (escapeFunction (parts [0 ])), e .mode ); err != nil {
667719 coloredString = unEscapeFunction (tout .DarkTags (string (textWithTags )))
668720 } else {
669721 coloredString = unEscapeFunction (tout .DarkTags (string (newTextWithTags )) + e .MultiLineComment .Start ("\" " + parts [1 ]))
@@ -745,7 +797,7 @@ func (e *Editor) WriteLines(c *vt.Canvas, fromline, toline LineIndex, cx, cy uin
745797 parts = strings .SplitN (line , otherCommentMarker , 2 )
746798 commentMarkerString = tout .DarkTags (parts [0 ] + "<" + e .Dollar + ">" + otherCommentMarker + "<off>" )
747799 theRestString = tout .DarkTags (parts [1 ])
748- if theRestWithTags , err = AsText ([]byte (escapeFunction (parts [1 ])), e .mode ); err == nil {
800+ if theRestWithTags , err = e . AsText ([]byte (escapeFunction (parts [1 ])), e .mode ); err == nil {
749801 theRestString = tout .DarkTags (string (theRestWithTags ))
750802 }
751803 coloredString = unEscapeFunction (commentMarkerString + theRestString )
0 commit comments