@@ -45,8 +45,10 @@ type DiffView struct {
46 splitHunks []splitHunk
46 splitHunks []splitHunk
48− codeWidth int
48+ codeWidth int
49− fullCodeWidth int // with leading symbols
49+ fullCodeWidth int // with leading symbols
52// New creates a new DiffView with default settings.
54// New creates a new DiffView with default settings.
@@ -130,6 +132,7 @@ func (dv *DiffView) String() string {
130 return err.Error()
132 return err.Error()
132 dv.convertDiffToSplit()
134 dv.convertDiffToSplit()
135+ dv.detectNumDigits()
133 dv.detectCodeWidth()
136 dv.detectCodeWidth()
135 switch dv.layout {
138 switch dv.layout {
@@ -144,14 +147,12 @@ func (dv *DiffView) String() string {
145// renderUnified renders the unified diff view as a string.
148// renderUnified renders the unified diff view as a string.
146func (dv *DiffView) renderUnified() string {
149func (dv *DiffView) renderUnified() string {
147− beforeNumDigits, afterNumDigits := dv.lineNumberDigits()
149 var b strings.Builder
150 var b strings.Builder
151 for _, h := range dv.unified.Hunks {
152 for _, h := range dv.unified.Hunks {
152 if dv.lineNumbers {
153 if dv.lineNumbers {
153− b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", beforeNumDigits)))
154+ b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", dv.beforeNumDigits)))
154− b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", afterNumDigits)))
155+ b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", dv.afterNumDigits)))
156 b.WriteString(dv.style.DividerLine.Code.Width(dv.fullCodeWidth).Render(dv.hunkLineFor(h)))
157 b.WriteString(dv.style.DividerLine.Code.Width(dv.fullCodeWidth).Render(dv.hunkLineFor(h)))
157 b.WriteRune('\n')
158 b.WriteRune('\n')
@@ -165,24 +166,24 @@ func (dv *DiffView) renderUnified() string {
165 switch l.Kind {
166 switch l.Kind {
166 case udiff.Equal:
167 case udiff.Equal:
167 if dv.lineNumbers {
168 if dv.lineNumbers {
168− b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(beforeLine, beforeNumDigits)))
169+ b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits)))
169− b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(afterLine, afterNumDigits)))
170+ b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(afterLine, dv.afterNumDigits)))
171 b.WriteString(dv.style.EqualLine.Code.Width(dv.fullCodeWidth).Render(" " + content))
172 b.WriteString(dv.style.EqualLine.Code.Width(dv.fullCodeWidth).Render(" " + content))
172 beforeLine++
173 beforeLine++
173 afterLine++
174 afterLine++
174 case udiff.Insert:
175 case udiff.Insert:
175 if dv.lineNumbers {
176 if dv.lineNumbers {
176− b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(" ", beforeNumDigits)))
177+ b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(" ", dv.beforeNumDigits)))
177− b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(afterLine, afterNumDigits)))
178+ b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(afterLine, dv.afterNumDigits)))
179 b.WriteString(dv.style.InsertLine.Symbol.Render("+ "))
180 b.WriteString(dv.style.InsertLine.Symbol.Render("+ "))
180 b.WriteString(dv.style.InsertLine.Code.Width(dv.codeWidth).Render(content))
181 b.WriteString(dv.style.InsertLine.Code.Width(dv.codeWidth).Render(content))
181 afterLine++
182 afterLine++
182 case udiff.Delete:
183 case udiff.Delete:
183 if dv.lineNumbers {
184 if dv.lineNumbers {
184− b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(beforeLine, beforeNumDigits)))
185+ b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits)))
185− b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(" ", afterNumDigits)))
186+ b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(" ", dv.afterNumDigits)))
187 b.WriteString(dv.style.DeleteLine.Symbol.Render("- "))
188 b.WriteString(dv.style.DeleteLine.Symbol.Render("- "))
188 b.WriteString(dv.style.DeleteLine.Code.Width(dv.codeWidth).Render(content))
189 b.WriteString(dv.style.DeleteLine.Code.Width(dv.codeWidth).Render(content))
@@ -197,17 +198,15 @@ func (dv *DiffView) renderUnified() string {
198// renderSplit renders the split (side-by-side) diff view as a string.
199// renderSplit renders the split (side-by-side) diff view as a string.
199func (dv *DiffView) renderSplit() string {
200func (dv *DiffView) renderSplit() string {
200− beforeNumDigits, afterNumDigits := dv.lineNumberDigits()
202 var b strings.Builder
201 var b strings.Builder
204 for i, h := range dv.splitHunks {
203 for i, h := range dv.splitHunks {
205 if dv.lineNumbers {
204 if dv.lineNumbers {
206− b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", beforeNumDigits)))
205+ b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", dv.beforeNumDigits)))
208 b.WriteString(dv.style.DividerLine.Code.Width(dv.fullCodeWidth).Render(dv.hunkLineFor(dv.unified.Hunks[i])))
207 b.WriteString(dv.style.DividerLine.Code.Width(dv.fullCodeWidth).Render(dv.hunkLineFor(dv.unified.Hunks[i])))
209 if dv.lineNumbers {
208 if dv.lineNumbers {
210− b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", afterNumDigits)))
209+ b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", dv.afterNumDigits)))
212 b.WriteString(dv.style.DividerLine.Code.Width(dv.fullCodeWidth).Render(" "))
211 b.WriteString(dv.style.DividerLine.Code.Width(dv.fullCodeWidth).Render(" "))
213 b.WriteRune('\n')
212 b.WriteRune('\n')
@@ -228,18 +227,18 @@ func (dv *DiffView) renderSplit() string {
229 case l.before == nil:
228 case l.before == nil:
230 if dv.lineNumbers {
229 if dv.lineNumbers {
231− b.WriteString(dv.style.MissingLine.LineNumber.Render(pad(" ", beforeNumDigits)))
230+ b.WriteString(dv.style.MissingLine.LineNumber.Render(pad(" ", dv.beforeNumDigits)))
233 b.WriteString(dv.style.MissingLine.Code.Width(dv.fullCodeWidth).Render(" "))
232 b.WriteString(dv.style.MissingLine.Code.Width(dv.fullCodeWidth).Render(" "))
234 case l.before.Kind == udiff.Equal:
233 case l.before.Kind == udiff.Equal:
235 if dv.lineNumbers {
234 if dv.lineNumbers {
236− b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(beforeLine, beforeNumDigits)))
235+ b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits)))
238 b.WriteString(dv.style.EqualLine.Code.Width(dv.fullCodeWidth).Render(" " + beforeContent))
237 b.WriteString(dv.style.EqualLine.Code.Width(dv.fullCodeWidth).Render(" " + beforeContent))
239 beforeLine++
238 beforeLine++
240 case l.before.Kind == udiff.Delete:
239 case l.before.Kind == udiff.Delete:
241 if dv.lineNumbers {
240 if dv.lineNumbers {
242− b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(beforeLine, beforeNumDigits)))
241+ b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits)))
244 b.WriteString(dv.style.DeleteLine.Symbol.Render("- "))
243 b.WriteString(dv.style.DeleteLine.Symbol.Render("- "))
245 b.WriteString(dv.style.DeleteLine.Code.Width(dv.codeWidth).Render(beforeContent))
244 b.WriteString(dv.style.DeleteLine.Code.Width(dv.codeWidth).Render(beforeContent))
@@ -249,18 +248,18 @@ func (dv *DiffView) renderSplit() string {
250 case l.after == nil:
249 case l.after == nil:
251 if dv.lineNumbers {
250 if dv.lineNumbers {
252− b.WriteString(dv.style.MissingLine.LineNumber.Render(pad(" ", afterNumDigits)))
251+ b.WriteString(dv.style.MissingLine.LineNumber.Render(pad(" ", dv.afterNumDigits)))
254 b.WriteString(dv.style.MissingLine.Code.Width(dv.fullCodeWidth).Render(" "))
253 b.WriteString(dv.style.MissingLine.Code.Width(dv.fullCodeWidth).Render(" "))
255 case l.after.Kind == udiff.Equal:
254 case l.after.Kind == udiff.Equal:
256 if dv.lineNumbers {
255 if dv.lineNumbers {
257− b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(afterLine, afterNumDigits)))
256+ b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(afterLine, dv.afterNumDigits)))
259 b.WriteString(dv.style.EqualLine.Code.Width(dv.fullCodeWidth).Render(" " + afterContent))
258 b.WriteString(dv.style.EqualLine.Code.Width(dv.fullCodeWidth).Render(" " + afterContent))
260 afterLine++
259 afterLine++
261 case l.after.Kind == udiff.Insert:
260 case l.after.Kind == udiff.Insert:
262 if dv.lineNumbers {
261 if dv.lineNumbers {
263− b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(afterLine, afterNumDigits)))
262+ b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(afterLine, dv.afterNumDigits)))
265 b.WriteString(dv.style.InsertLine.Symbol.Render("+ "))
264 b.WriteString(dv.style.InsertLine.Symbol.Render("+ "))
266 b.WriteString(dv.style.InsertLine.Code.Width(dv.codeWidth).Render(afterContent))
265 b.WriteString(dv.style.InsertLine.Code.Width(dv.codeWidth).Render(afterContent))
@@ -293,14 +292,16 @@ func (dv *DiffView) computeDiff() error {
293 return dv.err
292 return dv.err
296−// lineNumberDigits calculates the maximum number of digits needed for before and
295+// detectNumDigits calculates the maximum number of digits needed for before and
297// after line numbers.
296// after line numbers.
298−func (dv *DiffView) lineNumberDigits() (maxBefore, maxAfter int) {
297+func (dv *DiffView) detectNumDigits() {
298+ dv.beforeNumDigits = 0
299+ dv.afterNumDigits = 0
299 for _, h := range dv.unified.Hunks {
301 for _, h := range dv.unified.Hunks {
300− maxBefore = max(maxBefore, len(strconv.Itoa(h.FromLine+len(h.Lines))))
302+ dv.beforeNumDigits = max(dv.beforeNumDigits, len(strconv.Itoa(h.FromLine+len(h.Lines))))
301− maxAfter = max(maxAfter, len(strconv.Itoa(h.ToLine+len(h.Lines))))
303+ dv.afterNumDigits = max(dv.afterNumDigits, len(strconv.Itoa(h.ToLine+len(h.Lines))))
306func (dv *DiffView) hunkLineFor(h *udiff.Hunk) string {
307func (dv *DiffView) hunkLineFor(h *udiff.Hunk) string {