|
1 | 1 | package diffview |
2 | 2 |
|
3 | 3 | import ( |
4 | | - "bufio" |
5 | | - "strings" |
| 4 | + "bufio" |
| 5 | + "strings" |
6 | 6 | ) |
7 | 7 |
|
8 | 8 | // RowKind represents the semantic type of a side-by-side row. |
9 | 9 | type RowKind int |
10 | 10 |
|
11 | 11 | const ( |
12 | | - RowContext RowKind = iota |
13 | | - RowAdd |
14 | | - RowDel |
15 | | - RowReplace |
16 | | - RowHunk |
17 | | - RowMeta |
| 12 | + RowContext RowKind = iota |
| 13 | + RowAdd |
| 14 | + RowDel |
| 15 | + RowReplace |
| 16 | + RowHunk |
| 17 | + RowMeta |
18 | 18 | ) |
19 | 19 |
|
20 | 20 | // Row represents a single visual row for side-by-side rendering. |
21 | 21 | type Row struct { |
22 | | - Left string |
23 | | - Right string |
24 | | - Kind RowKind |
25 | | - Meta string // for hunk header text |
| 22 | + Left string |
| 23 | + Right string |
| 24 | + Kind RowKind |
| 25 | + Meta string // for hunk header text |
26 | 26 | } |
27 | 27 |
|
28 | 28 | // BuildRowsFromUnified parses a unified diff string into side-by-side rows. |
29 | 29 | // It uses a simple pairing strategy within each hunk: deletions are paired |
30 | 30 | // with subsequent additions as replacements; any remaining lines are shown |
31 | 31 | // as left-only (deletions) or right-only (additions). |
32 | 32 | func BuildRowsFromUnified(unified string) []Row { |
33 | | - s := bufio.NewScanner(strings.NewReader(unified)) |
34 | | - s.Buffer(make([]byte, 0, 64*1024), 10*1024*1024) // allow large lines |
| 33 | + s := bufio.NewScanner(strings.NewReader(unified)) |
| 34 | + s.Buffer(make([]byte, 0, 64*1024), 10*1024*1024) // allow large lines |
35 | 35 |
|
36 | | - rows := make([]Row, 0, 256) |
37 | | - pendingDel := make([]string, 0) |
| 36 | + rows := make([]Row, 0, 256) |
| 37 | + pendingDel := make([]string, 0) |
38 | 38 |
|
39 | | - flushPending := func() { |
40 | | - for _, dl := range pendingDel { |
41 | | - rows = append(rows, Row{Left: trimPrefix(dl), Right: "", Kind: RowDel}) |
42 | | - } |
43 | | - pendingDel = pendingDel[:0] |
44 | | - } |
| 39 | + flushPending := func() { |
| 40 | + for _, dl := range pendingDel { |
| 41 | + rows = append(rows, Row{Left: trimPrefix(dl), Right: "", Kind: RowDel}) |
| 42 | + } |
| 43 | + pendingDel = pendingDel[:0] |
| 44 | + } |
45 | 45 |
|
46 | | - inHunk := false |
47 | | - for s.Scan() { |
48 | | - line := s.Text() |
49 | | - if strings.HasPrefix(line, "diff --git ") || strings.HasPrefix(line, "index ") || strings.HasPrefix(line, "--- ") || strings.HasPrefix(line, "+++ ") { |
50 | | - // Metadata; flush any pending deletions |
51 | | - flushPending() |
52 | | - rows = append(rows, Row{Kind: RowMeta, Meta: line}) |
53 | | - continue |
54 | | - } |
55 | | - if strings.HasPrefix(line, "@@ ") { |
56 | | - flushPending() |
57 | | - rows = append(rows, Row{Kind: RowHunk, Meta: line}) |
58 | | - inHunk = true |
59 | | - continue |
60 | | - } |
61 | | - if !inHunk { |
62 | | - // Outside hunks, we don't have meaningful line-level info; skip |
63 | | - continue |
64 | | - } |
| 46 | + inHunk := false |
| 47 | + for s.Scan() { |
| 48 | + line := s.Text() |
| 49 | + if strings.HasPrefix(line, "diff --git ") || strings.HasPrefix(line, "index ") || strings.HasPrefix(line, "--- ") || strings.HasPrefix(line, "+++ ") { |
| 50 | + // Metadata; flush any pending deletions |
| 51 | + flushPending() |
| 52 | + rows = append(rows, Row{Kind: RowMeta, Meta: line}) |
| 53 | + continue |
| 54 | + } |
| 55 | + if strings.HasPrefix(line, "@@ ") { |
| 56 | + flushPending() |
| 57 | + rows = append(rows, Row{Kind: RowHunk, Meta: line}) |
| 58 | + inHunk = true |
| 59 | + continue |
| 60 | + } |
| 61 | + if !inHunk { |
| 62 | + // Outside hunks, we don't have meaningful line-level info; skip |
| 63 | + continue |
| 64 | + } |
65 | 65 |
|
66 | | - if len(line) == 0 { |
67 | | - // blank line inside hunk: treat as context |
68 | | - flushPending() |
69 | | - rows = append(rows, Row{Left: "", Right: "", Kind: RowContext}) |
70 | | - continue |
71 | | - } |
| 66 | + if len(line) == 0 { |
| 67 | + // blank line inside hunk: treat as context |
| 68 | + flushPending() |
| 69 | + rows = append(rows, Row{Left: "", Right: "", Kind: RowContext}) |
| 70 | + continue |
| 71 | + } |
72 | 72 |
|
73 | | - switch line[0] { |
74 | | - case ' ': |
75 | | - flushPending() |
76 | | - t := trimPrefix(line) |
77 | | - rows = append(rows, Row{Left: t, Right: t, Kind: RowContext}) |
78 | | - case '-': |
79 | | - pendingDel = append(pendingDel, line) |
80 | | - case '+': |
81 | | - if len(pendingDel) > 0 { |
82 | | - // Pair with the earliest pending deletion |
83 | | - dl := pendingDel[0] |
84 | | - pendingDel = pendingDel[1:] |
85 | | - rows = append(rows, Row{Left: trimPrefix(dl), Right: trimPrefix(line), Kind: RowReplace}) |
86 | | - } else { |
87 | | - rows = append(rows, Row{Left: "", Right: trimPrefix(line), Kind: RowAdd}) |
88 | | - } |
89 | | - default: |
90 | | - // Unknown line; ignore |
91 | | - } |
92 | | - } |
93 | | - flushPending() |
94 | | - return rows |
| 73 | + switch line[0] { |
| 74 | + case ' ': |
| 75 | + flushPending() |
| 76 | + t := trimPrefix(line) |
| 77 | + rows = append(rows, Row{Left: t, Right: t, Kind: RowContext}) |
| 78 | + case '-': |
| 79 | + pendingDel = append(pendingDel, line) |
| 80 | + case '+': |
| 81 | + if len(pendingDel) > 0 { |
| 82 | + // Pair with the earliest pending deletion |
| 83 | + dl := pendingDel[0] |
| 84 | + pendingDel = pendingDel[1:] |
| 85 | + rows = append(rows, Row{Left: trimPrefix(dl), Right: trimPrefix(line), Kind: RowReplace}) |
| 86 | + } else { |
| 87 | + rows = append(rows, Row{Left: "", Right: trimPrefix(line), Kind: RowAdd}) |
| 88 | + } |
| 89 | + default: |
| 90 | + // Unknown line; ignore |
| 91 | + } |
| 92 | + } |
| 93 | + flushPending() |
| 94 | + return rows |
95 | 95 | } |
96 | 96 |
|
97 | 97 | func trimPrefix(s string) string { |
98 | | - if s == "" { |
99 | | - return s |
100 | | - } |
101 | | - if s[0] == ' ' || s[0] == '+' || s[0] == '-' { |
102 | | - return s[1:] |
103 | | - } |
104 | | - return s |
| 98 | + if s == "" { |
| 99 | + return s |
| 100 | + } |
| 101 | + if s[0] == ' ' || s[0] == '+' || s[0] == '-' { |
| 102 | + return s[1:] |
| 103 | + } |
| 104 | + return s |
105 | 105 | } |
106 | | - |
0 commit comments