Skip to content

Commit a07c685

Browse files
committed
replace new ComputeEdits implementation
1 parent 06c04f5 commit a07c685

File tree

1 file changed

+48
-23
lines changed

1 file changed

+48
-23
lines changed

langserver/diff.go

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,57 +7,82 @@
77
package langserver
88

99
import (
10+
"slices"
1011
"strings"
1112
)
1213

13-
// OpKind is used to denote the type of operation a line represents.
14-
type OpKind int
15-
16-
const (
17-
// Delete is the operation kind for a line that is present in the input
18-
// but not in the output.
19-
Delete OpKind = iota
20-
// Insert is the operation kind for a line that is new in the output.
21-
Insert
22-
// Equal is the operation kind for a line that is the same in the input and
23-
// output, often used to provide context around edited lines.
24-
Equal
25-
)
26-
2714
// Sources:
2815
// https://blog.jcoglan.com/2017/02/17/the-myers-diff-algorithm-part-3/
2916
// https://www.codeproject.com/Articles/42279/%2FArticles%2F42279%2FInvestigating-Myers-diff-algorithm-Part-1-of-2
3017

31-
// ComputeEdits computes diff edits from 2 string inputs
18+
// ComputeEdits returns the diffs of two strings using a simple
19+
// line-based implementation, like [diff.Strings].
3220
func ComputeEdits(_ DocumentURI, before, after string) []TextEdit {
3321
ops := operations(splitLines(before), splitLines(after))
3422
edits := make([]TextEdit, 0, len(ops))
23+
24+
// If there're some insertions on the same line, they must be reversed to be applied in order.
25+
// So memorize the last insertion line and its index.
26+
var insHankLine int
27+
var insHankIndex int
3528
for _, op := range ops {
3629
switch op.Kind {
37-
case Delete:
30+
case opDelete:
3831
// Delete: unformatted[i1:i2] is deleted.
3932
edits = append(edits, TextEdit{Range: Range{
4033
Start: Position{Line: op.I1, Character: 0},
4134
End: Position{Line: op.I2, Character: 0},
4235
}})
43-
case Insert:
36+
insHankLine = -1 // Reset insertion hanking
37+
case opInsert:
4438
// Insert: formatted[j1:j2] is inserted at unformatted[i1:i1].
4539
if content := strings.Join(op.Content, ""); content != "" {
46-
edits = append(edits, TextEdit{
40+
newEdit := TextEdit{
4741
Range: Range{
4842
Start: Position{Line: op.I1, Character: 0},
4943
End: Position{Line: op.I2, Character: 0},
5044
},
5145
NewText: content,
52-
})
46+
}
47+
48+
if insHankLine == op.I1 {
49+
// If there're some insertion on the same line, insert it before the hank of the last insertions.
50+
edits = slices.Insert(edits, insHankIndex, newEdit)
51+
} else {
52+
insHankLine = op.I1
53+
insHankIndex = len(edits)
54+
edits = append(edits, newEdit)
55+
}
5356
}
5457
}
5558
}
5659
return edits
5760
}
5861

62+
// opKind is used to denote the type of operation a line represents.
63+
type opKind int
64+
65+
const (
66+
opDelete opKind = iota // line deleted from input (-)
67+
opInsert // line inserted into output (+)
68+
opEqual // line present in input and output
69+
)
70+
71+
func (kind opKind) String() string {
72+
switch kind {
73+
case opDelete:
74+
return "delete"
75+
case opInsert:
76+
return "insert"
77+
case opEqual:
78+
return "equal"
79+
default:
80+
panic("unknown opKind")
81+
}
82+
}
83+
5984
type operation struct {
60-
Kind OpKind
85+
Kind opKind
6186
Content []string // content from b
6287
I1, I2 int // indices of the line in a
6388
J1 int // indices of the line in b, J2 implied by len(Content)
@@ -83,7 +108,7 @@ func operations(a, b []string) []*operation {
83108
return
84109
}
85110
op.I2 = i2
86-
if op.Kind == Insert {
111+
if op.Kind == opInsert {
87112
op.Content = b[op.J1:j2]
88113
}
89114
solution[i] = op
@@ -99,7 +124,7 @@ func operations(a, b []string) []*operation {
99124
for snake[0]-snake[1] > x-y {
100125
if op == nil {
101126
op = &operation{
102-
Kind: Delete,
127+
Kind: opDelete,
103128
I1: x,
104129
J1: y,
105130
}
@@ -115,7 +140,7 @@ func operations(a, b []string) []*operation {
115140
for snake[0]-snake[1] < x-y {
116141
if op == nil {
117142
op = &operation{
118-
Kind: Insert,
143+
Kind: opInsert,
119144
I1: x,
120145
J1: y,
121146
}

0 commit comments

Comments
 (0)