fix(diffview): fix diffview width when code is too narrow

Andrey Nering created

Change summary

internal/exp/diffview/diffview.go                                      | 31 
internal/exp/diffview/diffview_test.go                                 | 22 
internal/exp/diffview/testdata/TestCustomContextLines/DarkMode.golden  |  2 
internal/exp/diffview/testdata/TestCustomContextLines/LightMode.golden |  2 
internal/exp/diffview/testdata/TestDefault/DarkMode.golden             |  2 
internal/exp/diffview/testdata/TestDefault/LightMode.golden            |  2 
internal/exp/diffview/testdata/TestMultipleHunks/DarkMode.golden       |  4 
internal/exp/diffview/testdata/TestMultipleHunks/LightMode.golden      |  4 
internal/exp/diffview/testdata/TestNarrow.after                        |  3 
internal/exp/diffview/testdata/TestNarrow.before                       |  3 
internal/exp/diffview/testdata/TestNarrow/DarkMode.golden              |  7 
internal/exp/diffview/testdata/TestNarrow/LightMode.golden             |  7 
internal/exp/diffview/testdata/TestNoLineNumbers/DarkMode.golden       |  2 
internal/exp/diffview/testdata/TestNoLineNumbers/LightMode.golden      |  2 
14 files changed, 70 insertions(+), 23 deletions(-)

Detailed changes

internal/exp/diffview/diffview.go šŸ”—

