@@ -149,6 +149,40 @@ func (dv *DiffView) String() string {
152+// computeDiff computes the differences between the "before" and "after" files.
153+func (dv *DiffView) computeDiff() error {
157+ dv.isComputed = true
158+ dv.edits = myers.ComputeEdits( //nolint:staticcheck
162+ dv.unified, dv.err = udiff.ToUnifiedDiff(
172+// convertDiffToSplit converts the unified diff to a split diff if the layout is
174+func (dv *DiffView) convertDiffToSplit() {
175+ if dv.layout != layoutSplit {
179+ dv.splitHunks = make([]splitHunk, len(dv.unified.Hunks))
180+ for i, h := range dv.unified.Hunks {
181+ dv.splitHunks[i] = hunkToSplit(h)
185+// adjustStyles adjusts adds padding and alignment to the styles.
152func (dv *DiffView) adjustStyles() {
186func (dv *DiffView) adjustStyles() {
153 dv.style.MissingLine.LineNumber = setPadding(dv.style.MissingLine.LineNumber)
187 dv.style.MissingLine.LineNumber = setPadding(dv.style.MissingLine.LineNumber)
154 dv.style.DividerLine.LineNumber = setPadding(dv.style.DividerLine.LineNumber)
188 dv.style.DividerLine.LineNumber = setPadding(dv.style.DividerLine.LineNumber)
@@ -157,10 +191,69 @@ func (dv *DiffView) adjustStyles() {
157 dv.style.DeleteLine.LineNumber = setPadding(dv.style.DeleteLine.LineNumber)
191 dv.style.DeleteLine.LineNumber = setPadding(dv.style.DeleteLine.LineNumber)
194+// detectNumDigits calculates the maximum number of digits needed for before and
195+// after line numbers.
196+func (dv *DiffView) detectNumDigits() {
197+ dv.beforeNumDigits = 0
198+ dv.afterNumDigits = 0
200+ for _, h := range dv.unified.Hunks {
201+ dv.beforeNumDigits = max(dv.beforeNumDigits, len(strconv.Itoa(h.FromLine+len(h.Lines))))
202+ dv.afterNumDigits = max(dv.afterNumDigits, len(strconv.Itoa(h.ToLine+len(h.Lines))))
160func setPadding(s lipgloss.Style) lipgloss.Style {
206func setPadding(s lipgloss.Style) lipgloss.Style {
161 return s.Padding(0, lineNumPadding).Align(lipgloss.Right)
207 return s.Padding(0, lineNumPadding).Align(lipgloss.Right)
210+// detectCodeWidth calculates the maximum width of code lines in the diff view.
211+func (dv *DiffView) detectCodeWidth() {
214+ dv.detectUnifiedCodeWidth()
216+ dv.detectSplitCodeWidth()
218+ dv.fullCodeWidth = dv.codeWidth + leadingSymbolsSize
221+// detectUnifiedCodeWidth calculates the maximum width of code lines in a
223+func (dv *DiffView) detectUnifiedCodeWidth() {
226+ for _, h := range dv.unified.Hunks {
227+ shownLines := ansi.StringWidth(dv.hunkLineFor(h))
229+ for _, l := range h.Lines {
230+ lineWidth := ansi.StringWidth(strings.TrimSuffix(l.Content, "\n")) + 1
231+ dv.codeWidth = max(dv.codeWidth, lineWidth, shownLines)
236+// detectSplitCodeWidth calculates the maximum width of code lines in a
238+func (dv *DiffView) detectSplitCodeWidth() {
241+ for i, h := range dv.splitHunks {
242+ shownLines := ansi.StringWidth(dv.hunkLineFor(dv.unified.Hunks[i]))
244+ for _, l := range h.lines {
245+ if l.before != nil {
246+ codeWidth := ansi.StringWidth(strings.TrimSuffix(l.before.Content, "\n")) + 1
247+ dv.codeWidth = max(dv.codeWidth, codeWidth, shownLines)
250+ codeWidth := ansi.StringWidth(strings.TrimSuffix(l.after.Content, "\n")) + 1
251+ dv.codeWidth = max(dv.codeWidth, codeWidth, shownLines)
164// renderUnified renders the unified diff view as a string.
257// renderUnified renders the unified diff view as a string.
165func (dv *DiffView) renderUnified() string {
258func (dv *DiffView) renderUnified() string {
166 var b strings.Builder
259 var b strings.Builder
@@ -289,37 +382,7 @@ func (dv *DiffView) renderSplit() string {
289 return b.String()
382 return b.String()
292−func (dv *DiffView) computeDiff() error {
385+// hunkLineFor formats the header line for a hunk in the unified diff view.
296− dv.isComputed = true
297− dv.edits = myers.ComputeEdits( //nolint:staticcheck
301− dv.unified, dv.err = udiff.ToUnifiedDiff(
311−// detectNumDigits calculates the maximum number of digits needed for before and
312−// after line numbers.
313−func (dv *DiffView) detectNumDigits() {
314− dv.beforeNumDigits = 0
315− dv.afterNumDigits = 0
317− for _, h := range dv.unified.Hunks {
318− dv.beforeNumDigits = max(dv.beforeNumDigits, len(strconv.Itoa(h.FromLine+len(h.Lines))))
319− dv.afterNumDigits = max(dv.afterNumDigits, len(strconv.Itoa(h.ToLine+len(h.Lines))))
323func (dv *DiffView) hunkLineFor(h *udiff.Hunk) string {
386func (dv *DiffView) hunkLineFor(h *udiff.Hunk) string {
324 beforeShownLines, afterShownLines := dv.hunkShownLines(h)
387 beforeShownLines, afterShownLines := dv.hunkShownLines(h)
@@ -348,56 +411,3 @@ func (dv *DiffView) hunkShownLines(h *udiff.Hunk) (before, after int) {
352−func (dv *DiffView) detectCodeWidth() {
355− dv.detectUnifiedCodeWidth()
357− dv.detectSplitCodeWidth()
359− dv.fullCodeWidth = dv.codeWidth + leadingSymbolsSize
362−func (dv *DiffView) detectUnifiedCodeWidth() {
365− for _, h := range dv.unified.Hunks {
366− shownLines := ansi.StringWidth(dv.hunkLineFor(h))
368− for _, l := range h.Lines {
369− lineWidth := ansi.StringWidth(strings.TrimSuffix(l.Content, "\n")) + 1
370− dv.codeWidth = max(dv.codeWidth, lineWidth, shownLines)
375−func (dv *DiffView) convertDiffToSplit() {
376− if dv.layout != layoutSplit {
380− dv.splitHunks = make([]splitHunk, len(dv.unified.Hunks))
381− for i, h := range dv.unified.Hunks {
382− dv.splitHunks[i] = hunkToSplit(h)
386−func (dv *DiffView) detectSplitCodeWidth() {
389− for i, h := range dv.splitHunks {
390− shownLines := ansi.StringWidth(dv.hunkLineFor(dv.unified.Hunks[i]))
392− for _, l := range h.lines {
393− if l.before != nil {
394− codeWidth := ansi.StringWidth(strings.TrimSuffix(l.before.Content, "\n")) + 1
395− dv.codeWidth = max(dv.codeWidth, codeWidth, shownLines)
398− codeWidth := ansi.StringWidth(strings.TrimSuffix(l.after.Content, "\n")) + 1
399− dv.codeWidth = max(dv.codeWidth, codeWidth, shownLines)