8 "github.com/aymanbagabas/go-udiff"
9 "github.com/aymanbagabas/go-udiff/myers"
10 "github.com/charmbracelet/lipgloss/v2"
11 "github.com/charmbracelet/x/ansi"
14const leadingSymbolsSize = 2
24 layoutUnified layout = iota + 1
28// DiffView represents a view for displaying differences between two files.
42 unified udiff.UnifiedDiff
46// New creates a new DiffView with default settings.
49 layout: layoutUnified,
50 contextLines: udiff.DefaultContextLines,
53 if lipgloss.HasDarkBackground(os.Stdin, os.Stdout) {
54 dv.style = DefaultDarkStyle
56 dv.style = DefaultLightStyle
61// Unified sets the layout of the DiffView to unified.
62func (dv *DiffView) Unified() *DiffView {
63 dv.layout = layoutUnified
67// Split sets the layout of the DiffView to split (side-by-side).
68func (dv *DiffView) Split() *DiffView {
69 dv.layout = layoutSplit
73// Before sets the "before" file for the DiffView.
74func (dv *DiffView) Before(path, content string) *DiffView {
75 dv.before = file{path: path, content: content}
79// After sets the "after" file for the DiffView.
80func (dv *DiffView) After(path, content string) *DiffView {
81 dv.after = file{path: path, content: content}
85// ContextLines sets the number of context lines for the DiffView.
86func (dv *DiffView) ContextLines(contextLines int) *DiffView {
87 dv.contextLines = contextLines
91// Style sets the style for the DiffView.
92func (dv *DiffView) Style(style Style) *DiffView {
97// LineNumbers sets whether to display line numbers in the DiffView.
98func (dv *DiffView) LineNumbers(lineNumbers bool) *DiffView {
99 dv.lineNumbers = lineNumbers
103// SyntaxHightlight sets whether to enable syntax highlighting in the DiffView.
104func (dv *DiffView) SyntaxHightlight(highlight bool) *DiffView {
105 dv.highlight = highlight
109// Height sets the height of the DiffView.
110func (dv *DiffView) Height(height int) *DiffView {
115// Width sets the width of the DiffView.
116func (dv *DiffView) Width(width int) *DiffView {
121// String returns the string representation of the DiffView.
122func (dv *DiffView) String() string {
123 if err := dv.computeDiff(); err != nil {
128 lineNumberWidth := func(start, num int) int {
129 return len(strconv.Itoa(start + num))
132 var b strings.Builder
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))
141 for _, l := range h.Lines {
142 content := strings.TrimSuffix(l.Content, "\n")
143 codeWidth := dv.width - leadingSymbolsSize
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))
156 b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(" ", beforeNumDigits)))
157 b.WriteString(dv.style.InsertLine.LineNumber.Render(pad(afterLine, afterNumDigits)))
159 b.WriteString(dv.style.InsertLine.Symbol.Render("+ "))
160 b.WriteString(dv.style.InsertLine.Code.Width(codeWidth).Render(content))
164 b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(beforeLine, beforeNumDigits)))
165 b.WriteString(dv.style.DeleteLine.LineNumber.Render(pad(" ", afterNumDigits)))
167 b.WriteString(dv.style.DeleteLine.Symbol.Render("- "))
168 b.WriteString(dv.style.DeleteLine.Code.Width(codeWidth).Render(content))
178func (dv *DiffView) computeDiff() error {
183 dv.edits = myers.ComputeEdits(
187 dv.unified, dv.err = udiff.ToUnifiedDiff(
197func (dv *DiffView) detectWidth() {
202 for _, h := range dv.unified.Hunks {
203 for _, l := range h.Lines {
204 lineWidth := ansi.StringWidth(strings.TrimSuffix(l.Content, "\n"))
205 lineWidth += leadingSymbolsSize
206 dv.width = max(dv.width, lineWidth)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list