From 88641d98b32adc8bb37889675de04db164156bf4 Mon Sep 17 00:00:00 2001 From: Ian Cottrell Date: Wed, 2 Oct 2019 23:47:30 -0400 Subject: [PATCH] internal/lsp: cleanup the diff/myers package The only exposed symbol is now the ComputeEdits function, all other functionality is now moved up to the diff layer and using edits instead of operations. Change-Id: I149e4f3276592e1a7c2c52e6eaffc826cc22a9fa Reviewed-on: https://go-review.googlesource.com/c/tools/+/198518 Run-TryBot: Ian Cottrell TryBot-Result: Gobot Gobot Reviewed-by: Rebecca Stambler --- internal/lsp/diff/myers/diff.go | 63 +++++++++++++++----------------- internal/lsp/diff/myers/myers.go | 62 ------------------------------- 2 files changed, 29 insertions(+), 96 deletions(-) delete mode 100644 internal/lsp/diff/myers/myers.go diff --git a/internal/lsp/diff/myers/diff.go b/internal/lsp/diff/myers/diff.go index e6e6e210c3..c50e33a80a 100644 --- a/internal/lsp/diff/myers/diff.go +++ b/internal/lsp/diff/myers/diff.go @@ -9,47 +9,42 @@ import ( "strings" "golang.org/x/tools/internal/lsp/diff" + "golang.org/x/tools/internal/span" ) // 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 { +func ComputeEdits(uri span.URI, before, after string) []diff.TextEdit { + ops := operations(splitLines(before), splitLines(after)) + 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 diff.Delete: + // Delete: unformatted[i1:i2] is deleted. + 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, diff.TextEdit{Span: s, NewText: content}) + } + } + } + return edits +} + +type operation struct { 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) } -func ApplyEdits(a []string, operations []*Op) []string { - var b []string - var prevI2 int - for _, op := range operations { - // catch up to latest indices - if op.I1-prevI2 > 0 { - for _, c := range a[prevI2:op.I1] { - b = append(b, c) - } - } - switch op.Kind { - case diff.Equal, diff.Insert: - b = append(b, op.Content...) - } - prevI2 = op.I2 - } - // final catch up - if len(a)-prevI2 > 0 { - for _, c := range a[prevI2:len(a)] { - b = append(b, c) - } - } - return b -} - -// Operations returns the list of operations to convert a into b, consolidating +// operations returns the list of operations to convert a into b, consolidating // operations for multiple lines and not including equal lines. -func Operations(a, b []string) []*Op { +func operations(a, b []string) []*operation { if len(a) == 0 && len(b) == 0 { return nil } @@ -60,9 +55,9 @@ func Operations(a, b []string) []*Op { M, N := len(a), len(b) var i int - solution := make([]*Op, len(a)+len(b)) + solution := make([]*operation, len(a)+len(b)) - add := func(op *Op, i2, j2 int) { + add := func(op *operation, i2, j2 int) { if op == nil { return } @@ -78,11 +73,11 @@ func Operations(a, b []string) []*Op { if len(snake) < 2 { continue } - var op *Op + var op *operation // delete (horizontal) for snake[0]-snake[1] > x-y { if op == nil { - op = &Op{ + op = &operation{ Kind: diff.Delete, I1: x, J1: y, @@ -98,7 +93,7 @@ func Operations(a, b []string) []*Op { // insert (vertical) for snake[0]-snake[1] < x-y { if op == nil { - op = &Op{ + op = &operation{ Kind: diff.Insert, I1: x, J1: y, @@ -201,7 +196,7 @@ func shortestEditSequence(a, b []string) ([][]int, int) { return nil, 0 } -func SplitLines(text string) []string { +func splitLines(text string) []string { lines := strings.SplitAfter(text, "\n") if lines[len(lines)-1] == "" { lines = lines[:len(lines)-1] diff --git a/internal/lsp/diff/myers/myers.go b/internal/lsp/diff/myers/myers.go deleted file mode 100644 index 2df12c306e..0000000000 --- a/internal/lsp/diff/myers/myers.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package myers - -import ( - "strings" - - "golang.org/x/tools/internal/lsp/diff" - "golang.org/x/tools/internal/span" -) - -func ComputeEdits(uri span.URI, before, after string) []diff.TextEdit { - u := SplitLines(before) - f := SplitLines(after) - return myersDiffToEdits(uri, Operations(u, f)) -} - -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 diff.Delete: - // Delete: unformatted[i1:i2] is deleted. - 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, diff.TextEdit{Span: s, NewText: content}) - } - } - } - return edits -} - -func myersEditsToDiff(edits []diff.TextEdit) []*Op { - iToJ := 0 - ops := make([]*Op, len(edits)) - for i, edit := range edits { - i1 := edit.Span.Start().Line() - 1 - i2 := edit.Span.End().Line() - 1 - kind := diff.Insert - if edit.NewText == "" { - kind = diff.Delete - } - ops[i] = &Op{ - Kind: kind, - Content: SplitLines(edit.NewText), - I1: i1, - I2: i2, - J1: i1 + iToJ, - } - if kind == diff.Insert { - iToJ += len(ops[i].Content) - } else { - iToJ -= i2 - i1 - } - } - return ops -}