refactor(diffview): cache num digits on a struct variable

Andrey Nering created

Change summary

internal/exp/diffview/diffview.go | 55 ++++++++++++++++----------------
1 file changed, 28 insertions(+), 27 deletions(-)

Detailed changes

internal/exp/diffview/diffview.go 🔗

@@ -45,8 +45,10 @@ type DiffView struct {
 
 	splitHunks []splitHunk
 
-	codeWidth     int
-	fullCodeWidth int // with leading symbols
+	codeWidth       int
+	fullCodeWidth   int // with leading symbols
+	beforeNumDigits int
+	afterNumDigits  int
 }
 
 // New creates a new DiffView with default settings.
@@ -130,6 +132,7 @@ func (dv *DiffView) String() string {
 		return err.Error()
 	}
 	dv.convertDiffToSplit()
+	dv.detectNumDigits()
 	dv.detectCodeWidth()
 
 	switch dv.layout {
@@ -144,14 +147,12 @@ func (dv *DiffView) String() string {
 
 // renderUnified renders the unified diff view as a string.
 func (dv *DiffView) renderUnified() string {
-	beforeNumDigits, afterNumDigits := dv.lineNumberDigits()
-
 	var b strings.Builder
 
 	for _, h := range dv.unified.Hunks {
 		if dv.lineNumbers {
-			b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", beforeNumDigits)))
-			b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", afterNumDigits)))
+			b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", dv.beforeNumDigits)))
+			b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", dv.afterNumDigits)))
 		}
 		b.WriteString(dv.style.DividerLine.Code.Width(dv.fullCodeWidth).Render(dv.hunkLineFor(h)))
 		b.WriteRune('\n')
@@ -165,24 +166,24 @@ func (dv *DiffView) renderUnified() string {
 			switch l.Kind {
 			case udiff.Equal:
 				if dv.lineNumbers {
-					b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(beforeLine, beforeNumDigits)))
-					b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(afterLine, afterNumDigits)))
+					b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits)))
+					b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(afterLine, dv.afterNumDigits)))
 				}
 				b.WriteString(dv.style.EqualLine.Code.Width(dv.fullCodeWidth).Render("  " + content))
 				beforeLine++
 				afterLine++
 			case udiff.Insert:
 				if dv.lineNumbers {
-					b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(" ", beforeNumDigits)))
-					b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(afterLine, afterNumDigits)))
+					b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(" ", dv.beforeNumDigits)))
+					b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(afterLine, dv.afterNumDigits)))
 				}
 				b.WriteString(dv.style.InsertLine.Symbol.Render("+ "))
 				b.WriteString(dv.style.InsertLine.Code.Width(dv.codeWidth).Render(content))
 				afterLine++
 			case udiff.Delete:
 				if dv.lineNumbers {
-					b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(beforeLine, beforeNumDigits)))
-					b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(" ", afterNumDigits)))
+					b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits)))
+					b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(" ", dv.afterNumDigits)))
 				}
 				b.WriteString(dv.style.DeleteLine.Symbol.Render("- "))
 				b.WriteString(dv.style.DeleteLine.Code.Width(dv.codeWidth).Render(content))
