@@ -1,6 +1,7 @@
package diffview
import (
+ "crypto/sha256"
"fmt"
"image/color"
"strconv"
@@ -59,6 +60,13 @@ type DiffView struct {
extraColOnAfter bool // add extra column on after panel
beforeNumDigits int
afterNumDigits int
+
+ // Cache lexer to avoid expensive file pattern matching on every line
+ cachedLexer chroma.Lexer
+
+ // Cache highlighted lines to avoid re-highlighting the same content
+ // Key: hash of (content + background color), Value: highlighted string
+ syntaxCache map[string]string
}
// New creates a new DiffView with default settings.
@@ -68,6 +76,7 @@ func New() *DiffView {
contextLines: udiff.DefaultContextLines,
lineNumbers: true,
tabWidth: 8,
+ syntaxCache: make(map[string]string),
}
dv.style = DefaultDarkStyle()
return dv
@@ -88,15 +97,26 @@ func (dv *DiffView) Split() *DiffView {
// Before sets the "before" file for the DiffView.
func (dv *DiffView) Before(path, content string) *DiffView {
dv.before = file{path: path, content: content}
+ // Clear caches when content changes
+ dv.clearCaches()
return dv
}
// After sets the "after" file for the DiffView.
func (dv *DiffView) After(path, content string) *DiffView {
dv.after = file{path: path, content: content}
+ // Clear caches when content changes
+ dv.clearCaches()
return dv
}
+// clearCaches clears all caches when content or major settings change.
+func (dv *DiffView) clearCaches() {
+ dv.cachedLexer = nil
+ dv.clearSyntaxCache()
+ dv.isComputed = false
+}
+
// ContextLines sets the number of context lines for the DiffView.
func (dv *DiffView) ContextLines(contextLines int) *DiffView {
dv.contextLines = contextLines
@@ -156,9 +176,21 @@ func (dv *DiffView) TabWidth(tabWidth int) *DiffView {
// If nil, no syntax highlighting will be applied.
func (dv *DiffView) ChromaStyle(style *chroma.Style) *DiffView {
dv.chromaStyle = style
+ // Clear syntax cache when style changes since highlighting will be different
+ dv.clearSyntaxCache()
return dv
}
+// clearSyntaxCache clears the syntax highlighting cache.
+func (dv *DiffView) clearSyntaxCache() {
+ if dv.syntaxCache != nil {
+ // Clear the map but keep it allocated
+ for k := range dv.syntaxCache {
+ delete(dv.syntaxCache, k)
+ }
+ }
+}
+
// String returns the string representation of the DiffView.
func (dv *DiffView) String() string {
dv.replaceTabs()
@@ -700,7 +732,15 @@ func (dv *DiffView) hightlightCode(source string, bgColor color.Color) string {
return source
}
- l := dv.getChromaLexer(source)
+ // Create cache key from content and background color
+ cacheKey := dv.createSyntaxCacheKey(source, bgColor)
+
+ // Check if we already have this highlighted
+ if cached, exists := dv.syntaxCache[cacheKey]; exists {
+ return cached
+ }
+
+ l := dv.getChromaLexer()
f := dv.getChromaFormatter(bgColor)
it, err := l.Tokenise(nil, source)
@@ -712,22 +752,47 @@ func (dv *DiffView) hightlightCode(source string, bgColor color.Color) string {
if err := f.Format(&b, dv.chromaStyle, it); err != nil {
return source
}
- return b.String()
+
+ result := b.String()
+
+ // Cache the result for future use
+ dv.syntaxCache[cacheKey] = result
+
+ return result
}
-func (dv *DiffView) getChromaLexer(source string) chroma.Lexer {
+// createSyntaxCacheKey creates a cache key from source content and background color.
+// We use a simple hash to keep memory usage reasonable.
+func (dv *DiffView) createSyntaxCacheKey(source string, bgColor color.Color) string {
+ // Convert color to string representation
+ r, g, b, a := bgColor.RGBA()
+ colorStr := fmt.Sprintf("%d,%d,%d,%d", r, g, b, a)
+
+ // Create a hash of the content + color to use as cache key
+ h := sha256.New()
+ h.Write([]byte(source))
+ h.Write([]byte(colorStr))
+ return fmt.Sprintf("%x", h.Sum(nil))
+}
+
+func (dv *DiffView) getChromaLexer() chroma.Lexer {
+ if dv.cachedLexer != nil {
+ return dv.cachedLexer
+ }
+
l := lexers.Match(dv.before.path)
if l == nil {
- l = lexers.Analyse(source)
+ l = lexers.Analyse(dv.before.content)
}
if l == nil {
l = lexers.Fallback
}
- return chroma.Coalesce(l)
+ dv.cachedLexer = chroma.Coalesce(l)
+ return dv.cachedLexer
}
-func (dv *DiffView) getChromaFormatter(gbColor color.Color) chroma.Formatter {
+func (dv *DiffView) getChromaFormatter(bgColor color.Color) chroma.Formatter {
return chromaFormatter{
- bgColor: gbColor,
+ bgColor: bgColor,
}
}