highlight.go 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. package common
  2. import (
  3. "bytes"
  4. "image/color"
  5. "github.com/alecthomas/chroma/v2"
  6. "github.com/alecthomas/chroma/v2/formatters"
  7. "github.com/alecthomas/chroma/v2/lexers"
  8. chromastyles "github.com/alecthomas/chroma/v2/styles"
  9. "github.com/charmbracelet/crush/internal/ui/styles"
  10. )
  11. // SyntaxHighlight applies syntax highlighting to the given source code based
  12. // on the file name and background color. It returns the highlighted code as a
  13. // string.
  14. func SyntaxHighlight(st *styles.Styles, source, fileName string, bg color.Color) (string, error) {
  15. // Determine the language lexer to use
  16. l := lexers.Match(fileName)
  17. if l == nil {
  18. l = lexers.Analyse(source)
  19. }
  20. if l == nil {
  21. l = lexers.Fallback
  22. }
  23. l = chroma.Coalesce(l)
  24. // Get the formatter
  25. f := formatters.Get("terminal16m")
  26. if f == nil {
  27. f = formatters.Fallback
  28. }
  29. style := chroma.MustNewStyle("crush", st.ChromaTheme())
  30. // Modify the style to use the provided background
  31. s, err := style.Builder().Transform(
  32. func(t chroma.StyleEntry) chroma.StyleEntry {
  33. r, g, b, _ := bg.RGBA()
  34. t.Background = chroma.NewColour(uint8(r>>8), uint8(g>>8), uint8(b>>8))
  35. return t
  36. },
  37. ).Build()
  38. if err != nil {
  39. s = chromastyles.Fallback
  40. }
  41. // Tokenize and format
  42. it, err := l.Tokenise(nil, source)
  43. if err != nil {
  44. return "", err
  45. }
  46. var buf bytes.Buffer
  47. err = f.Format(&buf, s, it)
  48. return buf.String(), err
  49. }