@@ -43,9 +43,10 @@ type DiffView struct {
4343 unified udiff.UnifiedDiff
4444 edits []udiff.Edit
4545
46− splitHunks []splitHunk
47− beforeCodeWidth int
48− afterCodeWidth int
46+ splitHunks []splitHunk
47+
48+ codeWidth int
49+ fullCodeWidth int // with leading symbols
4950}
5051
5152// New creates a new DiffView with default settings.
@@ -128,6 +129,8 @@ func (dv *DiffView) String() string {
128129 if err := dv.computeDiff(); err != nil {
129130 return err.Error()
130131 }
132+ dv.convertDiffToSplit()
133+ dv.detectCodeWidth()
131134
132135 switch dv.layout {
133136 case layoutUnified:
@@ -141,9 +144,6 @@ func (dv *DiffView) String() string {
141144
142145// renderUnified renders the unified diff view as a string.
143146func (dv *DiffView) renderUnified() string {
144− dv.detectUnifiedWidth()
145−
146− codeWidth := dv.width - leadingSymbolsSize
147147 beforeNumDigits, afterNumDigits := dv.lineNumberDigits()
148148
149149 var b strings.Builder
@@ -153,7 +153,7 @@ func (dv *DiffView) renderUnified() string {
153153 b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", beforeNumDigits)))
154154 b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", afterNumDigits)))
155155 }
156− b.WriteString(dv.style.DividerLine.Code.Width(codeWidth + leadingSymbolsSize).Render(dv.hunkLineFor(h)))
156+ b.WriteString(dv.style.DividerLine.Code.Width(dv.fullCodeWidth).Render(dv.hunkLineFor(h)))
157157 b.WriteRune('\n')
158158
159159 beforeLine := h.FromLine
@@ -168,7 +168,7 @@ func (dv *DiffView) renderUnified() string {
168168 b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(beforeLine, beforeNumDigits)))
169169 b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(afterLine, afterNumDigits)))
170170 }
171− b.WriteString(dv.style.EqualLine.Code.Width(codeWidth + leadingSymbolsSize).Render(" " + content))
171+ b.WriteString(dv.style.EqualLine.Code.Width(dv.fullCodeWidth).Render(" " + content))
172172 beforeLine++
173173 afterLine++
174174 case udiff.Insert:
@@ -177,7 +177,7 @@ func (dv *DiffView) renderUnified() string {
177177 b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(afterLine, afterNumDigits)))
178178 }
179179 b.WriteString(dv.style.InsertLine.Symbol.Render("+ "))
180− b.WriteString(dv.style.InsertLine.Code.Width(codeWidth).Render(content))
180+ b.WriteString(dv.style.InsertLine.Code.Width(dv.codeWidth).Render(content))
181181 afterLine++
182182 case udiff.Delete:
183183 if dv.lineNumbers {
@@ -185,7 +185,7 @@ func (dv *DiffView) renderUnified() string {
185185 b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(" ", afterNumDigits)))
186186 }
187187 b.WriteString(dv.style.DeleteLine.Symbol.Render("- "))
188− b.WriteString(dv.style.DeleteLine.Code.Width(codeWidth).Render(content))
188+ b.WriteString(dv.style.DeleteLine.Code.Width(dv.codeWidth).Render(content))
189189 beforeLine++
190190 }
191191 b.WriteRune('\n')
@@ -197,9 +197,6 @@ func (dv *DiffView) renderUnified() string {
197197
198198// renderSplit renders the split (side-by-side) diff view as a string.
199199func (dv *DiffView) renderSplit() string {
200− dv.convertDiffToSplit()
201− dv.detectSplitWidth()
202−
203200 beforeNumDigits, afterNumDigits := dv.lineNumberDigits()
204201
205202 var b strings.Builder
@@ -208,11 +205,11 @@ func (dv *DiffView) renderSplit() string {
208205 if dv.lineNumbers {
209206 b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", beforeNumDigits)))
210207 }
211− b.WriteString(dv.style.DividerLine.Code.Width(dv.beforeCodeWidth + leadingSymbolsSize).Render(dv.hunkLineFor(dv.unified.Hunks[i])))
208+ b.WriteString(dv.style.DividerLine.Code.Width(dv.fullCodeWidth).Render(dv.hunkLineFor(dv.unified.Hunks[i])))
212209 if dv.lineNumbers {
213210 b.WriteString(dv.style.DividerLine.LineNumber.Render(pad("…", afterNumDigits)))
214211 }
215− b.WriteString(dv.style.DividerLine.Code.Width(dv.afterCodeWidth + leadingSymbolsSize).Render(" "))
212+ b.WriteString(dv.style.DividerLine.Code.Width(dv.fullCodeWidth).Render(" "))
216213 b.WriteRune('\n')
217214
218215 beforeLine := h.fromLine
@@ -233,19 +230,19 @@ func (dv *DiffView) renderSplit() string {
233230 if dv.lineNumbers {
234231 b.WriteString(dv.style.MissingLine.LineNumber.Render(pad(" ", beforeNumDigits)))
235232 }
236− b.WriteString(dv.style.MissingLine.Code.Width(dv.beforeCodeWidth + leadingSymbolsSize).Render(" "))
233+ b.WriteString(dv.style.MissingLine.Code.Width(dv.fullCodeWidth).Render(" "))
237234 case l.before.Kind == udiff.Equal:
238235 if dv.lineNumbers {
239236 b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(beforeLine, beforeNumDigits)))
240237 }
241− b.WriteString(dv.style.EqualLine.Code.Width(dv.beforeCodeWidth + leadingSymbolsSize).Render(" " + beforeContent))
238+ b.WriteString(dv.style.EqualLine.Code.Width(dv.fullCodeWidth).Render(" " + beforeContent))
242239 beforeLine++
243240 case l.before.Kind == udiff.Delete:
244241 if dv.lineNumbers {
245242 b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(beforeLine, beforeNumDigits)))
246243 }
247244 b.WriteString(dv.style.DeleteLine.Symbol.Render("- "))
248− b.WriteString(dv.style.DeleteLine.Code.Width(dv.beforeCodeWidth).Render(beforeContent))
245+ b.WriteString(dv.style.DeleteLine.Code.Width(dv.codeWidth).Render(beforeContent))
249246 beforeLine++
250247 }
251248
@@ -254,19 +251,19 @@ func (dv *DiffView) renderSplit() string {
254251 if dv.lineNumbers {
255252 b.WriteString(dv.style.MissingLine.LineNumber.Render(pad(" ", afterNumDigits)))
256253 }
257− b.WriteString(dv.style.MissingLine.Code.Width(dv.afterCodeWidth + leadingSymbolsSize).Render(" "))
254+ b.WriteString(dv.style.MissingLine.Code.Width(dv.fullCodeWidth).Render(" "))
258255 case l.after.Kind == udiff.Equal:
259256 if dv.lineNumbers {
260257 b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(afterLine, afterNumDigits)))
261258 }
262− b.WriteString(dv.style.EqualLine.Code.Width(dv.afterCodeWidth + leadingSymbolsSize).Render(" " + afterContent))
259+ b.WriteString(dv.style.EqualLine.Code.Width(dv.fullCodeWidth).Render(" " + afterContent))
263260 afterLine++
264261 case l.after.Kind == udiff.Insert:
265262 if dv.lineNumbers {
266263 b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(afterLine, afterNumDigits)))
267264 }
268265 b.WriteString(dv.style.InsertLine.Symbol.Render("+ "))
269− b.WriteString(dv.style.InsertLine.Code.Width(dv.afterCodeWidth).Render(afterContent))
266+ b.WriteString(dv.style.InsertLine.Code.Width(dv.codeWidth).Render(afterContent))
270267 afterLine++
271268 }
272269
@@ -335,51 +332,55 @@ func (dv *DiffView) hunkShownLines(h *udiff.Hunk) (before, after int) {
335332 return
336333}
337334
338−func (dv *DiffView) detectUnifiedWidth() {
339− if dv.width > 0 {
340− return
335+func (dv *DiffView) detectCodeWidth() {
336+ switch dv.layout {
337+ case layoutUnified:
338+ dv.detectUnifiedCodeWidth()
339+ case layoutSplit:
340+ dv.detectSplitCodeWidth()
341341 }
342+ dv.fullCodeWidth = dv.codeWidth + leadingSymbolsSize
343+}
344+
345+func (dv *DiffView) detectUnifiedCodeWidth() {
346+ dv.codeWidth = 0
342347
343348 for _, h := range dv.unified.Hunks {
344349 shownLines := ansi.StringWidth(dv.hunkLineFor(h))
345350
346351 for _, l := range h.Lines {
347− lineWidth := ansi.StringWidth(strings.TrimSuffix(l.Content, "\n"))
348− lineWidth += leadingSymbolsSize
349− dv.width = max(dv.width, lineWidth, shownLines)
352+ lineWidth := ansi.StringWidth(strings.TrimSuffix(l.Content, "\n")) + 1
353+ dv.codeWidth = max(dv.codeWidth, lineWidth, shownLines)
350354 }
351355 }
352356}
353357
354358func (dv *DiffView) convertDiffToSplit() {
359+ if dv.layout != layoutSplit {
360+ return
361+ }
362+
355363 dv.splitHunks = make([]splitHunk, len(dv.unified.Hunks))
356364 for i, h := range dv.unified.Hunks {
357365 dv.splitHunks[i] = hunkToSplit(h)
358366 }
359367}
360368
361−func (dv *DiffView) detectSplitWidth() {
362− if dv.width > 0 {
363− return
364− }
369+func (dv *DiffView) detectSplitCodeWidth() {
370+ dv.codeWidth = 0
365371
366372 for i, h := range dv.splitHunks {
367373 shownLines := ansi.StringWidth(dv.hunkLineFor(dv.unified.Hunks[i]))
368374
369375 for _, l := range h.lines {
370− var lineWidth int
371376 if l.before != nil {
372377 codeWidth := ansi.StringWidth(strings.TrimSuffix(l.before.Content, "\n")) + 1
373− dv.beforeCodeWidth = max(dv.beforeCodeWidth, codeWidth, shownLines)
374− lineWidth += codeWidth
378+ dv.codeWidth = max(dv.codeWidth, codeWidth, shownLines)
375379 }
376380 if l.after != nil {
377381 codeWidth := ansi.StringWidth(strings.TrimSuffix(l.after.Content, "\n")) + 1
378− dv.afterCodeWidth = max(dv.afterCodeWidth, codeWidth, shownLines)
379− lineWidth += codeWidth
382+ dv.codeWidth = max(dv.codeWidth, codeWidth, shownLines)
380383 }
381− lineWidth += leadingSymbolsSize * 2
382− dv.width = max(dv.width, lineWidth, shownLines)
383384 }
384385 }
385386}