diff --git a/internal/exp/diffview/Taskfile.yaml b/internal/exp/diffview/Taskfile.yaml index 50cb6a04600fcfc640a4910d5bd1b718984eecda..be40107e348a340eadffc7d7095c9535330faeca 100644 --- a/internal/exp/diffview/Taskfile.yaml +++ b/internal/exp/diffview/Taskfile.yaml @@ -40,3 +40,23 @@ tasks: - for: sources cmd: echo && echo "------- {{.ITEM}} -------" && echo && cat {{.ITEM}} silent: true + + test:print:height:unified: + desc: Print golden files for debugging + method: none + sources: + - ./testdata/TestDiffViewHeight/Unified/LightMode/*.golden + cmds: + - for: sources + cmd: echo && echo "------- {{.ITEM}} -------" && echo && cat {{.ITEM}} + silent: true + + test:print:height:split: + desc: Print golden files for debugging + method: none + sources: + - ./testdata/TestDiffViewHeight/Split/LightMode/*.golden + cmds: + - for: sources + cmd: echo && echo "------- {{.ITEM}} -------" && echo && cat {{.ITEM}} + silent: true diff --git a/internal/exp/diffview/diffview.go b/internal/exp/diffview/diffview.go index 7bc4206d969bb743f419949683f706c249e10c86..8776c90d5c07ee00d938a990f3a1382176451016 100644 --- a/internal/exp/diffview/diffview.go +++ b/internal/exp/diffview/diffview.go @@ -149,6 +149,9 @@ func (dv *DiffView) String() string { if dv.width > 0 { style = style.MaxWidth(dv.width) } + if dv.height > 0 { + style = style.MaxHeight(dv.height) + } switch dv.layout { case layoutUnified: @@ -287,6 +290,7 @@ func (dv *DiffView) renderUnified() string { var b strings.Builder fullContentStyle := lipgloss.NewStyle().MaxWidth(dv.fullCodeWidth) + printedLines := 0 for _, h := range dv.unified.Hunks { if dv.lineNumbers { @@ -296,6 +300,7 @@ func (dv *DiffView) renderUnified() string { content := ansi.Truncate(dv.hunkLineFor(h), dv.fullCodeWidth, "…") b.WriteString(dv.style.DividerLine.Code.Width(dv.fullCodeWidth).Render(content)) b.WriteRune('\n') + printedLines++ beforeLine := h.FromLine afterLine := h.ToLine @@ -337,7 +342,19 @@ func (dv *DiffView) renderUnified() string { beforeLine++ } b.WriteRune('\n') + + printedLines++ + } + } + + for printedLines < dv.height { + if dv.lineNumbers { + b.WriteString(dv.style.MissingLine.LineNumber.Render(pad(" ", dv.beforeNumDigits))) + b.WriteString(dv.style.MissingLine.LineNumber.Render(pad(" ", dv.afterNumDigits))) } + b.WriteString(dv.style.MissingLine.Code.Width(dv.fullCodeWidth).Render(" ")) + b.WriteRune('\n') + printedLines++ } return b.String() @@ -349,6 +366,7 @@ func (dv *DiffView) renderSplit() string { beforeFullContentStyle := lipgloss.NewStyle().MaxWidth(dv.fullCodeWidth) afterFullContentStyle := lipgloss.NewStyle().MaxWidth(dv.fullCodeWidth + btoi(dv.extraColOnAfter)) + printedLines := 0 for i, h := range dv.splitHunks { if dv.lineNumbers { @@ -361,6 +379,7 @@ func (dv *DiffView) renderSplit() string { } b.WriteString(dv.style.DividerLine.Code.Width(dv.fullCodeWidth + btoi(dv.extraColOnAfter)).Render(" ")) b.WriteRune('\n') + printedLines++ beforeLine := h.fromLine afterLine := h.toLine @@ -432,9 +451,24 @@ func (dv *DiffView) renderSplit() string { } b.WriteRune('\n') + + printedLines++ } } + for printedLines < dv.height { + if dv.lineNumbers { + b.WriteString(dv.style.MissingLine.LineNumber.Render(pad("…", dv.beforeNumDigits))) + } + b.WriteString(dv.style.MissingLine.Code.Width(dv.fullCodeWidth).Render(" ")) + if dv.lineNumbers { + b.WriteString(dv.style.MissingLine.LineNumber.Render(pad("…", dv.afterNumDigits))) + } + b.WriteString(dv.style.MissingLine.Code.Width(dv.fullCodeWidth + btoi(dv.extraColOnAfter)).Render(" ")) + b.WriteRune('\n') + printedLines++ + } + return b.String() } diff --git a/internal/exp/diffview/diffview_test.go b/internal/exp/diffview/diffview_test.go index c26e89c58194f43725f05096cc4ee5e3afa2ae25..fbf2661ccd269ed71aa40d46333ba5594df9078d 100644 --- a/internal/exp/diffview/diffview_test.go +++ b/internal/exp/diffview/diffview_test.go @@ -167,6 +167,32 @@ func TestDiffViewWidth(t *testing.T) { } } +func TestDiffViewHeight(t *testing.T) { + for layoutName, layoutFunc := range LayoutFuncs { + t.Run(layoutName, func(t *testing.T) { + for themeName, themeFunc := range ThemeFuncs { + t.Run(themeName, func(t *testing.T) { + for height := 1; height <= 20; height++ { + t.Run(fmt.Sprintf("HeightOf%03d", height), func(t *testing.T) { + dv := diffview.New(). + Before("main.go", TestMultipleHunksBefore). + After("main.go", TestMultipleHunksAfter). + Height(height) + dv = layoutFunc(dv) + dv = themeFunc(dv) + + output := dv.String() + golden.RequireEqual(t, []byte(output)) + + assertHeight(t, height, output) + }) + } + }) + } + }) + } +} + func assertLineWidth(t *testing.T, expected int, output string) { var lineWidth int for line := range strings.SplitSeq(output, "\n") { @@ -176,3 +202,11 @@ func assertLineWidth(t *testing.T, expected int, output string) { t.Errorf("expected output width to be == %d, got %d", expected, lineWidth) } } + +func assertHeight(t *testing.T, expected int, output string) { + output = strings.TrimSuffix(output, "\n") + lines := strings.Count(output, "\n") + 1 + if lines != expected { + t.Errorf("expected output height to be == %d, got %d", expected, lines) + } +}