Detailed changes
@@ -1,16 +1,30 @@
package common
import (
+ "image/color"
+
"charm.land/glamour/v2"
+ "github.com/alecthomas/chroma/v2/formatters"
"github.com/charmbracelet/crush/internal/ui/styles"
+ "github.com/charmbracelet/crush/internal/ui/xchroma"
)
+const formatterName = "crush"
+
+func init() {
+ // NOTE: Glamour does not offer us an option to pass the formatter
+ // implementation directly. We need to register and use by name.
+ var zero color.Color
+ formatters.Register(formatterName, xchroma.Formatter(zero, nil))
+}
+
// MarkdownRenderer returns a glamour [glamour.TermRenderer] configured with
// the given styles and width.
func MarkdownRenderer(sty *styles.Styles, width int) *glamour.TermRenderer {
r, _ := glamour.NewTermRenderer(
glamour.WithStyles(sty.Markdown),
glamour.WithWordWrap(width),
+ glamour.WithChromaFormatter(formatterName),
)
return r
}
@@ -21,6 +35,7 @@ func PlainMarkdownRenderer(sty *styles.Styles, width int) *glamour.TermRenderer
r, _ := glamour.NewTermRenderer(
glamour.WithStyles(sty.PlainMarkdown),
glamour.WithWordWrap(width),
+ glamour.WithChromaFormatter(formatterName),
)
return r
}
@@ -1,57 +0,0 @@
-package diffview
-
-import (
- "fmt"
- "image/color"
- "io"
- "strings"
-
- "charm.land/lipgloss/v2"
- "github.com/alecthomas/chroma/v2"
- "github.com/charmbracelet/crush/internal/ansiext"
-)
-
-var _ chroma.Formatter = chromaFormatter{}
-
-// chromaFormatter is a custom formatter for Chroma that uses Lip Gloss for
-// foreground styling, while keeping a forced background color.
-type chromaFormatter struct {
- bgColor color.Color
-}
-
-// Format implements the chroma.Formatter interface.
-func (c chromaFormatter) Format(w io.Writer, style *chroma.Style, it chroma.Iterator) error {
- for token := it(); token != chroma.EOF; token = it() {
- value := strings.TrimRight(token.Value, "\n")
- value = ansiext.Escape(value)
-
- entry := style.Get(token.Type)
- if entry.IsZero() {
- if _, err := fmt.Fprint(w, value); err != nil {
- return err
- }
- continue
- }
-
- s := lipgloss.NewStyle().
- Background(c.bgColor)
-
- if entry.Bold == chroma.Yes {
- s = s.Bold(true)
- }
- if entry.Underline == chroma.Yes {
- s = s.Underline(true)
- }
- if entry.Italic == chroma.Yes {
- s = s.Italic(true)
- }
- if entry.Colour.IsSet() {
- s = s.Foreground(lipgloss.Color(entry.Colour.String()))
- }
-
- if _, err := fmt.Fprint(w, s.Render(value)); err != nil {
- return err
- }
- }
- return nil
-}
@@ -10,6 +10,8 @@ import (
"github.com/alecthomas/chroma/v2"
"github.com/alecthomas/chroma/v2/lexers"
"github.com/aymanbagabas/go-udiff"
+ "github.com/charmbracelet/crush/internal/ansiext"
+ "github.com/charmbracelet/crush/internal/ui/xchroma"
"github.com/charmbracelet/x/ansi"
"github.com/zeebo/xxh3"
)
@@ -768,7 +770,11 @@ func (dv *DiffView) getChromaLexer() chroma.Lexer {
}
func (dv *DiffView) getChromaFormatter(bgColor color.Color) chroma.Formatter {
- return chromaFormatter{
- bgColor: bgColor,
- }
+ return xchroma.Formatter(bgColor, processChromaValue)
+}
+
+func processChromaValue(value string) string {
+ value = strings.TrimRight(value, "\n")
+ value = ansiext.Escape(value)
+ return value
}
@@ -0,0 +1,52 @@
+package xchroma
+
+import (
+ "fmt"
+ "image/color"
+ "io"
+
+ "charm.land/lipgloss/v2"
+ "github.com/alecthomas/chroma/v2"
+)
+
+// Formatter is func that returns a custom formatter for Chroma that uses
+// Lip Gloss for foreground styling, while keeping a forced background color.
+func Formatter(bgColor color.Color, processValue func(string) string) chroma.Formatter {
+ return chroma.FormatterFunc(func(w io.Writer, style *chroma.Style, it chroma.Iterator) error {
+ for token := it(); token != chroma.EOF; token = it() {
+ value := token.Value
+ if processValue != nil {
+ value = processValue(value)
+ }
+
+ entry := style.Get(token.Type)
+ if entry.IsZero() {
+ if _, err := fmt.Fprint(w, value); err != nil {
+ return err
+ }
+ continue
+ }
+
+ s := lipgloss.NewStyle().
+ Background(bgColor)
+
+ if entry.Bold == chroma.Yes {
+ s = s.Bold(true)
+ }
+ if entry.Underline == chroma.Yes {
+ s = s.Underline(true)
+ }
+ if entry.Italic == chroma.Yes {
+ s = s.Italic(true)
+ }
+ if entry.Colour.IsSet() {
+ s = s.Foreground(lipgloss.Color(entry.Colour.String()))
+ }
+
+ if _, err := fmt.Fprint(w, s.Render(value)); err != nil {
+ return err
+ }
+ }
+ return nil
+ })
+}