@@ -132,21 +132,11 @@ func (dv *DiffView) String() string {
 	var b strings.Builder
 
 	for i, h := range dv.unified.Hunks {
-		beforeShownLines, afterShownLines := dv.hunkShownLines(i)
-
 		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.Code.Width(codeWidth + leadingSymbolsSize).Render(
-			fmt.Sprintf(
-				"  @@ -%d,%d +%d,%d @@",
-				h.FromLine,
-				beforeShownLines,
-				h.ToLine,
-				afterShownLines,
-			),
-		))
+		b.WriteString(dv.style.DividerLine.Code.Width(codeWidth + leadingSymbolsSize).Render(dv.hunkLineFor(i)))
 		b.WriteRune('\n')
 
 		beforeLine := h.FromLine
@@ -217,6 +207,19 @@ func (dv *DiffView) lineNumberDigits() (maxBefore, maxAfter int) {
 	return
 }
 
+func (dv *DiffView) hunkLineFor(i int) string {
+	h := dv.unified.Hunks[i]
+	beforeShownLines, afterShownLines := dv.hunkShownLines(i)
+
+	return fmt.Sprintf(
+		"  @@ -%d,%d +%d,%d @@ ",
+		h.FromLine,
+		beforeShownLines,
+		h.ToLine,
+		afterShownLines,
+	)
+}
+
 // hunkShownLines calculates the number of lines shown in a hunk for both before
 // and after versions.
 func (dv *DiffView) hunkShownLines(i int) (before, after int) {
@@ -239,11 +242,13 @@ func (dv *DiffView) detectWidth() {
 		return
 	}
 
-	for _, h := range dv.unified.Hunks {
+	for i, h := range dv.unified.Hunks {
+		shownLines := ansi.StringWidth(dv.hunkLineFor(i))
+
 		for _, l := range h.Lines {
 			lineWidth := ansi.StringWidth(strings.TrimSuffix(l.Content, "\n"))
 			lineWidth += leadingSymbolsSize
-			dv.width = max(dv.width, lineWidth)
+			dv.width = max(dv.width, lineWidth, shownLines)
 		}
 	}
 }

internal/exp/diffview/diffview_test.go šŸ”—

@@ -20,6 +20,12 @@ var TestMultipleHunksBefore string
 //go:embed testdata/TestMultipleHunks.after
 var TestMultipleHunksAfter string
 
+//go:embed testdata/TestNarrow.before
+var TestNarrowBefore string
+
+//go:embed testdata/TestNarrow.after
+var TestNarrowAfter string
+
 func TestDefault(t *testing.T) {
 	dv := diffview.New().
 		Before("main.go", TestDefaultBefore).
@@ -85,3 +91,19 @@ func TestCustomContextLines(t *testing.T) {
 		golden.RequireEqual(t, []byte(dv.String()))
 	})
 }
+
+func TestNarrow(t *testing.T) {
+	dv := diffview.New().
+		Before("text.txt", TestNarrowBefore).
+		After("text.txt", TestNarrowAfter)
+
+	t.Run("LightMode", func(t *testing.T) {
+		dv = dv.Style(diffview.DefaultLightStyle)
+		golden.RequireEqual(t, []byte(dv.String()))
+	})
+
+	t.Run("DarkMode", func(t *testing.T) {
+		dv = dv.Style(diffview.DefaultDarkStyle)
+		golden.RequireEqual(t, []byte(dv.String()))
+	})
+}

internal/exp/diffview/testdata/TestCustomContextLines/DarkMode.golden šŸ”—

@@ -1,4 +1,4 @@
-Ā  …Ā Ā  …Ā   @@ -1,13 +1,15 @@                              
+Ā  …Ā Ā  …Ā   @@ -1,13 +1,15 @@                              
 Ā  1Ā Ā  1Ā   package main                                   
 Ā  2Ā Ā  2Ā                                                  
 Ā  3Ā Ā  3Ā   import (                                       

internal/exp/diffview/testdata/TestCustomContextLines/LightMode.golden šŸ”—

@@ -1,4 +1,4 @@
-Ā  …Ā Ā  …Ā   @@ -1,13 +1,15 @@                              
+Ā  …Ā Ā  …Ā   @@ -1,13 +1,15 @@                              
 Ā  1Ā Ā  1Ā   package main                                   
 Ā  2Ā Ā  2Ā                                                  
 Ā  3Ā Ā  3Ā   import (                                       

internal/exp/diffview/testdata/TestDefault/DarkMode.golden šŸ”—

@@ -1,4 +1,4 @@
-Ā  …Ā Ā  …Ā   @@ -5,5 +5,6 @@                 
+Ā  …Ā Ā  …Ā   @@ -5,5 +5,6 @@                 
 Ā  5Ā Ā  5Ā   )                               
 Ā  6Ā Ā  6Ā                                   
 Ā  7Ā Ā  7Ā   func main() {                   

internal/exp/diffview/testdata/TestDefault/LightMode.golden šŸ”—

@@ -1,4 +1,4 @@
-Ā  …Ā Ā  …Ā   @@ -5,5 +5,6 @@                 
+Ā  …Ā Ā  …Ā   @@ -5,5 +5,6 @@                 
 Ā  5Ā Ā  5Ā   )                               
 Ā  6Ā Ā  6Ā                                   
 Ā  7Ā Ā  7Ā   func main() {                   

internal/exp/diffview/testdata/TestMultipleHunks/DarkMode.golden šŸ”—

@@ -1,4 +1,4 @@
-Ā  …Ā Ā  …Ā   @@ -2,6 +2,7 @@                                
+Ā  …Ā Ā  …Ā   @@ -2,6 +2,7 @@                                
 Ā  2Ā Ā  2Ā                                                  
 Ā  3Ā Ā  3Ā   import (                                       
 Ā  4Ā Ā  4Ā       "fmt"                                      
@@ -6,7 +6,7 @@
 Ā  5Ā Ā  6Ā   )                                              
 Ā  6Ā Ā  7Ā                                                  
 Ā  7Ā Ā  8Ā   func main() {                                  
-Ā  …Ā Ā  …Ā   @@ -9,5 +10,6 @@                               
+Ā  …Ā Ā  …Ā   @@ -9,5 +10,6 @@                               
 Ā  9Ā Ā 10Ā   }                                              
 Ā 10Ā Ā 11Ā                                                  
 Ā 11Ā Ā 12Ā   func getContent() string {                     

internal/exp/diffview/testdata/TestMultipleHunks/LightMode.golden šŸ”—

@@ -1,4 +1,4 @@
-Ā  …Ā Ā  …Ā   @@ -2,6 +2,7 @@                                
+Ā  …Ā Ā  …Ā   @@ -2,6 +2,7 @@                                
 Ā  2Ā Ā  2Ā                                                  
 Ā  3Ā Ā  3Ā   import (                                       
 Ā  4Ā Ā  4Ā       "fmt"                                      
@@ -6,7 +6,7 @@
 Ā  5Ā Ā  6Ā   )                                              
 Ā  6Ā Ā  7Ā                                                  
 Ā  7Ā Ā  8Ā   func main() {                                  
-Ā  …Ā Ā  …Ā   @@ -9,5 +10,6 @@                               
+Ā  …Ā Ā  …Ā   @@ -9,5 +10,6 @@                               
 Ā  9Ā Ā 10Ā   }                                              
 Ā 10Ā Ā 11Ā                                                  
 Ā 11Ā Ā 12Ā   func getContent() string {                     

internal/exp/diffview/testdata/TestNarrow/DarkMode.golden šŸ”—

@@ -0,0 +1,7 @@
+Ā …Ā Ā …Ā   @@ -1,3 +1,3 @@ 
+Ā 1Ā Ā  Ā - a               
+Ā 2Ā Ā  Ā - b               
+Ā 3Ā Ā  Ā - c               
+Ā  Ā Ā 1Ā + d               
+Ā  Ā Ā 2Ā + e               
+Ā  Ā Ā 3Ā + f               

internal/exp/diffview/testdata/TestNarrow/LightMode.golden šŸ”—

@@ -0,0 +1,7 @@
+Ā …Ā Ā …Ā   @@ -1,3 +1,3 @@ 
+Ā 1Ā Ā  Ā - a               
+Ā 2Ā Ā  Ā - b               
+Ā 3Ā Ā  Ā - c               
+Ā  Ā Ā 1Ā + d               
+Ā  Ā Ā 2Ā + e               
+Ā  Ā Ā 3Ā + f               

internal/exp/diffview/testdata/TestNoLineNumbers/DarkMode.golden šŸ”—

@@ -1,4 +1,4 @@
-  @@ -5,5 +5,6 @@                 
+  @@ -5,5 +5,6 @@                 
   )                               
                                   
   func main() {                   

internal/exp/diffview/testdata/TestNoLineNumbers/LightMode.golden šŸ”—

@@ -1,4 +1,4 @@
-  @@ -5,5 +5,6 @@                 
+  @@ -5,5 +5,6 @@                 
   )                               
                                   
   func main() {