@@ -197,17 +198,15 @@ func (dv *DiffView) renderUnified() string {
 
 // renderSplit renders the split (side-by-side) diff view as a string.
 func (dv *DiffView) renderSplit() string {
-	beforeNumDigits, afterNumDigits := dv.lineNumberDigits()
-
 	var b strings.Builder
 
 	for i, h := range dv.splitHunks {
 		if dv.lineNumbers {
-			b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", beforeNumDigits)))
+			b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", dv.beforeNumDigits)))
 		}
 		b.WriteString(dv.style.DividerLine.Code.Width(dv.fullCodeWidth).Render(dv.hunkLineFor(dv.unified.Hunks[i])))
 		if dv.lineNumbers {
-			b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", afterNumDigits)))
+			b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", dv.afterNumDigits)))
 		}
 		b.WriteString(dv.style.DividerLine.Code.Width(dv.fullCodeWidth).Render(" "))
 		b.WriteRune('\n')
@@ -228,18 +227,18 @@ func (dv *DiffView) renderSplit() string {
 			switch {
 			case l.before == nil:
 				if dv.lineNumbers {
-					b.WriteString(dv.style.MissingLine.LineNumber.Render(pad(" ", beforeNumDigits)))
+					b.WriteString(dv.style.MissingLine.LineNumber.Render(pad(" ", dv.beforeNumDigits)))
 				}
 				b.WriteString(dv.style.MissingLine.Code.Width(dv.fullCodeWidth).Render("  "))
 			case l.before.Kind == udiff.Equal:
 				if dv.lineNumbers {
-					b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(beforeLine, beforeNumDigits)))
+					b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits)))
 				}
 				b.WriteString(dv.style.EqualLine.Code.Width(dv.fullCodeWidth).Render("  " + beforeContent))
 				beforeLine++
 			case l.before.Kind == udiff.Delete:
 				if dv.lineNumbers {
-					b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(beforeLine, beforeNumDigits)))
+					b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits)))
 				}
 				b.WriteString(dv.style.DeleteLine.Symbol.Render("- "))
 				b.WriteString(dv.style.DeleteLine.Code.Width(dv.codeWidth).Render(beforeContent))
@@ -249,18 +248,18 @@ func (dv *DiffView) renderSplit() string {
 			switch {
 			case l.after == nil:
 				if dv.lineNumbers {
-					b.WriteString(dv.style.MissingLine.LineNumber.Render(pad(" ", afterNumDigits)))
+					b.WriteString(dv.style.MissingLine.LineNumber.Render(pad(" ", dv.afterNumDigits)))
 				}
 				b.WriteString(dv.style.MissingLine.Code.Width(dv.fullCodeWidth).Render("  "))
 			case l.after.Kind == udiff.Equal:
 				if dv.lineNumbers {
-					b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(afterLine, afterNumDigits)))
+					b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(afterLine, dv.afterNumDigits)))
 				}
 				b.WriteString(dv.style.EqualLine.Code.Width(dv.fullCodeWidth).Render("  " + afterContent))
 				afterLine++
 			case l.after.Kind == udiff.Insert:
 				if dv.lineNumbers {
-					b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(afterLine, afterNumDigits)))
+					b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(afterLine, dv.afterNumDigits)))
 				}
 				b.WriteString(dv.style.InsertLine.Symbol.Render("+ "))
 				b.WriteString(dv.style.InsertLine.Code.Width(dv.codeWidth).Render(afterContent))
@@ -293,14 +292,16 @@ func (dv *DiffView) computeDiff() error {
 	return dv.err
 }
 
-// lineNumberDigits calculates the maximum number of digits needed for before and
+// detectNumDigits calculates the maximum number of digits needed for before and
 // after line numbers.
-func (dv *DiffView) lineNumberDigits() (maxBefore, maxAfter int) {
+func (dv *DiffView) detectNumDigits() {
+	dv.beforeNumDigits = 0
+	dv.afterNumDigits = 0
+
 	for _, h := range dv.unified.Hunks {
-		maxBefore = max(maxBefore, len(strconv.Itoa(h.FromLine+len(h.Lines))))
-		maxAfter = max(maxAfter, len(strconv.Itoa(h.ToLine+len(h.Lines))))
+		dv.beforeNumDigits = max(dv.beforeNumDigits, len(strconv.Itoa(h.FromLine+len(h.Lines))))
+		dv.afterNumDigits = max(dv.afterNumDigits, len(strconv.Itoa(h.ToLine+len(h.Lines))))
 	}
-	return
 }
 
 func (dv *DiffView) hunkLineFor(h *udiff.Hunk) string {