1package diffview
2
3import (
4 "github.com/aymanbagabas/go-udiff"
5 "github.com/aymanbagabas/go-udiff/myers"
6 "github.com/charmbracelet/lipgloss/v2"
7)
8
9type file struct {
10 path string
11 content string
12}
13
14type layout int
15
16const (
17 layoutUnified layout = iota + 1
18 layoutSplit
19)
20
21// DiffView represents a view for displaying differences between two files.
22type DiffView struct {
23 layout layout
24 before file
25 after file
26 contextLines int
27 baseStyle lipgloss.Style
28 highlight bool
29 height int
30 width int
31
32 isComputed bool
33 err error
34 unified udiff.UnifiedDiff
35 edits []udiff.Edit
36}
37
38// New creates a new DiffView with default settings.
39func New() *DiffView {
40 return &DiffView{
41 layout: layoutUnified,
42 contextLines: udiff.DefaultContextLines,
43 }
44}
45
46// Unified sets the layout of the DiffView to unified.
47func (dv *DiffView) Unified() *DiffView {
48 dv.layout = layoutUnified
49 return dv
50}
51
52// Split sets the layout of the DiffView to split (side-by-side).
53func (dv *DiffView) Split() *DiffView {
54 dv.layout = layoutSplit
55 return dv
56}
57
58// Before sets the "before" file for the DiffView.
59func (dv *DiffView) Before(path, content string) *DiffView {
60 dv.before = file{path: path, content: content}
61 return dv
62}
63
64// After sets the "after" file for the DiffView.
65func (dv *DiffView) After(path, content string) *DiffView {
66 dv.after = file{path: path, content: content}
67 return dv
68}
69
70// ContextLines sets the number of context lines for the DiffView.
71func (dv *DiffView) ContextLines(contextLines int) *DiffView {
72 dv.contextLines = contextLines
73 return dv
74}
75
76// BaseStyle sets the base style for the DiffView.
77// This is useful for setting a custom background color, for example.
78func (dv *DiffView) BaseStyle(baseStyle lipgloss.Style) *DiffView {
79 dv.baseStyle = baseStyle
80 return dv
81}
82
83// SyntaxHighlight sets whether to enable syntax highlighting in the DiffView.
84func (dv *DiffView) SyntaxHighlight(highlight bool) *DiffView {
85 dv.highlight = highlight
86 return dv
87}
88
89// Height sets the height of the DiffView.
90func (dv *DiffView) Height(height int) *DiffView {
91 dv.height = height
92 return dv
93}
94
95// Width sets the width of the DiffView.
96func (dv *DiffView) Width(width int) *DiffView {
97 dv.width = width
98 return dv
99}
100
101// String returns the string representation of the DiffView.
102func (dv *DiffView) String() string {
103 if !dv.isComputed {
104 dv.compute()
105 }
106 if dv.err != nil {
107 return dv.err.Error()
108 }
109 return dv.unified.String()
110}
111
112func (dv *DiffView) compute() {
113 dv.isComputed = true
114 dv.edits = myers.ComputeEdits(
115 dv.before.content,
116 dv.after.content,
117 )
118 dv.unified, dv.err = udiff.ToUnifiedDiff(
119 dv.before.path,
120 dv.after.path,
121 dv.before.content,
122 dv.edits,
123 dv.contextLines,
124 )
125}