Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / internal / lsp / diff / myers / diff.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/internal/lsp/diff/myers/diff.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/internal/lsp/diff/myers/diff.go
new file mode 100644 (file)
index 0000000..c50e33a
--- /dev/null
@@ -0,0 +1,205 @@
+// 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 implements the Myers diff algorithm.
+package myers
+
+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
+
+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)
+}
+
+// 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) []*operation {
+       if len(a) == 0 && len(b) == 0 {
+               return nil
+       }
+
+       trace, offset := shortestEditSequence(a, b)
+       snakes := backtrack(trace, len(a), len(b), offset)
+
+       M, N := len(a), len(b)
+
+       var i int
+       solution := make([]*operation, len(a)+len(b))
+
+       add := func(op *operation, i2, j2 int) {
+               if op == nil {
+                       return
+               }
+               op.I2 = i2
+               if op.Kind == diff.Insert {
+                       op.Content = b[op.J1:j2]
+               }
+               solution[i] = op
+               i++
+       }
+       x, y := 0, 0
+       for _, snake := range snakes {
+               if len(snake) < 2 {
+                       continue
+               }
+               var op *operation
+               // delete (horizontal)
+               for snake[0]-snake[1] > x-y {
+                       if op == nil {
+                               op = &operation{
+                                       Kind: diff.Delete,
+                                       I1:   x,
+                                       J1:   y,
+                               }
+                       }
+                       x++
+                       if x == M {
+                               break
+                       }
+               }
+               add(op, x, y)
+               op = nil
+               // insert (vertical)
+               for snake[0]-snake[1] < x-y {
+                       if op == nil {
+                               op = &operation{
+                                       Kind: diff.Insert,
+                                       I1:   x,
+                                       J1:   y,
+                               }
+                       }
+                       y++
+               }
+               add(op, x, y)
+               op = nil
+               // equal (diagonal)
+               for x < snake[0] {
+                       x++
+                       y++
+               }
+               if x >= M && y >= N {
+                       break
+               }
+       }
+       return solution[:i]
+}
+
+// backtrack uses the trace for the edit sequence computation and returns the
+// "snakes" that make up the solution. A "snake" is a single deletion or
+// insertion followed by zero or diagonals.
+func backtrack(trace [][]int, x, y, offset int) [][]int {
+       snakes := make([][]int, len(trace))
+       d := len(trace) - 1
+       for ; x > 0 && y > 0 && d > 0; d-- {
+               V := trace[d]
+               if len(V) == 0 {
+                       continue
+               }
+               snakes[d] = []int{x, y}
+
+               k := x - y
+
+               var kPrev int
+               if k == -d || (k != d && V[k-1+offset] < V[k+1+offset]) {
+                       kPrev = k + 1
+               } else {
+                       kPrev = k - 1
+               }
+
+               x = V[kPrev+offset]
+               y = x - kPrev
+       }
+       if x < 0 || y < 0 {
+               return snakes
+       }
+       snakes[d] = []int{x, y}
+       return snakes
+}
+
+// shortestEditSequence returns the shortest edit sequence that converts a into b.
+func shortestEditSequence(a, b []string) ([][]int, int) {
+       M, N := len(a), len(b)
+       V := make([]int, 2*(N+M)+1)
+       offset := N + M
+       trace := make([][]int, N+M+1)
+
+       // Iterate through the maximum possible length of the SES (N+M).
+       for d := 0; d <= N+M; d++ {
+               copyV := make([]int, len(V))
+               // k lines are represented by the equation y = x - k. We move in
+               // increments of 2 because end points for even d are on even k lines.
+               for k := -d; k <= d; k += 2 {
+                       // At each point, we either go down or to the right. We go down if
+                       // k == -d, and we go to the right if k == d. We also prioritize
+                       // the maximum x value, because we prefer deletions to insertions.
+                       var x int
+                       if k == -d || (k != d && V[k-1+offset] < V[k+1+offset]) {
+                               x = V[k+1+offset] // down
+                       } else {
+                               x = V[k-1+offset] + 1 // right
+                       }
+
+                       y := x - k
+
+                       // Diagonal moves while we have equal contents.
+                       for x < M && y < N && a[x] == b[y] {
+                               x++
+                               y++
+                       }
+
+                       V[k+offset] = x
+
+                       // Return if we've exceeded the maximum values.
+                       if x == M && y == N {
+                               // Makes sure to save the state of the array before returning.
+                               copy(copyV, V)
+                               trace[d] = copyV
+                               return trace, offset
+                       }
+               }
+
+               // Save the state of the array.
+               copy(copyV, V)
+               trace[d] = copyV
+       }
+       return nil, 0
+}
+
+func splitLines(text string) []string {
+       lines := strings.SplitAfter(text, "\n")
+       if lines[len(lines)-1] == "" {
+               lines = lines[:len(lines)-1]
+       }
+       return lines
+}