Skip to content

Commit

Permalink
internal/lsp: invert the diff dependencies so myers depends on diff
Browse files Browse the repository at this point in the history
This makes it so the diff package is depended on by all implementations, rather
than the diff package having to depend on the default myers implementation.

Change-Id: I04b9caee6ff1017fa8e5476a7434e4b0e17753c3
Reviewed-on: https://go-review.googlesource.com/c/tools/+/198379
Reviewed-by: Rebecca Stambler <[email protected]>
  • Loading branch information
ianthehat committed Oct 3, 2019
1 parent b2e299b commit 9cd7e18
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 89 deletions.
24 changes: 24 additions & 0 deletions internal/lsp/diff/hooks.go → internal/lsp/diff/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,30 @@ var (
ToUnified func(from, to string, before string, edits []TextEdit) string
)

type OpKind int

const (
Delete OpKind = iota
Insert
Equal
)

func (k OpKind) String() string {
switch k {
case Delete:
return "delete"
case Insert:
return "insert"
case Equal:
return "equal"
default:
panic("unknown operation kind")
}
}

// SortTextEdits attempts to order all edits by their starting points.
// The sort is stable so that edits with the same starting point will not
// be reordered.
func SortTextEdits(d []TextEdit) {
// Use a stable sort to maintain the order of edits inserted at the same position.
sort.SliceStable(d, func(i int, j int) bool {
Expand Down
16 changes: 0 additions & 16 deletions internal/lsp/diff/diff_test.go

This file was deleted.

37 changes: 10 additions & 27 deletions internal/lsp/diff/myers/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,23 @@
// Package myers implements the Myers diff algorithm.
package myers

import "strings"
import (
"strings"

"golang.org/x/tools/internal/lsp/diff"
)

// Sources:
// https://blog.jcoglan.com/2017/02/17/the-myers-diff-algorithm-part-3/
// https://www.codeproject.com/Articles/42279/%2FArticles%2F42279%2FInvestigating-Myers-diff-algorithm-Part-1-of-2

type Op struct {
Kind OpKind
Kind diff.OpKind
Content []string // content from b
I1, I2 int // indices of the line in a
J1 int // indices of the line in b, J2 implied by len(Content)
}

type OpKind int

const (
Delete OpKind = iota
Insert
Equal
)

func (k OpKind) String() string {
switch k {
case Delete:
return "delete"
case Insert:
return "insert"
case Equal:
return "equal"
default:
panic("unknown operation kind")
}
}

func ApplyEdits(a []string, operations []*Op) []string {
var b []string
var prevI2 int
Expand All @@ -50,7 +33,7 @@ func ApplyEdits(a []string, operations []*Op) []string {
}
}
switch op.Kind {
case Equal, Insert:
case diff.Equal, diff.Insert:
b = append(b, op.Content...)
}
prevI2 = op.I2
Expand Down Expand Up @@ -84,7 +67,7 @@ func Operations(a, b []string) []*Op {
return
}
op.I2 = i2
if op.Kind == Insert {
if op.Kind == diff.Insert {
op.Content = b[op.J1:j2]
}
solution[i] = op
Expand All @@ -100,7 +83,7 @@ func Operations(a, b []string) []*Op {
for snake[0]-snake[1] > x-y {
if op == nil {
op = &Op{
Kind: Delete,
Kind: diff.Delete,
I1: x,
J1: y,
}
Expand All @@ -116,7 +99,7 @@ func Operations(a, b []string) []*Op {
for snake[0]-snake[1] < x-y {
if op == nil {
op = &Op{
Kind: Insert,
Kind: diff.Insert,
I1: x,
J1: y,
}
Expand Down
30 changes: 18 additions & 12 deletions internal/lsp/diff/myers/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"strings"
"testing"

"golang.org/x/tools/internal/lsp/diff"
"golang.org/x/tools/internal/lsp/diff/difftest"
"golang.org/x/tools/internal/lsp/diff/myers"
)

Expand All @@ -26,6 +28,10 @@ const (
var verifyDiff = flag.Bool("verify-diff", false, "Check that the unified diff output matches `diff -u`")

func TestDiff(t *testing.T) {
difftest.DiffTest(t, myers.ComputeEdits)
}

func TestMyersDiff(t *testing.T) {
for _, test := range []struct {
a, b string
lines []*myers.Op
Expand All @@ -42,8 +48,8 @@ func TestDiff(t *testing.T) {
a: "A\n",
b: "B\n",
operations: []*myers.Op{
&myers.Op{Kind: myers.Delete, I1: 0, I2: 1, J1: 0},
&myers.Op{Kind: myers.Insert, Content: []string{"B\n"}, I1: 1, I2: 1, J1: 0},
&myers.Op{Kind: diff.Delete, I1: 0, I2: 1, J1: 0},
&myers.Op{Kind: diff.Insert, Content: []string{"B\n"}, I1: 1, I2: 1, J1: 0},
},
unified: `
@@ -1 +1 @@
Expand All @@ -53,8 +59,8 @@ func TestDiff(t *testing.T) {
a: "A",
b: "B",
operations: []*myers.Op{
&myers.Op{Kind: myers.Delete, I1: 0, I2: 1, J1: 0},
&myers.Op{Kind: myers.Insert, Content: []string{"B"}, I1: 1, I2: 1, J1: 0},
&myers.Op{Kind: diff.Delete, I1: 0, I2: 1, J1: 0},
&myers.Op{Kind: diff.Insert, Content: []string{"B"}, I1: 1, I2: 1, J1: 0},
},
unified: `
@@ -1 +1 @@
Expand All @@ -66,11 +72,11 @@ func TestDiff(t *testing.T) {
a: "A\nB\nC\nA\nB\nB\nA\n",
b: "C\nB\nA\nB\nA\nC\n",
operations: []*myers.Op{
&myers.Op{Kind: myers.Delete, I1: 0, I2: 1, J1: 0},
&myers.Op{Kind: myers.Delete, I1: 1, I2: 2, J1: 0},
&myers.Op{Kind: myers.Insert, Content: []string{"B\n"}, I1: 3, I2: 3, J1: 1},
&myers.Op{Kind: myers.Delete, I1: 5, I2: 6, J1: 4},
&myers.Op{Kind: myers.Insert, Content: []string{"C\n"}, I1: 7, I2: 7, J1: 5},
&myers.Op{Kind: diff.Delete, I1: 0, I2: 1, J1: 0},
&myers.Op{Kind: diff.Delete, I1: 1, I2: 2, J1: 0},
&myers.Op{Kind: diff.Insert, Content: []string{"B\n"}, I1: 3, I2: 3, J1: 1},
&myers.Op{Kind: diff.Delete, I1: 5, I2: 6, J1: 4},
&myers.Op{Kind: diff.Insert, Content: []string{"C\n"}, I1: 7, I2: 7, J1: 5},
},
unified: `
@@ -1,7 +1,6 @@
Expand All @@ -90,9 +96,9 @@ func TestDiff(t *testing.T) {
a: "A\nB\n",
b: "A\nC\n\n",
operations: []*myers.Op{
&myers.Op{Kind: myers.Delete, I1: 1, I2: 2, J1: 1},
&myers.Op{Kind: myers.Insert, Content: []string{"C\n"}, I1: 2, I2: 2, J1: 1},
&myers.Op{Kind: myers.Insert, Content: []string{"\n"}, I1: 2, I2: 2, J1: 2},
&myers.Op{Kind: diff.Delete, I1: 1, I2: 2, J1: 1},
&myers.Op{Kind: diff.Insert, Content: []string{"C\n"}, I1: 2, I2: 2, J1: 1},
&myers.Op{Kind: diff.Insert, Content: []string{"\n"}, I1: 2, I2: 2, J1: 2},
},
unified: `
@@ -1,2 +1,3 @@
Expand Down
46 changes: 23 additions & 23 deletions internal/lsp/diff/myers.go → internal/lsp/diff/myers/myers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,68 +2,68 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package diff
package myers

import (
"fmt"
"strings"

"golang.org/x/tools/internal/lsp/diff/myers"
"golang.org/x/tools/internal/lsp/diff"
"golang.org/x/tools/internal/span"
)

func init() {
ToUnified = myersToUnified
diff.ToUnified = myersToUnified
}

func MyersComputeEdits(uri span.URI, before, after string) []TextEdit {
u := myers.SplitLines(before)
f := myers.SplitLines(after)
return myersDiffToEdits(uri, myers.Operations(u, f))
func ComputeEdits(uri span.URI, before, after string) []diff.TextEdit {
u := SplitLines(before)
f := SplitLines(after)
return myersDiffToEdits(uri, Operations(u, f))
}

func myersToUnified(from, to string, before string, edits []TextEdit) string {
u := myers.SplitLines(before)
func myersToUnified(from, to string, before string, edits []diff.TextEdit) string {
u := SplitLines(before)
ops := myersEditsToDiff(edits)
return fmt.Sprint(myers.ToUnified(from, to, u, ops))
return fmt.Sprint(ToUnified(from, to, u, ops))
}

func myersDiffToEdits(uri span.URI, ops []*myers.Op) []TextEdit {
edits := make([]TextEdit, 0, len(ops))
func myersDiffToEdits(uri span.URI, ops []*Op) []diff.TextEdit {
edits := make([]diff.TextEdit, 0, len(ops))
for _, op := range ops {
s := span.New(uri, span.NewPoint(op.I1+1, 1, 0), span.NewPoint(op.I2+1, 1, 0))
switch op.Kind {
case myers.Delete:
case diff.Delete:
// Delete: unformatted[i1:i2] is deleted.
edits = append(edits, TextEdit{Span: s})
case myers.Insert:
edits = append(edits, diff.TextEdit{Span: s})
case diff.Insert:
// Insert: formatted[j1:j2] is inserted at unformatted[i1:i1].
if content := strings.Join(op.Content, ""); content != "" {
edits = append(edits, TextEdit{Span: s, NewText: content})
edits = append(edits, diff.TextEdit{Span: s, NewText: content})
}
}
}
return edits
}

func myersEditsToDiff(edits []TextEdit) []*myers.Op {
func myersEditsToDiff(edits []diff.TextEdit) []*Op {
iToJ := 0
ops := make([]*myers.Op, len(edits))
ops := make([]*Op, len(edits))
for i, edit := range edits {
i1 := edit.Span.Start().Line() - 1
i2 := edit.Span.End().Line() - 1
kind := myers.Insert
kind := diff.Insert
if edit.NewText == "" {
kind = myers.Delete
kind = diff.Delete
}
ops[i] = &myers.Op{
ops[i] = &Op{
Kind: kind,
Content: myers.SplitLines(edit.NewText),
Content: SplitLines(edit.NewText),
I1: i1,
I2: i2,
J1: i1 + iToJ,
}
if kind == myers.Insert {
if kind == diff.Insert {
iToJ += len(ops[i].Content)
} else {
iToJ -= i2 - i1
Expand Down
22 changes: 12 additions & 10 deletions internal/lsp/diff/myers/unified.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ package myers
import (
"fmt"
"strings"

"golang.org/x/tools/internal/lsp/diff"
)

type Unified struct {
Expand All @@ -21,7 +23,7 @@ type Hunk struct {
}

type Line struct {
Kind OpKind
Kind diff.OpKind
Content string
}

Expand Down Expand Up @@ -67,14 +69,14 @@ func ToUnified(from, to string, lines []string, ops []*Op) Unified {
}
last = op.I1
switch op.Kind {
case Delete:
case diff.Delete:
for i := op.I1; i < op.I2; i++ {
h.Lines = append(h.Lines, Line{Kind: Delete, Content: lines[i]})
h.Lines = append(h.Lines, Line{Kind: diff.Delete, Content: lines[i]})
last++
}
case Insert:
case diff.Insert:
for _, c := range op.Content {
h.Lines = append(h.Lines, Line{Kind: Insert, Content: c})
h.Lines = append(h.Lines, Line{Kind: diff.Insert, Content: c})
}
default:
// all other op types ignored
Expand All @@ -97,7 +99,7 @@ func addEqualLines(h *Hunk, lines []string, start, end int) int {
if i >= len(lines) {
return delta
}
h.Lines = append(h.Lines, Line{Kind: Equal, Content: lines[i]})
h.Lines = append(h.Lines, Line{Kind: diff.Equal, Content: lines[i]})
delta++
}
return delta
Expand All @@ -113,9 +115,9 @@ func (u Unified) Format(f fmt.State, r rune) {
fromCount, toCount := 0, 0
for _, l := range hunk.Lines {
switch l.Kind {
case Delete:
case diff.Delete:
fromCount++
case Insert:
case diff.Insert:
toCount++
default:
fromCount++
Expand All @@ -136,9 +138,9 @@ func (u Unified) Format(f fmt.State, r rune) {
fmt.Fprint(f, " @@\n")
for _, l := range hunk.Lines {
switch l.Kind {
case Delete:
case diff.Delete:
fmt.Fprintf(f, "-%s", l.Content)
case Insert:
case diff.Insert:
fmt.Fprintf(f, "+%s", l.Content)
default:
fmt.Fprintf(f, " %s", l.Content)
Expand Down
3 changes: 2 additions & 1 deletion internal/lsp/source/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"golang.org/x/tools/internal/lsp/diff"
"golang.org/x/tools/internal/lsp/diff/myers"
"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/telemetry/tag"
errors "golang.org/x/xerrors"
Expand Down Expand Up @@ -41,7 +42,7 @@ var (
FuzzyMatching: true,
Budget: 100 * time.Millisecond,
},
ComputeEdits: diff.MyersComputeEdits,
ComputeEdits: myers.ComputeEdits,
}
)

Expand Down

0 comments on commit 9cd7e18

Please sign in to comment.