From a9bd37f04a9574a9d0c4144a17ec7710e0821507 Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Fri, 20 Jun 2025 10:30:01 -0300 Subject: [PATCH] perf(diffview): only compute syntax highlight for printed lines --- internal/exp/diffview/diffview.go | 347 ++++++++++++++++-------------- 1 file changed, 182 insertions(+), 165 deletions(-) diff --git a/internal/exp/diffview/diffview.go b/internal/exp/diffview/diffview.go index 8c0d626090078749fc0b2b1669afab2f4fc7f32b..bb51a7e505666e67fd9e914a135a0dd7632bb184 100644 --- a/internal/exp/diffview/diffview.go +++ b/internal/exp/diffview/diffview.go @@ -362,23 +362,29 @@ func (dv *DiffView) renderUnified() string { fullContentStyle := lipgloss.NewStyle().MaxWidth(dv.fullCodeWidth) printedLines := -dv.yOffset - - write := func(s string) { - if printedLines >= 0 { - b.WriteString(s) - } + shouldWrite := func() bool { return printedLines >= 0 } + + getContent := func(in string, ls LineStyle) (content string, leadingEllipsis bool) { + content = strings.TrimSuffix(in, "\n") + content = dv.hightlightCode(content, ls.Code.GetBackground()) + content = ansi.GraphemeWidth.Cut(content, dv.xOffset, len(content)) + content = ansi.Truncate(content, dv.codeWidth, "…") + leadingEllipsis = dv.xOffset > 0 && strings.TrimSpace(content) != "" + return } outer: for i, h := range dv.unified.Hunks { - ls := dv.style.DividerLine - if dv.lineNumbers { - write(ls.LineNumber.Render(pad("…", dv.beforeNumDigits))) - write(ls.LineNumber.Render(pad("…", dv.afterNumDigits))) + if shouldWrite() { + ls := dv.style.DividerLine + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad("…", dv.beforeNumDigits))) + b.WriteString(ls.LineNumber.Render(pad("…", dv.afterNumDigits))) + } + content := ansi.Truncate(dv.hunkLineFor(h), dv.fullCodeWidth, "…") + b.WriteString(ls.Code.Width(dv.fullCodeWidth).Render(content)) + b.WriteString("\n") } - content := ansi.Truncate(dv.hunkLineFor(h), dv.fullCodeWidth, "…") - write(ls.Code.Width(dv.fullCodeWidth).Render(content)) - write("\n") printedLines++ beforeLine := h.FromLine @@ -390,80 +396,82 @@ outer: isLastHunk := i+1 == len(dv.unified.Hunks) isLastLine := j+1 == len(h.Lines) if hasReachedHeight && (!isLastHunk || !isLastLine) { - ls := dv.lineStyleForType(l.Kind) - if dv.lineNumbers { - write(ls.LineNumber.Render(pad("…", dv.beforeNumDigits))) - write(ls.LineNumber.Render(pad("…", dv.afterNumDigits))) + if shouldWrite() { + ls := dv.lineStyleForType(l.Kind) + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad("…", dv.beforeNumDigits))) + b.WriteString(ls.LineNumber.Render(pad("…", dv.afterNumDigits))) + } + b.WriteString(fullContentStyle.Render( + ls.Code.Width(dv.fullCodeWidth).Render(" …"), + )) + b.WriteRune('\n') } - write(fullContentStyle.Render( - ls.Code.Width(dv.fullCodeWidth).Render(" …"), - )) - write("\n") break outer } - getContent := func(ls LineStyle) string { - content := strings.TrimSuffix(l.Content, "\n") - content = dv.hightlightCode(content, ls.Code.GetBackground()) - content = ansi.GraphemeWidth.Cut(content, dv.xOffset, len(content)) - content = ansi.Truncate(content, dv.codeWidth, "…") - return content - } - - leadingEllipsis := dv.xOffset > 0 && strings.TrimSpace(content) != "" - switch l.Kind { case udiff.Equal: - ls := dv.style.EqualLine - content := getContent(ls) - if dv.lineNumbers { - write(ls.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits))) - write(ls.LineNumber.Render(pad(afterLine, dv.afterNumDigits))) + if shouldWrite() { + ls := dv.style.EqualLine + content, leadingEllipsis := getContent(l.Content, ls) + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits))) + b.WriteString(ls.LineNumber.Render(pad(afterLine, dv.afterNumDigits))) + } + b.WriteString(fullContentStyle.Render( + ls.Code.Width(dv.fullCodeWidth).Render(ternary(leadingEllipsis, " …", " ") + content), + )) } - write(fullContentStyle.Render( - ls.Code.Width(dv.fullCodeWidth).Render(ternary(leadingEllipsis, " …", " ") + content), - )) beforeLine++ afterLine++ case udiff.Insert: - ls := dv.style.InsertLine - content := getContent(ls) - if dv.lineNumbers { - write(ls.LineNumber.Render(pad(" ", dv.beforeNumDigits))) - write(ls.LineNumber.Render(pad(afterLine, dv.afterNumDigits))) + if shouldWrite() { + ls := dv.style.InsertLine + content, leadingEllipsis := getContent(l.Content, ls) + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad(" ", dv.beforeNumDigits))) + b.WriteString(ls.LineNumber.Render(pad(afterLine, dv.afterNumDigits))) + } + b.WriteString(fullContentStyle.Render( + ls.Symbol.Render(ternary(leadingEllipsis, "+…", "+ ")) + + ls.Code.Width(dv.codeWidth).Render(content), + )) } - write(fullContentStyle.Render( - ls.Symbol.Render(ternary(leadingEllipsis, "+…", "+ ")) + - ls.Code.Width(dv.codeWidth).Render(content), - )) afterLine++ case udiff.Delete: - ls := dv.style.DeleteLine - content := getContent(ls) - if dv.lineNumbers { - write(ls.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits))) - write(ls.LineNumber.Render(pad(" ", dv.afterNumDigits))) + if shouldWrite() { + ls := dv.style.DeleteLine + content, leadingEllipsis := getContent(l.Content, ls) + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits))) + b.WriteString(ls.LineNumber.Render(pad(" ", dv.afterNumDigits))) + } + b.WriteString(fullContentStyle.Render( + ls.Symbol.Render(ternary(leadingEllipsis, "-…", "- ")) + + ls.Code.Width(dv.codeWidth).Render(content), + )) } - write(fullContentStyle.Render( - ls.Symbol.Render(ternary(leadingEllipsis, "-…", "- ")) + - ls.Code.Width(dv.codeWidth).Render(content), - )) beforeLine++ } - write("\n") + if shouldWrite() { + b.WriteRune('\n') + } printedLines++ } } for printedLines < dv.height { - ls := dv.style.MissingLine - if dv.lineNumbers { - write(ls.LineNumber.Render(pad(" ", dv.beforeNumDigits))) - write(ls.LineNumber.Render(pad(" ", dv.afterNumDigits))) + if shouldWrite() { + ls := dv.style.MissingLine + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad(" ", dv.beforeNumDigits))) + b.WriteString(ls.LineNumber.Render(pad(" ", dv.afterNumDigits))) + } + b.WriteString(ls.Code.Width(dv.fullCodeWidth).Render(" ")) + b.WriteRune('\n') } - write(ls.Code.Width(dv.fullCodeWidth).Render(" ")) - write("\n") printedLines++ } @@ -477,26 +485,32 @@ func (dv *DiffView) renderSplit() string { beforeFullContentStyle := lipgloss.NewStyle().MaxWidth(dv.fullCodeWidth) afterFullContentStyle := lipgloss.NewStyle().MaxWidth(dv.fullCodeWidth + btoi(dv.extraColOnAfter)) printedLines := -dv.yOffset - - write := func(s string) { - if printedLines >= 0 { - b.WriteString(s) - } + shouldWrite := func() bool { return printedLines >= 0 } + + getContent := func(in string, ls LineStyle) (content string, leadingEllipsis bool) { + content = strings.TrimSuffix(in, "\n") + content = dv.hightlightCode(content, ls.Code.GetBackground()) + content = ansi.GraphemeWidth.Cut(content, dv.xOffset, len(content)) + content = ansi.Truncate(content, dv.codeWidth, "…") + leadingEllipsis = dv.xOffset > 0 && strings.TrimSpace(content) != "" + return } outer: for i, h := range dv.splitHunks { - ls := dv.style.DividerLine - if dv.lineNumbers { - write(ls.LineNumber.Render(pad("…", dv.beforeNumDigits))) - } - content := ansi.Truncate(dv.hunkLineFor(dv.unified.Hunks[i]), dv.fullCodeWidth, "…") - write(ls.Code.Width(dv.fullCodeWidth).Render(content)) - if dv.lineNumbers { - write(ls.LineNumber.Render(pad("…", dv.afterNumDigits))) + if shouldWrite() { + ls := dv.style.DividerLine + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad("…", dv.beforeNumDigits))) + } + content := ansi.Truncate(dv.hunkLineFor(dv.unified.Hunks[i]), dv.fullCodeWidth, "…") + b.WriteString(ls.Code.Width(dv.fullCodeWidth).Render(content)) + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad("…", dv.afterNumDigits))) + } + b.WriteString(ls.Code.Width(dv.fullCodeWidth + btoi(dv.extraColOnAfter)).Render(" ")) + b.WriteRune('\n') } - write(ls.Code.Width(dv.fullCodeWidth + btoi(dv.extraColOnAfter)).Render(" ")) - write("\n") printedLines++ beforeLine := h.fromLine @@ -508,126 +522,129 @@ outer: isLastHunk := i+1 == len(dv.unified.Hunks) isLastLine := j+1 == len(h.lines) if hasReachedHeight && (!isLastHunk || !isLastLine) { - ls := dv.style.MissingLine - if l.before != nil { - ls = dv.lineStyleForType(l.before.Kind) - } - if dv.lineNumbers { - write(ls.LineNumber.Render(pad("…", dv.beforeNumDigits))) + if shouldWrite() { + ls := dv.style.MissingLine + if l.before != nil { + ls = dv.lineStyleForType(l.before.Kind) + } + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad("…", dv.beforeNumDigits))) + } + b.WriteString(beforeFullContentStyle.Render( + ls.Code.Width(dv.fullCodeWidth).Render(" …"), + )) + ls = dv.style.MissingLine + if l.after != nil { + ls = dv.lineStyleForType(l.after.Kind) + } + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad("…", dv.afterNumDigits))) + } + b.WriteString(afterFullContentStyle.Render( + ls.Code.Width(dv.fullCodeWidth).Render(" …"), + )) + b.WriteRune('\n') } - write(beforeFullContentStyle.Render( - ls.Code.Width(dv.fullCodeWidth).Render(" …"), - )) - ls = dv.style.MissingLine - if l.after != nil { - ls = dv.lineStyleForType(l.after.Kind) - } - if dv.lineNumbers { - write(ls.LineNumber.Render(pad("…", dv.afterNumDigits))) - } - write(afterFullContentStyle.Render( - ls.Code.Width(dv.fullCodeWidth).Render(" …"), - )) - write("\n") break outer } - getContent := func(content string, ls LineStyle) string { - content = strings.TrimSuffix(content, "\n") - content = dv.hightlightCode(content, ls.Code.GetBackground()) - content = ansi.GraphemeWidth.Cut(content, dv.xOffset, len(content)) - content = ansi.Truncate(content, dv.codeWidth, "…") - return content - } - getLeadingEllipsis := func(content string) bool { - return dv.xOffset > 0 && strings.TrimSpace(content) != "" - } - switch { case l.before == nil: - ls := dv.style.MissingLine - if dv.lineNumbers { - write(ls.LineNumber.Render(pad(" ", dv.beforeNumDigits))) + if shouldWrite() { + ls := dv.style.MissingLine + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad(" ", dv.beforeNumDigits))) + } + b.WriteString(beforeFullContentStyle.Render( + ls.Code.Width(dv.fullCodeWidth).Render(" "), + )) } - write(beforeFullContentStyle.Render( - ls.Code.Width(dv.fullCodeWidth).Render(" "), - )) case l.before.Kind == udiff.Equal: - ls := dv.style.EqualLine - content := getContent(l.before.Content, ls) - leadingEllipsis := getLeadingEllipsis(content) - if dv.lineNumbers { - write(ls.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits))) + if shouldWrite() { + ls := dv.style.EqualLine + content, leadingEllipsis := getContent(l.before.Content, ls) + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits))) + } + b.WriteString(beforeFullContentStyle.Render( + ls.Code.Width(dv.fullCodeWidth).Render(ternary(leadingEllipsis, " …", " ") + content), + )) } - write(beforeFullContentStyle.Render( - ls.Code.Width(dv.fullCodeWidth).Render(ternary(leadingEllipsis, " …", " ") + content), - )) beforeLine++ case l.before.Kind == udiff.Delete: - ls := dv.style.DeleteLine - content := getContent(l.before.Content, ls) - leadingEllipsis := getLeadingEllipsis(content) - if dv.lineNumbers { - write(ls.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits))) + if shouldWrite() { + ls := dv.style.DeleteLine + content, leadingEllipsis := getContent(l.before.Content, ls) + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits))) + } + b.WriteString(beforeFullContentStyle.Render( + ls.Symbol.Render(ternary(leadingEllipsis, "-…", "- ")) + + ls.Code.Width(dv.codeWidth).Render(content), + )) } - write(beforeFullContentStyle.Render( - ls.Symbol.Render(ternary(leadingEllipsis, "-…", "- ")) + - ls.Code.Width(dv.codeWidth).Render(content), - )) beforeLine++ } switch { case l.after == nil: - ls := dv.style.MissingLine - if dv.lineNumbers { - write(ls.LineNumber.Render(pad(" ", dv.afterNumDigits))) + if shouldWrite() { + ls := dv.style.MissingLine + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad(" ", dv.afterNumDigits))) + } + b.WriteString(afterFullContentStyle.Render( + ls.Code.Width(dv.fullCodeWidth + btoi(dv.extraColOnAfter)).Render(" "), + )) } - write(afterFullContentStyle.Render( - ls.Code.Width(dv.fullCodeWidth + btoi(dv.extraColOnAfter)).Render(" "), - )) case l.after.Kind == udiff.Equal: - ls := dv.style.EqualLine - content := getContent(l.after.Content, ls) - leadingEllipsis := getLeadingEllipsis(content) - if dv.lineNumbers { - write(ls.LineNumber.Render(pad(afterLine, dv.afterNumDigits))) + if shouldWrite() { + ls := dv.style.EqualLine + content, leadingEllipsis := getContent(l.after.Content, ls) + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad(afterLine, dv.afterNumDigits))) + } + b.WriteString(afterFullContentStyle.Render( + ls.Code.Width(dv.fullCodeWidth + btoi(dv.extraColOnAfter)).Render(ternary(leadingEllipsis, " …", " ") + content), + )) } - write(afterFullContentStyle.Render( - ls.Code.Width(dv.fullCodeWidth + btoi(dv.extraColOnAfter)).Render(ternary(leadingEllipsis, " …", " ") + content), - )) afterLine++ case l.after.Kind == udiff.Insert: - ls := dv.style.InsertLine - content := getContent(l.after.Content, ls) - leadingEllipsis := getLeadingEllipsis(content) - if dv.lineNumbers { - write(ls.LineNumber.Render(pad(afterLine, dv.afterNumDigits))) + if shouldWrite() { + ls := dv.style.InsertLine + content, leadingEllipsis := getContent(l.after.Content, ls) + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad(afterLine, dv.afterNumDigits))) + } + b.WriteString(afterFullContentStyle.Render( + ls.Symbol.Render(ternary(leadingEllipsis, "+…", "+ ")) + + ls.Code.Width(dv.codeWidth+btoi(dv.extraColOnAfter)).Render(content), + )) } - write(afterFullContentStyle.Render( - ls.Symbol.Render(ternary(leadingEllipsis, "+…", "+ ")) + - ls.Code.Width(dv.codeWidth+btoi(dv.extraColOnAfter)).Render(content), - )) afterLine++ } - write("\n") + if shouldWrite() { + b.WriteRune('\n') + } printedLines++ } } for printedLines < dv.height { - ls := dv.style.MissingLine - if dv.lineNumbers { - write(ls.LineNumber.Render(pad(" ", dv.beforeNumDigits))) - } - write(ls.Code.Width(dv.fullCodeWidth).Render(" ")) - if dv.lineNumbers { - write(ls.LineNumber.Render(pad(" ", dv.afterNumDigits))) + if shouldWrite() { + ls := dv.style.MissingLine + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad(" ", dv.beforeNumDigits))) + } + b.WriteString(ls.Code.Width(dv.fullCodeWidth).Render(" ")) + if dv.lineNumbers { + b.WriteString(ls.LineNumber.Render(pad(" ", dv.afterNumDigits))) + } + b.WriteString(ls.Code.Width(dv.fullCodeWidth + btoi(dv.extraColOnAfter)).Render(" ")) + b.WriteRune('\n') } - write(ls.Code.Width(dv.fullCodeWidth + btoi(dv.extraColOnAfter)).Render(" ")) - write("\n") printedLines++ }