Skip to content

Commit 37c2f14

Browse files
committed
diff, textdiff: add position information to Edits
Also rename fields in textdiff to use LineNo instead of Pos to disambiguate the meaning.
1 parent 08061d0 commit 37c2f14

4 files changed

Lines changed: 293 additions & 257 deletions

File tree

diff.go

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,16 @@ const (
3535

3636
// Edit describes a single edit of a diff.
3737
//
38-
// - For Match, both X and Y contain the matching element.
39-
// - For Delete, X contains the deleted element and Y is unset (zero value).
40-
// - For Insert, Y contains the inserted element and X is unset (zero value).
38+
// - For Match, both X and Y contain the matching element. PosX and PosY contain their respective
39+
// positions in the input.
40+
// - For Delete, X contains the deleted element and Y is unset (zero value). PosX contains its
41+
// position in the input and PosY is -1.
42+
// - For Insert, Y contains the inserted element and X is unset (zero value). PosY contains its
43+
// position in the input and PosX is -1.
4144
type Edit[T any] struct {
42-
Op Op
43-
X, Y T
45+
Op Op
46+
PosX, PosY int
47+
X, Y T
4448
}
4549

4650
// Hunk describes a sequence of consecutive edits.
@@ -108,23 +112,29 @@ func hunks[T any](x, y []T, rx, ry []bool, cfg config.Config) []Hunk[T] {
108112
for s, t := hunk.S0, hunk.T0; s < hunk.S1 || t < hunk.T1; {
109113
for s < hunk.S1 && rx[s] {
110114
eout = append(eout, Edit[T]{
111-
Op: Delete,
112-
X: x[s],
115+
Op: Delete,
116+
X: x[s],
117+
PosX: s,
118+
PosY: -1,
113119
})
114120
s++
115121
}
116122
for t < hunk.T1 && ry[t] {
117123
eout = append(eout, Edit[T]{
118-
Op: Insert,
119-
Y: y[t],
124+
Op: Insert,
125+
Y: y[t],
126+
PosX: -1,
127+
PosY: t,
120128
})
121129
t++
122130
}
123131
for s < hunk.S1 && t < hunk.T1 && !rx[s] && !ry[t] {
124132
eout = append(eout, Edit[T]{
125-
Op: Match,
126-
X: x[s],
127-
Y: y[t],
133+
Op: Match,
134+
X: x[s],
135+
Y: y[t],
136+
PosX: s,
137+
PosY: t,
128138
})
129139
s++
130140
t++
@@ -204,23 +214,29 @@ func edits[T any](x, y []T, rx, ry []bool) []Edit[T] {
204214
for s, t := 0, 0; s < n || t < m; {
205215
for s < n && rx[s] {
206216
eout = append(eout, Edit[T]{
207-
Op: Delete,
208-
X: x[s],
217+
Op: Delete,
218+
X: x[s],
219+
PosX: s,
220+
PosY: -1,
209221
})
210222
s++
211223
}
212224
for t < m && ry[t] {
213225
eout = append(eout, Edit[T]{
214-
Op: Insert,
215-
Y: y[t],
226+
Op: Insert,
227+
Y: y[t],
228+
PosX: -1,
229+
PosY: t,
216230
})
217231
t++
218232
}
219233
for s < n && t < m && !rx[s] && !ry[t] {
220234
eout = append(eout, Edit[T]{
221-
Op: Match,
222-
X: x[s],
223-
Y: y[t],
235+
Op: Match,
236+
X: x[s],
237+
Y: y[t],
238+
PosX: s,
239+
PosY: t,
224240
})
225241
s++
226242
t++

diff_test.go

Lines changed: 75 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ func TestHunks(t *testing.T) {
5454
EndX: 0,
5555
EndY: 3,
5656
Edits: []Edit[string]{
57-
{Insert, "", "foo"},
58-
{Insert, "", "bar"},
59-
{Insert, "", "baz"},
57+
{Insert, -1, 0, "", "foo"},
58+
{Insert, -1, 1, "", "bar"},
59+
{Insert, -1, 2, "", "baz"},
6060
},
6161
},
6262
},
@@ -72,9 +72,9 @@ func TestHunks(t *testing.T) {
7272
EndX: 3,
7373
EndY: 0,
7474
Edits: []Edit[string]{
75-
{Delete, "foo", ""},
76-
{Delete, "bar", ""},
77-
{Delete, "baz", ""},
75+
{Delete, 0, -1, "foo", ""},
76+
{Delete, 1, -1, "bar", ""},
77+
{Delete, 2, -1, "baz", ""},
7878
},
7979
},
8080
},
@@ -90,9 +90,9 @@ func TestHunks(t *testing.T) {
9090
PosY: 0,
9191
EndY: 2,
9292
Edits: []Edit[string]{
93-
{Match, "foo", "foo"},
94-
{Delete, "bar", ""},
95-
{Insert, "", "baz"},
93+
{Match, 0, 0, "foo", "foo"},
94+
{Delete, 1, -1, "bar", ""},
95+
{Insert, -1, 1, "", "baz"},
9696
},
9797
},
9898
},
@@ -108,9 +108,9 @@ func TestHunks(t *testing.T) {
108108
PosY: 0,
109109
EndY: 2,
110110
Edits: []Edit[string]{
111-
{Delete, "foo", ""},
112-
{Insert, "", "loo"},
113-
{Match, "bar", "bar"},
111+
{Delete, 0, -1, "foo", ""},
112+
{Insert, -1, 0, "", "loo"},
113+
{Match, 1, 1, "bar", "bar"},
114114
},
115115
},
116116
},
@@ -126,15 +126,15 @@ func TestHunks(t *testing.T) {
126126
EndX: 7,
127127
EndY: 6,
128128
Edits: []Edit[string]{
129-
{Delete, "A", ""},
130-
{Insert, "", "C"},
131-
{Match, "B", "B"},
132-
{Delete, "C", ""},
133-
{Match, "A", "A"},
134-
{Match, "B", "B"},
135-
{Delete, "B", ""},
136-
{Match, "A", "A"},
137-
{Insert, "", "C"},
129+
{Delete, 0, -1, "A", ""},
130+
{Insert, -1, 0, "", "C"},
131+
{Match, 1, 1, "B", "B"},
132+
{Delete, 2, -1, "C", ""},
133+
{Match, 3, 2, "A", "A"},
134+
{Match, 4, 3, "B", "B"},
135+
{Delete, 5, -1, "B", ""},
136+
{Match, 6, 4, "A", "A"},
137+
{Insert, -1, 5, "", "C"},
138138
},
139139
},
140140
},
@@ -151,8 +151,8 @@ func TestHunks(t *testing.T) {
151151
EndX: 1,
152152
EndY: 1,
153153
Edits: []Edit[string]{
154-
{Delete, "A", ""},
155-
{Insert, "", "C"},
154+
{Delete, 0, -1, "A", ""},
155+
{Insert, -1, 0, "", "C"},
156156
},
157157
},
158158
{
@@ -161,7 +161,7 @@ func TestHunks(t *testing.T) {
161161
EndX: 3,
162162
EndY: 2,
163163
Edits: []Edit[string]{
164-
{Delete, "C", ""},
164+
{Delete, 2, -1, "C", ""},
165165
},
166166
},
167167
{
@@ -170,7 +170,7 @@ func TestHunks(t *testing.T) {
170170
EndX: 6,
171171
EndY: 4,
172172
Edits: []Edit[string]{
173-
{Delete, "B", ""},
173+
{Delete, 5, -1, "B", ""},
174174
},
175175
},
176176
{
@@ -179,7 +179,7 @@ func TestHunks(t *testing.T) {
179179
EndX: 7,
180180
EndY: 6,
181181
Edits: []Edit[string]{
182-
{Insert, "", "C"},
182+
{Insert, -1, 5, "", "C"},
183183
},
184184
},
185185
},
@@ -218,12 +218,12 @@ func TestHunks(t *testing.T) {
218218
PosY: 0,
219219
EndY: 6,
220220
Edits: []Edit[string]{
221-
{Insert, "", "this is a new paragraph"},
222-
{Insert, "", "that is inserted at the top"},
223-
{Insert, "", ""},
224-
{Match, "this paragraph", "this paragraph"},
225-
{Match, "is not", "is not"},
226-
{Match, "changed and", "changed and"},
221+
{Insert, -1, 0, "", "this is a new paragraph"},
222+
{Insert, -1, 1, "", "that is inserted at the top"},
223+
{Insert, -1, 2, "", ""},
224+
{Match, 0, 3, "this paragraph", "this paragraph"},
225+
{Match, 1, 4, "is not", "is not"},
226+
{Match, 2, 5, "changed and", "changed and"},
227227
},
228228
},
229229
{
@@ -232,13 +232,13 @@ func TestHunks(t *testing.T) {
232232
PosY: 7,
233233
EndY: 10,
234234
Edits: []Edit[string]{
235-
{Match, "enough to", "enough to"},
236-
{Match, "create a", "create a"},
237-
{Match, "new hunk", "new hunk"},
238-
{Delete, "", ""},
239-
{Delete, "this paragraph", ""},
240-
{Delete, "is going to be", ""},
241-
{Delete, "removed", ""},
235+
{Match, 4, 7, "enough to", "enough to"},
236+
{Match, 5, 8, "create a", "create a"},
237+
{Match, 6, 9, "new hunk", "new hunk"},
238+
{Delete, 7, -1, "", ""},
239+
{Delete, 8, -1, "this paragraph", ""},
240+
{Delete, 9, -1, "is going to be", ""},
241+
{Delete, 10, -1, "removed", ""},
242242
},
243243
},
244244
},
@@ -273,18 +273,18 @@ func TestHunks(t *testing.T) {
273273
PosY: 0,
274274
EndY: 8,
275275
Edits: []Edit[string]{
276-
{Insert, "", "this is a new paragraph"},
277-
{Insert, "", "that is inserted at the top"},
278-
{Insert, "", ""},
279-
{Match, "this paragraph", "this paragraph"},
280-
{Match, "stays but is", "stays but is"},
281-
{Match, "not long enough", "not long enough"},
282-
{Match, "to create a", "to create a"},
283-
{Match, "new hunk", "new hunk"},
284-
{Delete, "", ""},
285-
{Delete, "this paragraph", ""},
286-
{Delete, "is going to be", ""},
287-
{Delete, "removed", ""},
276+
{Insert, -1, 0, "", "this is a new paragraph"},
277+
{Insert, -1, 1, "", "that is inserted at the top"},
278+
{Insert, -1, 2, "", ""},
279+
{Match, 0, 3, "this paragraph", "this paragraph"},
280+
{Match, 1, 4, "stays but is", "stays but is"},
281+
{Match, 2, 5, "not long enough", "not long enough"},
282+
{Match, 3, 6, "to create a", "to create a"},
283+
{Match, 4, 7, "new hunk", "new hunk"},
284+
{Delete, 5, -1, "", ""},
285+
{Delete, 6, -1, "this paragraph", ""},
286+
{Delete, 7, -1, "is going to be", ""},
287+
{Delete, 8, -1, "removed", ""},
288288
},
289289
},
290290
},
@@ -320,9 +320,9 @@ func TestEdits(t *testing.T) {
320320
x: []string{"foo", "bar", "baz"},
321321
y: []string{"foo", "bar", "baz"},
322322
want: []Edit[string]{
323-
{Match, "foo", "foo"},
324-
{Match, "bar", "bar"},
325-
{Match, "baz", "baz"},
323+
{Match, 0, 0, "foo", "foo"},
324+
{Match, 1, 1, "bar", "bar"},
325+
{Match, 2, 2, "baz", "baz"},
326326
},
327327
},
328328
{
@@ -332,54 +332,54 @@ func TestEdits(t *testing.T) {
332332
name: "x-empty",
333333
y: []string{"foo", "bar", "baz"},
334334
want: []Edit[string]{
335-
{Insert, "", "foo"},
336-
{Insert, "", "bar"},
337-
{Insert, "", "baz"},
335+
{Insert, -1, 0, "", "foo"},
336+
{Insert, -1, 1, "", "bar"},
337+
{Insert, -1, 2, "", "baz"},
338338
},
339339
},
340340
{
341341
name: "y-empty",
342342
x: []string{"foo", "bar", "baz"},
343343
want: []Edit[string]{
344-
{Delete, "foo", ""},
345-
{Delete, "bar", ""},
346-
{Delete, "baz", ""},
344+
{Delete, 0, -1, "foo", ""},
345+
{Delete, 1, -1, "bar", ""},
346+
{Delete, 2, -1, "baz", ""},
347347
},
348348
},
349349
{
350350
name: "ABCABBA_to_CBABAC",
351351
x: strings.Split("ABCABBA", ""),
352352
y: strings.Split("CBABAC", ""),
353353
want: []Edit[string]{
354-
{Delete, "A", ""},
355-
{Insert, "", "C"},
356-
{Match, "B", "B"},
357-
{Delete, "C", ""},
358-
{Match, "A", "A"},
359-
{Match, "B", "B"},
360-
{Delete, "B", ""},
361-
{Match, "A", "A"},
362-
{Insert, "", "C"},
354+
{Delete, 0, -1, "A", ""},
355+
{Insert, -1, 0, "", "C"},
356+
{Match, 1, 1, "B", "B"},
357+
{Delete, 2, -1, "C", ""},
358+
{Match, 3, 2, "A", "A"},
359+
{Match, 4, 3, "B", "B"},
360+
{Delete, 5, -1, "B", ""},
361+
{Match, 6, 4, "A", "A"},
362+
{Insert, -1, 5, "", "C"},
363363
},
364364
},
365365
{
366366
name: "same-prefix",
367367
x: []string{"foo", "bar"},
368368
y: []string{"foo", "baz"},
369369
want: []Edit[string]{
370-
{Match, "foo", "foo"},
371-
{Delete, "bar", ""},
372-
{Insert, "", "baz"},
370+
{Match, 0, 0, "foo", "foo"},
371+
{Delete, 1, -1, "bar", ""},
372+
{Insert, -1, 1, "", "baz"},
373373
},
374374
},
375375
{
376376
name: "same-suffix",
377377
x: []string{"foo", "bar"},
378378
y: []string{"loo", "bar"},
379379
want: []Edit[string]{
380-
{Delete, "foo", ""},
381-
{Insert, "", "loo"},
382-
{Match, "bar", "bar"},
380+
{Delete, 0, -1, "foo", ""},
381+
{Insert, -1, 0, "", "loo"},
382+
{Match, 1, 1, "bar", "bar"},
383383
},
384384
},
385385
}

0 commit comments

Comments
 (0)