-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdiff.go
More file actions
115 lines (106 loc) · 3.7 KB
/
Copy pathdiff.go
File metadata and controls
115 lines (106 loc) · 3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package main
import (
"fmt"
"strings"
"charm.land/lipgloss/v2"
)
// renderDiffPanel renders a unified-diff string as a colorized panel with a dim
// left `│` rule, mirroring renderOutputPanel's truncation + expand semantics:
// the first headLines raw diff lines are shown unless `expanded`; a dim hint
// line offers the ctrl+o toggle. A one-line dim file header is extracted from a
// `+++ b/<path>` marker when present (always shown, not counted toward the
// limit).
//
// Each diff line is classified by its leading marker and styled via the theme:
// - (not "+++ ") -> added (green)
// - (not "--- ") -> removed (red)
// "@@", "--- ", "+++ ", "diff --git", "\ " (no-newline marker) -> meta (cyan)
// everything else -> context (dim)
//
// Lines are wrapped to the panel width on their RAW text before styling so the
// per-line style's ANSI escapes can't corrupt the rune-counted wrap.
func renderDiffPanel(diff string, expanded bool, w int, toggleHint ...string) string {
const headLines = 3
toggle := "ctrl+o"
if len(toggleHint) > 0 && strings.TrimSpace(toggleHint[0]) != "" {
toggle = toggleHint[0]
}
diff = strings.TrimSpace(diff)
if diff == "" {
return ""
}
rawLines := strings.Split(diff, "\n")
// Optional one-line file header drawn from a "+++ b/<path>" marker.
header := ""
for _, l := range rawLines {
if strings.HasPrefix(l, "+++ ") {
p := strings.TrimSpace(strings.TrimPrefix(l, "+++ "))
p = strings.TrimPrefix(p, "b/")
if p != "" && p != "/dev/null" {
header = p
}
break
}
}
contentW := w - 3 // "│ " prefix + content
if contentW < 2 {
contentW = 2
}
rule := mutedStyle.Render("│ ")
// emitRow wraps a raw line to the panel width and writes a rule + styled
// piece per wrapped row. Wrapping runs on the raw text (before styling) so
// the style's ANSI escapes can't skew the rune-counted wrap.
emitRow := func(line string, st lipgloss.Style, b *strings.Builder) {
for _, piece := range wrapLine(line, contentW) {
b.WriteString(rule)
b.WriteString(st.Render(piece))
b.WriteByte('\n')
}
}
// panelBody renders the given raw diff lines (already truncated if needed)
// plus the optional file header, as rule-prefixed rows.
panelBody := func(lines []string) string {
var b strings.Builder
if header != "" {
emitRow("◆ "+header, mutedStyle, &b)
}
for _, l := range lines {
emitRow(l, diffLineStyle(l), &b)
}
return strings.TrimRight(b.String(), "\n")
}
// Truncation mirrors renderOutputPanel: first headLines raw lines unless
// expanded, with a dim hint offering the ctrl+o toggle.
if len(rawLines) > headLines && !expanded {
more := len(rawLines) - headLines
panel := panelBody(rawLines[:headLines])
hint := mutedStyle.Italic(true).Render(
fmt.Sprintf("│ … +%d line%s (%s expand)", more, pluralS(more), toggle))
return panel + "\n" + hint
}
panel := panelBody(rawLines)
if len(rawLines) > headLines && expanded {
panel += "\n" + mutedStyle.Italic(true).Render("│ ("+toggle+" collapse)")
}
return panel
}
// diffLineStyle classifies a unified-diff line by its leading marker and
// returns the matching theme style. The meta markers ("+++ ", "--- ", "@@",
// "diff --git", "\ ") are checked before the bare "+"/"-" cases so a file
// header line is never misclassified as an added/removed line.
func diffLineStyle(line string) lipgloss.Style {
switch {
case strings.HasPrefix(line, "+++ "),
strings.HasPrefix(line, "--- "),
strings.HasPrefix(line, "diff --git"),
strings.HasPrefix(line, "@@"),
strings.HasPrefix(line, "\\ "):
return toolDiffMeta
case strings.HasPrefix(line, "+"):
return toolDiffAdded
case strings.HasPrefix(line, "-"):
return toolDiffRemoved
default:
return toolDiffContext
}
}