@@ -39,6 +39,7 @@ type DiffView struct {
highlight bool
height int
width int
+ xOffset int
style Style
isComputed bool
@@ -130,6 +131,12 @@ func (dv *DiffView) Width(width int) *DiffView {
return dv
}
+// XOffset sets the horizontal offset for the DiffView.
+func (dv *DiffView) XOffset(xOffset int) *DiffView {
+ dv.xOffset = xOffset
+ return dv
+}
+
// String returns the string representation of the DiffView.
func (dv *DiffView) String() string {
if err := dv.computeDiff(); err != nil {
@@ -323,8 +330,11 @@ outer:
}
content := strings.TrimSuffix(l.Content, "\n")
+ content = ansi.GraphemeWidth.Cut(content, dv.xOffset, len(content))
content = ansi.Truncate(content, dv.codeWidth, "…")
+ leadingEllipsis := dv.xOffset > 0 && strings.TrimSpace(content) != ""
+
switch l.Kind {
case udiff.Equal:
if dv.lineNumbers {
@@ -332,7 +342,7 @@ outer:
b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(afterLine, dv.afterNumDigits)))
}
b.WriteString(fullContentStyle.Render(
- dv.style.EqualLine.Code.Width(dv.fullCodeWidth).Render(" " + content),
+ dv.style.EqualLine.Code.Width(dv.fullCodeWidth).Render(ternary(leadingEllipsis, " …", " ") + content),
))
beforeLine++
afterLine++
@@ -342,7 +352,7 @@ outer:
b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(afterLine, dv.afterNumDigits)))
}
b.WriteString(fullContentStyle.Render(
- dv.style.InsertLine.Symbol.Render("+ ") +
+ dv.style.InsertLine.Symbol.Render(ternary(leadingEllipsis, "+…", "+ ")) +
dv.style.InsertLine.Code.Width(dv.codeWidth).Render(content),
))
afterLine++
@@ -352,7 +362,7 @@ outer:
b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(" ", dv.afterNumDigits)))
}
b.WriteString(fullContentStyle.Render(
- dv.style.DeleteLine.Symbol.Render("- ") +
+ dv.style.DeleteLine.Symbol.Render(ternary(leadingEllipsis, "-…", "- ")) +
dv.style.DeleteLine.Code.Width(dv.codeWidth).Render(content),
))
beforeLine++
@@ -427,13 +437,18 @@ outer:
var afterContent string
if l.before != nil {
beforeContent = strings.TrimSuffix(l.before.Content, "\n")
+ beforeContent = ansi.GraphemeWidth.Cut(beforeContent, dv.xOffset, len(beforeContent))
beforeContent = ansi.Truncate(beforeContent, dv.codeWidth, "…")
}
if l.after != nil {
afterContent = strings.TrimSuffix(l.after.Content, "\n")
+ afterContent = ansi.GraphemeWidth.Cut(afterContent, dv.xOffset, len(afterContent))
afterContent = ansi.Truncate(afterContent, dv.codeWidth+btoi(dv.extraColOnAfter), "…")
}
+ leadingBeforeEllipsis := dv.xOffset > 0 && strings.TrimSpace(beforeContent) != ""
+ leadingAfterEllipsis := dv.xOffset > 0 && strings.TrimSpace(afterContent) != ""
+
switch {
case l.before == nil:
if dv.lineNumbers {
@@ -447,7 +462,7 @@ outer:
b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits)))
}
b.WriteString(beforeFullContentStyle.Render(
- dv.style.EqualLine.Code.Width(dv.fullCodeWidth).Render(" " + beforeContent),
+ dv.style.EqualLine.Code.Width(dv.fullCodeWidth).Render(ternary(leadingBeforeEllipsis, " …", " ") + beforeContent),
))
beforeLine++
case l.before.Kind == udiff.Delete:
@@ -455,7 +470,7 @@ outer:
b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(beforeLine, dv.beforeNumDigits)))
}
b.WriteString(beforeFullContentStyle.Render(
- dv.style.DeleteLine.Symbol.Render("- ") +
+ dv.style.DeleteLine.Symbol.Render(ternary(leadingBeforeEllipsis, "-…", "- ")) +
dv.style.DeleteLine.Code.Width(dv.codeWidth).Render(beforeContent),
))
beforeLine++
@@ -474,7 +489,7 @@ outer:
b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(afterLine, dv.afterNumDigits)))
}
b.WriteString(afterFullContentStyle.Render(
- dv.style.EqualLine.Code.Width(dv.fullCodeWidth + btoi(dv.extraColOnAfter)).Render(" " + afterContent),
+ dv.style.EqualLine.Code.Width(dv.fullCodeWidth + btoi(dv.extraColOnAfter)).Render(ternary(leadingAfterEllipsis, " …", " ") + afterContent),
))
afterLine++
case l.after.Kind == udiff.Insert:
@@ -482,7 +497,7 @@ outer:
b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(afterLine, dv.afterNumDigits)))
}
b.WriteString(afterFullContentStyle.Render(
- dv.style.InsertLine.Symbol.Render("+ ") +
+ dv.style.InsertLine.Symbol.Render(ternary(leadingAfterEllipsis, "+…", "+ ")) +
dv.style.InsertLine.Code.Width(dv.codeWidth+btoi(dv.extraColOnAfter)).Render(afterContent),
))
afterLine++
@@ -193,6 +193,29 @@ func TestDiffViewHeight(t *testing.T) {
}
}
+func TestDiffViewXOffset(t *testing.T) {
+ for layoutName, layoutFunc := range LayoutFuncs {
+ t.Run(layoutName, func(t *testing.T) {
+ for xOffset := range 21 {
+ t.Run(fmt.Sprintf("XOffsetOf%02d", xOffset), func(t *testing.T) {
+ dv := diffview.New().
+ Before("main.go", TestDefaultBefore).
+ After("main.go", TestDefaultAfter).
+ Style(diffview.DefaultLightStyle).
+ Width(60).
+ XOffset(xOffset)
+ dv = layoutFunc(dv)
+
+ output := dv.String()
+ golden.RequireEqual(t, []byte(output))
+
+ assertLineWidth(t, 60, output)
+ })
+ }
+ })
+ }
+}
+
func assertLineWidth(t *testing.T, expected int, output string) {
var lineWidth int
for line := range strings.SplitSeq(output, "\n") {