@@ -2,13 +2,13 @@ package diffview
7 "github.com/aymanbagabas/go-udiff"
8 "github.com/aymanbagabas/go-udiff"
8 "github.com/aymanbagabas/go-udiff/myers"
9 "github.com/aymanbagabas/go-udiff/myers"
9 "github.com/charmbracelet/lipgloss/v2"
10 "github.com/charmbracelet/lipgloss/v2"
10 "github.com/charmbracelet/x/ansi"
11 "github.com/charmbracelet/x/ansi"
11− "github.com/charmbracelet/x/exp/charmtone"
14const leadingSymbolsSize = 2
14const leadingSymbolsSize = 2
@@ -25,71 +25,13 @@ const (
25 layoutSplit
25 layoutSplit
28−type LineStyle struct {
29− Symbol lipgloss.Style
39−var DefaultLightStyle = Style{
40− EqualLine: LineStyle{
41− Code: lipgloss.NewStyle().
42− Foreground(charmtone.Pepper).
43− Background(charmtone.Salt),
45− InsertLine: LineStyle{
46− Symbol: lipgloss.NewStyle().
47− Foreground(charmtone.Turtle).
48− Background(lipgloss.Color("#e8f5e9")),
49− Code: lipgloss.NewStyle().
50− Foreground(charmtone.Pepper).
51− Background(lipgloss.Color("#e8f5e9")),
53− DeleteLine: LineStyle{
54− Symbol: lipgloss.NewStyle().
55− Foreground(charmtone.Cherry).
56− Background(lipgloss.Color("#ffebee")),
57− Code: lipgloss.NewStyle().
58− Foreground(charmtone.Pepper).
59− Background(lipgloss.Color("#ffebee")),
63−var DefaultDarkStyle = Style{
64− EqualLine: LineStyle{
65− Code: lipgloss.NewStyle().
66− Foreground(charmtone.Salt).
67− Background(charmtone.Pepper),
69− InsertLine: LineStyle{
70− Symbol: lipgloss.NewStyle().
71− Foreground(charmtone.Turtle).
72− Background(lipgloss.Color("#303a30")),
73− Code: lipgloss.NewStyle().
74− Foreground(charmtone.Salt).
75− Background(lipgloss.Color("#303a30")),
77− DeleteLine: LineStyle{
78− Symbol: lipgloss.NewStyle().
79− Foreground(charmtone.Cherry).
80− Background(lipgloss.Color("#3a3030")),
81− Code: lipgloss.NewStyle().
82− Foreground(charmtone.Salt).
83− Background(lipgloss.Color("#3a3030")),
87// DiffView represents a view for displaying differences between two files.
28// DiffView represents a view for displaying differences between two files.
88type DiffView struct {
29type DiffView struct {
89 layout layout
30 layout layout
90 before file
31 before file
91 after file
32 after file
92 contextLines int
33 contextLines int
93 highlight bool
35 highlight bool
94 height int
36 height int
@@ -106,6 +48,7 @@ func New() *DiffView {
106 dv := &DiffView{
48 dv := &DiffView{
107 layout: layoutUnified,
49 layout: layoutUnified,
108 contextLines: udiff.DefaultContextLines,
50 contextLines: udiff.DefaultContextLines,
110 if lipgloss.HasDarkBackground(os.Stdin, os.Stdout) {
53 if lipgloss.HasDarkBackground(os.Stdin, os.Stdout) {
111 dv.style = DefaultDarkStyle
54 dv.style = DefaultDarkStyle
@@ -151,8 +94,14 @@ func (dv *DiffView) Style(style Style) *DiffView {
151 return dv
94 return dv
97+// LineNumbers sets whether to display line numbers in the DiffView.
98+func (dv *DiffView) LineNumbers(lineNumbers bool) *DiffView {
99+ dv.lineNumbers = lineNumbers
154−// SyntaxHighlight sets whether to enable syntax highlighting in the DiffView.
103+// SyntaxHightlight sets whether to enable syntax highlighting in the DiffView.
155−func (dv *DiffView) SyntaxHighlight(highlight bool) *DiffView {
104+func (dv *DiffView) SyntaxHightlight(highlight bool) *DiffView {
156 dv.highlight = highlight
105 dv.highlight = highlight
157 return dv
106 return dv
@@ -176,22 +125,48 @@ func (dv *DiffView) String() string {
177 dv.detectWidth()
126 dv.detectWidth()
128+ lineNumberWidth := func(start, num int) int {
129+ return len(strconv.Itoa(start + num))
179 var b strings.Builder
132 var b strings.Builder
181 for _, h := range dv.unified.Hunks {
134 for _, h := range dv.unified.Hunks {
135+ beforeLine := h.FromLine
136+ afterLine := h.ToLine
138+ beforeNumDigits := lineNumberWidth(h.FromLine, len(h.Lines))
139+ afterNumDigits := lineNumberWidth(h.ToLine, len(h.Lines))
182 for _, l := range h.Lines {
141 for _, l := range h.Lines {
183 content := strings.TrimSuffix(l.Content, "\n")
142 content := strings.TrimSuffix(l.Content, "\n")
184− width := dv.width - leadingSymbolsSize
143+ codeWidth := dv.width - leadingSymbolsSize
186 switch l.Kind {
145 switch l.Kind {
148+ b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(beforeLine, beforeNumDigits)))
149+ b.WriteString(dv.style.EqualLine.LineNumber.Render(pad(afterLine, afterNumDigits)))
151+ b.WriteString(dv.style.EqualLine.Code.Width(codeWidth + leadingSymbolsSize).Render(" " + content))
187 case udiff.Insert:
154 case udiff.Insert:
156+ b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(" ", beforeNumDigits)))
157+ b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(afterLine, afterNumDigits)))
188 b.WriteString(dv.style.InsertLine.Symbol.Render("+ "))
159 b.WriteString(dv.style.InsertLine.Symbol.Render("+ "))
189− b.WriteString(dv.style.InsertLine.Code.Width(width).Render(content))
160+ b.WriteString(dv.style.InsertLine.Code.Width(codeWidth).Render(content))
190 case udiff.Delete:
162 case udiff.Delete:
164+ b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(beforeLine, beforeNumDigits)))
165+ b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(" ", afterNumDigits)))
191 b.WriteString(dv.style.DeleteLine.Symbol.Render("- "))
167 b.WriteString(dv.style.DeleteLine.Symbol.Render("- "))
192− b.WriteString(dv.style.DeleteLine.Code.Width(width).Render(content))
168+ b.WriteString(dv.style.DeleteLine.Code.Width(codeWidth).Render(content))
193− case udiff.Equal:
169+ beforeLine++
194− b.WriteString(dv.style.EqualLine.Code.Width(width + leadingSymbolsSize).Render(" " + content))
196 b.WriteRune('\n')
171 b.WriteRune('\n')