diff --git a/cli/blocks_test.go b/cli/blocks_test.go
index 27afa07c..cac9841e 100644
--- a/cli/blocks_test.go
+++ b/cli/blocks_test.go
@@ -9,8 +9,8 @@ import (
c "github.com/gookit/color"
"github.com/katbyte/terrafmt/lib/common"
+ "github.com/katbyte/terrafmt/lib/diff"
"github.com/katbyte/terrafmt/lib/fmtverbs"
- "github.com/kylelemons/godebug/diff"
"github.com/spf13/afero"
)
@@ -384,7 +384,7 @@ func TestCmdBlocksDefault(t *testing.T) {
}
if actualStdOut != expected {
- t.Errorf("Output does not match expected: ('-' actual, '+' expected)\n%s", diff.Diff(actualStdOut, expected))
+ t.Errorf("Output does not match expected: ('-' actual, '+' expected)\n%s", diff.LineDiff(actualStdOut, expected))
}
if actualStdErr != "" {
@@ -449,7 +449,7 @@ func TestCmdBlocksZeroTerminated(t *testing.T) {
}
if actualStdOut != expected {
- t.Errorf("Output does not match expected: ('-' actual, '+' expected)\n%s", diff.Diff(actualStdOut, expected))
+ t.Errorf("Output does not match expected: ('-' actual, '+' expected)\n%s", diff.LineDiff(actualStdOut, expected))
}
if actualStdErr != "" {
@@ -496,7 +496,7 @@ func TestCmdBlocksJson(t *testing.T) {
}
if !equivalentJSON([]byte(actualStdOut), expected) {
- t.Errorf("Output does not match expected: ('-' actual, '+' expected)\n%s", diff.Diff(actualStdOut, string(expected)))
+ t.Errorf("Output does not match expected: ('-' actual, '+' expected)\n%s", diff.LineDiff(actualStdOut, string(expected)))
}
if actualStdErr != "" {
@@ -543,7 +543,7 @@ func TestCmdBlocksFmtVerbsJson(t *testing.T) {
}
if !equivalentJSON([]byte(actualStdOut), expected) {
- t.Errorf("Output does not match expected: ('-' actual, '+' expected)\n%s", diff.Diff(actualStdOut, string(expected)))
+ t.Errorf("Output does not match expected: ('-' actual, '+' expected)\n%s", diff.LineDiff(actualStdOut, string(expected)))
}
if actualStdErr != "" {
diff --git a/cli/cmds.go b/cli/cmds.go
index 760dc41c..e17d01d6 100644
--- a/cli/cmds.go
+++ b/cli/cmds.go
@@ -15,9 +15,9 @@ import (
c "github.com/gookit/color"
"github.com/hashicorp/go-multierror"
- diff "github.com/katbyte/andreyvit-diff"
"github.com/katbyte/terrafmt/lib/blocks"
"github.com/katbyte/terrafmt/lib/common"
+ "github.com/katbyte/terrafmt/lib/diff"
verbs "github.com/katbyte/terrafmt/lib/fmtverbs"
"github.com/katbyte/terrafmt/lib/format"
"github.com/katbyte/terrafmt/lib/version"
diff --git a/cli/diff_test.go b/cli/diff_test.go
index 323c8c92..b786c42c 100644
--- a/cli/diff_test.go
+++ b/cli/diff_test.go
@@ -7,7 +7,7 @@ import (
c "github.com/gookit/color"
"github.com/katbyte/terrafmt/lib/common"
- "github.com/kylelemons/godebug/diff"
+ "github.com/katbyte/terrafmt/lib/diff"
"github.com/spf13/afero"
)
@@ -184,7 +184,7 @@ func TestCmdDiffDefault(t *testing.T) {
}
if actualStdOut != expected {
- t.Errorf("Output does not match expected: ('-' actual, '+' expected)\n%s", diff.Diff(actualStdOut, expected))
+ t.Errorf("Output does not match expected: ('-' actual, '+' expected)\n%s", diff.LineDiff(actualStdOut, expected))
}
errMsg := []string{}
diff --git a/cli/fmt_test.go b/cli/fmt_test.go
index 45773340..7e37b4e4 100644
--- a/cli/fmt_test.go
+++ b/cli/fmt_test.go
@@ -8,7 +8,7 @@ import (
c "github.com/gookit/color"
"github.com/katbyte/terrafmt/lib/common"
- "github.com/kylelemons/godebug/diff"
+ "github.com/katbyte/terrafmt/lib/diff"
"github.com/spf13/afero"
)
@@ -212,7 +212,7 @@ func TestCmdFmtStdinDefault(t *testing.T) {
}
if actualStdOut != expected {
- t.Errorf("Case %q: Output does not match expected: ('-' actual, '+' expected)\n%s", testcase.name, diff.Diff(actualStdOut, expected))
+ t.Errorf("Case %q: Output does not match expected: ('-' actual, '+' expected)\n%s", testcase.name, diff.LineDiff(actualStdOut, expected))
}
errMsg := []string{}
@@ -323,7 +323,7 @@ func TestCmdFmtFileDefault(t *testing.T) {
}
actualContent := c.String(string(data))
if actualContent != expected {
- t.Errorf("Case %q: File does not match expected: ('-' actual, '+' expected)\n%s", testcase.name, diff.Diff(actualContent, expected))
+ t.Errorf("Case %q: File does not match expected: ('-' actual, '+' expected)\n%s", testcase.name, diff.LineDiff(actualContent, expected))
}
if len(testcase.errMsg) != br.ErrorBlocks {
@@ -430,7 +430,7 @@ func TestCmdFmtIdempotency(t *testing.T) {
}
if !bytes.Equal(before, after) {
- t.Errorf("fmt is not idempotent for %q: ('-' before, '+' after)\n%s", testcase.sourcefile, diff.Diff(string(before), string(after)))
+ t.Errorf("fmt is not idempotent for %q: ('-' before, '+' after)\n%s", testcase.sourcefile, diff.LineDiff(string(before), string(after)))
}
})
}
diff --git a/go.mod b/go.mod
index bc28f35b..8bae75c8 100644
--- a/go.mod
+++ b/go.mod
@@ -6,8 +6,6 @@ require (
github.com/gookit/color v1.6.1
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/hcl/v2 v2.24.0
- github.com/katbyte/andreyvit-diff v0.0.3
- github.com/kylelemons/godebug v1.1.0
github.com/sirupsen/logrus v1.9.4
github.com/spf13/afero v1.15.0
github.com/spf13/cobra v1.10.2
@@ -24,7 +22,6 @@ require (
github.com/google/go-cmp v0.7.0 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
- github.com/katbyte/sergi-go-diff v1.2.3 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
diff --git a/go.sum b/go.sum
index 355556ba..316a8fbc 100644
--- a/go.sum
+++ b/go.sum
@@ -27,16 +27,10 @@ github.com/hashicorp/hcl/v2 v2.24.0 h1:2QJdZ454DSsYGoaE6QheQZjtKZSUs9Nh2izTWiwQx
github.com/hashicorp/hcl/v2 v2.24.0/go.mod h1:oGoO1FIQYfn/AgyOhlg9qLC6/nOJPX3qGbkZpYAcqfM=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
-github.com/katbyte/andreyvit-diff v0.0.3 h1:gMfE0xQUKAZb3B2cnnrkLYCCZxnuGCxG4nVczq/dWfE=
-github.com/katbyte/andreyvit-diff v0.0.3/go.mod h1:S//wdxNytA9hp598USfO3jHUDuLJug2TqUyvEErbowM=
-github.com/katbyte/sergi-go-diff v1.2.3 h1:z08AHpmtBTYIOCQBInFTHu9KULlvaWP1Iz2RZ9po3pQ=
-github.com/katbyte/sergi-go-diff v1.2.3/go.mod h1:BxkLLDDB1iVQsnURErqoQMjkyXIlR0DefDKzZCUHNEw=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
-github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
diff --git a/lib/blocks/blockreader_test.go b/lib/blocks/blockreader_test.go
index a65a7158..a51f896a 100644
--- a/lib/blocks/blockreader_test.go
+++ b/lib/blocks/blockreader_test.go
@@ -5,7 +5,7 @@ import (
"testing"
"github.com/katbyte/terrafmt/lib/common"
- "github.com/kylelemons/godebug/diff"
+ "github.com/katbyte/terrafmt/lib/diff"
"github.com/spf13/afero"
)
@@ -301,7 +301,7 @@ func TestBlockDetection(t *testing.T) {
for i, actual := range actualBlocks {
expected := testcase.expectedBlocks[i]
if actual.text != expected.text {
- t.Errorf("Case %q, block %d text: ('-' actual, '+' expected)\n%s", testcase.sourcefile, i+1, diff.Diff(actual.text, expected.text))
+ t.Errorf("Case %q, block %d text: ('-' actual, '+' expected)\n%s", testcase.sourcefile, i+1, diff.LineDiff(actual.text, expected.text))
}
if actual.leadingPadding != expected.leadingPadding {
t.Errorf("Case %q, block %d leading padding: expected %q, got %q", testcase.sourcefile, i+1, expected.leadingPadding, actual.leadingPadding)
diff --git a/vendor/github.com/katbyte/andreyvit-diff/LICENSE b/lib/diff/LICENSE
similarity index 100%
rename from vendor/github.com/katbyte/andreyvit-diff/LICENSE
rename to lib/diff/LICENSE
diff --git a/vendor/github.com/katbyte/andreyvit-diff/diff.go b/lib/diff/diff.go
similarity index 74%
rename from vendor/github.com/katbyte/andreyvit-diff/diff.go
rename to lib/diff/diff.go
index 47837203..3b6468ef 100644
--- a/vendor/github.com/katbyte/andreyvit-diff/diff.go
+++ b/lib/diff/diff.go
@@ -1,10 +1,14 @@
+// Package diff produces linewise diffs between two strings.
+//
+// Absorbed from github.com/andreyvit/diff (via github.com/katbyte/andreyvit-diff,
+// MIT licensed, see LICENSE), trimmed to the LineDiff path used by terrafmt.
package diff
import (
"bytes"
"strings"
- "github.com/katbyte/sergi-go-diff/diffmatchpatch"
+ "github.com/katbyte/terrafmt/lib/diff/diffmatchpatch"
)
func diff(a, b string) []diffmatchpatch.Diff {
@@ -17,31 +21,6 @@ func diff(a, b string) []diffmatchpatch.Diff {
return diffs
}
-// CharacterDiff returns an inline diff between the two strings, using (++added++) and (~~deleted~~) markup.
-func CharacterDiff(a, b string) string {
- return diffsToString(diff(a, b))
-}
-
-func diffsToString(diffs []diffmatchpatch.Diff) string {
- var buff bytes.Buffer
- for _, diff := range diffs {
- text := diff.Text
- switch diff.Type {
- case diffmatchpatch.DiffInsert:
- buff.WriteString("(++")
- buff.WriteString(text)
- buff.WriteString("++)")
- case diffmatchpatch.DiffDelete:
- buff.WriteString("(~~")
- buff.WriteString(text)
- buff.WriteString("~~)")
- case diffmatchpatch.DiffEqual:
- buff.WriteString(text)
- }
- }
- return buff.String()
-}
-
// LineDiff returns a normal linewise diff between the two given strings.
func LineDiff(a, b string) string {
return strings.Join(LineDiffAsLines(a, b), "\n")
@@ -68,6 +47,7 @@ func (b *patchBuilder) AddCharacters(text string, op diffmatchpatch.Operation) {
b.oldLineBuffer.WriteString(text)
}
}
+
func (b *patchBuilder) AddNewline(op diffmatchpatch.Operation) {
oldLine := b.oldLineBuffer.String()
newLine := b.newLineBuffer.String()
@@ -88,6 +68,7 @@ func (b *patchBuilder) AddNewline(op diffmatchpatch.Operation) {
}
}
}
+
func (b *patchBuilder) FlushChunk() {
if b.oldLines != nil {
b.output = append(b.output, b.oldLines...)
@@ -98,12 +79,14 @@ func (b *patchBuilder) FlushChunk() {
b.newLines = nil
}
}
+
func (b *patchBuilder) Flush() {
- if b.oldLineBuffer.Len() > 0 && b.newLineBuffer.Len() > 0 {
+ switch {
+ case b.oldLineBuffer.Len() > 0 && b.newLineBuffer.Len() > 0:
b.AddNewline(diffmatchpatch.DiffEqual)
- } else if b.oldLineBuffer.Len() > 0 {
+ case b.oldLineBuffer.Len() > 0:
b.AddNewline(diffmatchpatch.DiffDelete)
- } else if b.newLineBuffer.Len() > 0 {
+ case b.newLineBuffer.Len() > 0:
b.AddNewline(diffmatchpatch.DiffInsert)
}
b.FlushChunk()
diff --git a/lib/diff/diff_test.go b/lib/diff/diff_test.go
new file mode 100644
index 00000000..9a2febdc
--- /dev/null
+++ b/lib/diff/diff_test.go
@@ -0,0 +1,80 @@
+package diff_test
+
+import (
+ "testing"
+
+ "github.com/katbyte/terrafmt/lib/diff"
+)
+
+// The expected outputs are pinned from github.com/katbyte/andreyvit-diff v0.0.3,
+// which this package absorbed; byte-identical output was verified against that
+// library by differential fuzzing and a corpus replay before it was removed.
+func TestLineDiff(t *testing.T) {
+ t.Parallel()
+
+ tests := []struct {
+ name string
+ a string
+ b string
+ want string
+ }{
+ {
+ name: "changed line",
+ a: "a\nb\nc\n",
+ b: "a\nB\nc\n",
+ want: " a\n-b\n+B\n c",
+ },
+ {
+ name: "removed line",
+ a: "a\nb\nc\n",
+ b: "a\nc\n",
+ want: " a\n-b\n c",
+ },
+ {
+ name: "added line",
+ a: "a\nc\n",
+ b: "a\nb\nc\n",
+ want: " a\n+b\n c",
+ },
+ {
+ name: "terraform block formatting",
+ a: "resource \"aws_thing\" \"test\" {\nname=\"foo\"\ncount=1\n}\n",
+ b: "resource \"aws_thing\" \"test\" {\n name = \"foo\"\n count = 1\n}\n",
+ want: " resource \"aws_thing\" \"test\" {\n-name=\"foo\"\n-count=1\n+ name = \"foo\"\n+ count = 1\n }",
+ },
+ {
+ name: "empty to content",
+ a: "",
+ b: "a\n",
+ want: "+a",
+ },
+ {
+ name: "no trailing newline",
+ a: "a",
+ b: "b",
+ want: "-a\n+b",
+ },
+ {
+ name: "multibyte runes",
+ a: "héllo wörld\n",
+ b: "héllo world\n",
+ want: "-héllo wörld\n+héllo world",
+ },
+ {
+ name: "identical input",
+ a: "a\nb\n",
+ b: "a\nb\n",
+ want: " a\n b",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ t.Parallel()
+
+ if got := diff.LineDiff(tt.a, tt.b); got != tt.want {
+ t.Errorf("LineDiff(%q, %q) = %q, want %q", tt.a, tt.b, got, tt.want)
+ }
+ })
+ }
+}
diff --git a/vendor/github.com/katbyte/sergi-go-diff/AUTHORS b/lib/diff/diffmatchpatch/AUTHORS
similarity index 100%
rename from vendor/github.com/katbyte/sergi-go-diff/AUTHORS
rename to lib/diff/diffmatchpatch/AUTHORS
diff --git a/vendor/github.com/katbyte/sergi-go-diff/CONTRIBUTORS b/lib/diff/diffmatchpatch/CONTRIBUTORS
similarity index 100%
rename from vendor/github.com/katbyte/sergi-go-diff/CONTRIBUTORS
rename to lib/diff/diffmatchpatch/CONTRIBUTORS
diff --git a/vendor/github.com/katbyte/sergi-go-diff/LICENSE b/lib/diff/diffmatchpatch/LICENSE
similarity index 100%
rename from vendor/github.com/katbyte/sergi-go-diff/LICENSE
rename to lib/diff/diffmatchpatch/LICENSE
diff --git a/vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/diff.go b/lib/diff/diffmatchpatch/diff.go
similarity index 74%
rename from vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/diff.go
rename to lib/diff/diffmatchpatch/diff.go
index cb25b437..7fca701f 100644
--- a/vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/diff.go
+++ b/lib/diff/diffmatchpatch/diff.go
@@ -9,14 +9,9 @@
package diffmatchpatch
import (
- "bytes"
- "errors"
- "fmt"
- "html"
"math"
- "net/url"
"regexp"
- "strconv"
+ "slices"
"strings"
"time"
"unicode/utf8"
@@ -43,7 +38,7 @@ type Diff struct {
}
// splice removes amount elements from slice at index index, replacing them with elements.
-func splice(slice []Diff, index int, amount int, elements ...Diff) []Diff {
+func splice(slice []Diff, index, amount int, elements ...Diff) []Diff {
if len(elements) == amount {
// Easy case: overwrite the relevant items.
copy(slice[index:], elements)
@@ -120,7 +115,7 @@ func (dmp *DiffMatchPatch) diffMainRunes(text1, text2 []rune, checklines bool, d
// Restore the prefix and suffix.
if len(commonprefix) != 0 {
- diffs = append([]Diff{Diff{DiffEqual, string(commonprefix)}}, diffs...)
+ diffs = append([]Diff{{DiffEqual, string(commonprefix)}}, diffs...)
}
if len(commonsuffix) != 0 {
diffs = append(diffs, Diff{DiffEqual, string(commonsuffix)})
@@ -157,16 +152,16 @@ func (dmp *DiffMatchPatch) diffCompute(text1, text2 []rune, checklines bool, dea
}
// Shorter text is inside the longer text (speedup).
return []Diff{
- Diff{op, string(longtext[:i])},
- Diff{DiffEqual, string(shorttext)},
- Diff{op, string(longtext[i+len(shorttext):])},
+ {op, string(longtext[:i])},
+ {DiffEqual, string(shorttext)},
+ {op, string(longtext[i+len(shorttext):])},
}
} else if len(shorttext) == 1 {
// Single character string.
// After the previous speedup, the character can't be an equality.
return []Diff{
- Diff{DiffDelete, string(text1)},
- Diff{DiffInsert, string(text2)},
+ {DiffDelete, string(text1)},
+ {DiffInsert, string(text2)},
}
// Check to see if the problem can be split in two.
} else if hm := dmp.diffHalfMatch(text1, text2); hm != nil {
@@ -231,10 +226,10 @@ func (dmp *DiffMatchPatch) diffLineMode(text1, text2 []rune, deadline time.Time)
pointer = pointer - countDelete - countInsert
a := dmp.diffMainRunes([]rune(textDelete), []rune(textInsert), false, deadline)
- for j := len(a) - 1; j >= 0; j-- {
- diffs = splice(diffs, pointer, 0, a[j])
+ for _, aDiff := range slices.Backward(a) {
+ diffs = splice(diffs, pointer, 0, aDiff)
}
- pointer = pointer + len(a)
+ pointer += len(a)
}
countInsert = 0
@@ -248,14 +243,6 @@ func (dmp *DiffMatchPatch) diffLineMode(text1, text2 []rune, deadline time.Time)
return diffs[:len(diffs)-1] // Remove the dummy entry at the end.
}
-// DiffBisect finds the 'middle snake' of a diff, split the problem in two and return the recursively constructed diff.
-// If an invalid UTF-8 sequence is encountered, it will be replaced by the Unicode replacement character.
-// See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.
-func (dmp *DiffMatchPatch) DiffBisect(text1, text2 string, deadline time.Time) []Diff {
- // Unused in this code, but retained for interface compatibility.
- return dmp.diffBisect([]rune(text1), []rune(text2), deadline)
-}
-
// diffBisect finds the 'middle snake' of a diff, splits the problem in two and returns the recursively constructed diff.
// See Myers's 1986 paper: An O(ND) Difference Algorithm and Its Variations.
func (dmp *DiffMatchPatch) diffBisect(runes1, runes2 []rune, deadline time.Time) []Diff {
@@ -283,7 +270,7 @@ func (dmp *DiffMatchPatch) diffBisect(runes1, runes2 []rune, deadline time.Time)
k1end := 0
k2start := 0
k2end := 0
- for d := 0; d < maxD; d++ {
+ for d := range maxD {
// Bail out if deadline is reached.
if !deadline.IsZero() && d%16 == 0 && time.Now().After(deadline) {
break
@@ -309,13 +296,14 @@ func (dmp *DiffMatchPatch) diffBisect(runes1, runes2 []rune, deadline time.Time)
y1++
}
v1[k1Offset] = x1
- if x1 > runes1Len {
+ switch {
+ case x1 > runes1Len:
// Ran off the right of the graph.
k1end += 2
- } else if y1 > runes2Len {
+ case y1 > runes2Len:
// Ran off the bottom of the graph.
k1start += 2
- } else if front {
+ case front:
k2Offset := vOffset + delta - k1
if k2Offset >= 0 && k2Offset < vLength && v2[k2Offset] != -1 {
// Mirror x2 onto top-left coordinate system.
@@ -336,7 +324,7 @@ func (dmp *DiffMatchPatch) diffBisect(runes1, runes2 []rune, deadline time.Time)
} else {
x2 = v2[k2Offset-1] + 1
}
- var y2 = x2 - k2
+ y2 := x2 - k2
for x2 < runes1Len && y2 < runes2Len {
if runes1[runes1Len-x2-1] != runes2[runes2Len-y2-1] {
break
@@ -345,13 +333,14 @@ func (dmp *DiffMatchPatch) diffBisect(runes1, runes2 []rune, deadline time.Time)
y2++
}
v2[k2Offset] = x2
- if x2 > runes1Len {
+ switch {
+ case x2 > runes1Len:
// Ran off the left of the graph.
k2end += 2
- } else if y2 > runes2Len {
+ case y2 > runes2Len:
// Ran off the top of the graph.
k2start += 2
- } else if !front {
+ case !front:
k1Offset := vOffset + delta - k2
if k1Offset >= 0 && k1Offset < vLength && v1[k1Offset] != -1 {
x1 := v1[k1Offset]
@@ -368,13 +357,14 @@ func (dmp *DiffMatchPatch) diffBisect(runes1, runes2 []rune, deadline time.Time)
}
// Diff took too long and hit the deadline or number of diffs equals number of characters, no commonality at all.
return []Diff{
- Diff{DiffDelete, string(runes1)},
- Diff{DiffInsert, string(runes2)},
+ {DiffDelete, string(runes1)},
+ {DiffInsert, string(runes2)},
}
}
func (dmp *DiffMatchPatch) diffBisectSplit(runes1, runes2 []rune, x, y int,
- deadline time.Time) []Diff {
+ deadline time.Time,
+) []Diff {
runes1a := runes1[:x]
runes2a := runes2[:y]
runes1b := runes1[x:]
@@ -387,33 +377,26 @@ func (dmp *DiffMatchPatch) diffBisectSplit(runes1, runes2 []rune, x, y int,
return append(diffs, diffsb...)
}
-// DiffLinesToChars splits two texts into a list of strings, and educes the texts to a string of hashes where each Unicode character represents one line.
-// It's slightly faster to call DiffLinesToRunes first, followed by DiffMainRunes.
-func (dmp *DiffMatchPatch) DiffLinesToChars(text1, text2 string) (string, string, []string) {
- chars1, chars2, lineArray := dmp.DiffLinesToRunes(text1, text2)
- return string(chars1), string(chars2), lineArray
-}
-
// DiffLinesToRunes splits two texts into a list of runes. Each rune represents one line.
-func (dmp *DiffMatchPatch) DiffLinesToRunes(text1, text2 string) ([]rune, []rune, []string) {
+func (dmp *DiffMatchPatch) DiffLinesToRunes(text1, text2 string) (chars1, chars2 []rune, lineArray []string) {
// '\x00' is a valid character, but various debuggers don't like it. So we'll insert a junk entry to avoid generating a null character.
- lineArray := []string{""} // e.g. lineArray[4] == 'Hello\n'
+ lineArray = []string{""} // e.g. lineArray[4] == 'Hello\n'
lineHash := map[string]int{} // e.g. lineHash['Hello\n'] == 4
- chars1 := dmp.diffLinesToRunesMunge(text1, &lineArray, lineHash)
- chars2 := dmp.diffLinesToRunesMunge(text2, &lineArray, lineHash)
+ chars1 = dmp.diffLinesToRunesMunge(text1, &lineArray, lineHash)
+ chars2 = dmp.diffLinesToRunesMunge(text2, &lineArray, lineHash)
return chars1, chars2, lineArray
}
-func (dmp *DiffMatchPatch) diffLinesToRunes(text1, text2 []rune) ([]rune, []rune, []string) {
+func (dmp *DiffMatchPatch) diffLinesToRunes(text1, text2 []rune) (chars1, chars2 []rune, lineArray []string) {
return dmp.DiffLinesToRunes(string(text1), string(text2))
}
// diffLinesToRunesMunge splits a text into an array of strings, and reduces the texts to a []rune where each Unicode character represents one line.
// We use strings instead of []runes as input mainly because you can't use []rune as a map key.
func (dmp *DiffMatchPatch) diffLinesToRunesMunge(text string, lineArray *[]string, lineHash map[string]int) []rune {
- // Walk the text, pulling out a substring for each line. text.split('\n') would would temporarily double our memory footprint. Modifying text would create many large strings to garbage collect.
+ // Walk the text, pulling out a substring for each line. text.split('\n') would temporarily double our memory footprint. Modifying text would create many large strings to garbage collect.
lineStart := 0
lineEnd := -1
runes := []rune{}
@@ -430,11 +413,11 @@ func (dmp *DiffMatchPatch) diffLinesToRunesMunge(text string, lineArray *[]strin
lineValue, ok := lineHash[line]
if ok {
- runes = append(runes, rune(lineValue))
+ runes = append(runes, rune(lineValue)) //nolint:gosec // G115: line indices cannot realistically overflow rune
} else {
*lineArray = append(*lineArray, line)
lineHash[line] = len(*lineArray) - 1
- runes = append(runes, rune(len(*lineArray)-1))
+ runes = append(runes, rune(len(*lineArray)-1)) //nolint:gosec // G115: line indices cannot realistically overflow rune
}
}
@@ -458,12 +441,6 @@ func (dmp *DiffMatchPatch) DiffCharsToLines(diffs []Diff, lineArray []string) []
return hydrated
}
-// DiffCommonPrefix determines the common prefix length of two strings.
-func (dmp *DiffMatchPatch) DiffCommonPrefix(text1, text2 string) int {
- // Unused in this code, but retained for interface compatibility.
- return commonPrefixLength([]rune(text1), []rune(text2))
-}
-
// DiffCommonSuffix determines the common suffix length of two strings.
func (dmp *DiffMatchPatch) DiffCommonSuffix(text1, text2 string) int {
// Unused in this code, but retained for interface compatibility.
@@ -498,7 +475,7 @@ func commonSuffixLength(text1, text2 []rune) int {
}
// DiffCommonOverlap determines if the suffix of one string is the prefix of another.
-func (dmp *DiffMatchPatch) DiffCommonOverlap(text1 string, text2 string) int {
+func (dmp *DiffMatchPatch) DiffCommonOverlap(text1, text2 string) int {
// Cache the text lengths to prevent multiple calls.
text1Length := len(text1)
text2Length := len(text2)
@@ -537,21 +514,7 @@ func (dmp *DiffMatchPatch) DiffCommonOverlap(text1 string, text2 string) int {
return best
}
-// DiffHalfMatch checks whether the two texts share a substring which is at least half the length of the longer text. This speedup can produce non-minimal diffs.
-func (dmp *DiffMatchPatch) DiffHalfMatch(text1, text2 string) []string {
- // Unused in this code, but retained for interface compatibility.
- runeSlices := dmp.diffHalfMatch([]rune(text1), []rune(text2))
- if runeSlices == nil {
- return nil
- }
-
- result := make([]string, len(runeSlices))
- for i, r := range runeSlices {
- result[i] = string(r)
- }
- return result
-}
-
+// diffHalfMatch checks whether the two texts share a substring which is at least half the length of the longer text. This speedup can produce non-minimal diffs.
func (dmp *DiffMatchPatch) diffHalfMatch(text1, text2 []rune) [][]rune {
if dmp.DiffTimeout <= 0 {
// Don't risk returning a non-optimal diff if we have unlimited time.
@@ -577,14 +540,15 @@ func (dmp *DiffMatchPatch) diffHalfMatch(text1, text2 []rune) [][]rune {
// Check again based on the third quarter.
hm2 := dmp.diffHalfMatchI(longtext, shorttext, int(float64(len(longtext)+1)/2))
- hm := [][]rune{}
- if hm1 == nil && hm2 == nil {
+ var hm [][]rune
+ switch {
+ case hm1 == nil && hm2 == nil:
return nil
- } else if hm2 == nil {
+ case hm2 == nil:
hm = hm1
- } else if hm1 == nil {
+ case hm1 == nil:
hm = hm2
- } else {
+ default:
// Both matched. Select the longest.
if len(hm1[4]) > len(hm2[4]) {
hm = hm1
@@ -677,7 +641,7 @@ func (dmp *DiffMatchPatch) DiffCleanupSemantic(diffs []Diff) []Diff {
// Eliminate an equality that is smaller or equal to the edits on both sides of it.
difference1 := int(math.Max(float64(lengthInsertions1), float64(lengthDeletions1)))
difference2 := int(math.Max(float64(lengthInsertions2), float64(lengthDeletions2)))
- if len(lastequality) > 0 &&
+ if lastequality != "" &&
(len(lastequality) <= difference1) &&
(len(lastequality) <= difference2) {
// Duplicate record.
@@ -708,7 +672,7 @@ func (dmp *DiffMatchPatch) DiffCleanupSemantic(diffs []Diff) []Diff {
pointer++
}
- // Normalize the diff.
+ // Normalise the diff.
if changes {
diffs = dmp.DiffCleanupMerge(diffs)
}
@@ -730,11 +694,9 @@ func (dmp *DiffMatchPatch) DiffCleanupSemantic(diffs []Diff) []Diff {
if overlapLength1 >= overlapLength2 {
if float64(overlapLength1) >= float64(len(deletion))/2 ||
float64(overlapLength1) >= float64(len(insertion))/2 {
-
// Overlap found. Insert an equality and trim the surrounding edits.
diffs = splice(diffs, pointer, 0, Diff{DiffEqual, insertion[:overlapLength1]})
- diffs[pointer-1].Text =
- deletion[0 : len(deletion)-overlapLength1]
+ diffs[pointer-1].Text = deletion[0 : len(deletion)-overlapLength1]
diffs[pointer+1].Text = insertion[overlapLength1:]
pointer++
}
@@ -765,13 +727,12 @@ var (
whitespaceRegex = regexp.MustCompile(`\s`)
linebreakRegex = regexp.MustCompile(`[\r\n]`)
blanklineEndRegex = regexp.MustCompile(`\n\r?\n$`)
- blanklineStartRegex = regexp.MustCompile(`^\r?\n\r?\n`)
)
// diffCleanupSemanticScore computes a score representing whether the internal boundary falls on logical boundaries.
// Scores range from 6 (best) to 0 (worst). Closure, but does not reference any external variables.
func diffCleanupSemanticScore(one, two string) int {
- if len(one) == 0 || len(two) == 0 {
+ if one == "" || two == "" {
// Edges are the best.
return 6
}
@@ -791,19 +752,20 @@ func diffCleanupSemanticScore(one, two string) int {
blankLine1 := lineBreak1 && blanklineEndRegex.MatchString(one)
blankLine2 := lineBreak2 && blanklineEndRegex.MatchString(two)
- if blankLine1 || blankLine2 {
+ switch {
+ case blankLine1 || blankLine2:
// Five points for blank lines.
return 5
- } else if lineBreak1 || lineBreak2 {
+ case lineBreak1 || lineBreak2:
// Four points for line breaks.
return 4
- } else if nonAlphaNumeric1 && !whitespace1 && whitespace2 {
+ case nonAlphaNumeric1 && !whitespace1 && whitespace2:
// Three points for end of sentences.
return 3
- } else if whitespace1 || whitespace2 {
+ case whitespace1 || whitespace2:
// Two points for whitespace.
return 2
- } else if nonAlphaNumeric1 || nonAlphaNumeric2 {
+ case nonAlphaNumeric1 || nonAlphaNumeric2:
// One point for non-alphanumeric.
return 1
}
@@ -819,7 +781,6 @@ func (dmp *DiffMatchPatch) DiffCleanupSemanticLossless(diffs []Diff) []Diff {
for pointer < len(diffs)-1 {
if diffs[pointer-1].Type == DiffEqual &&
diffs[pointer+1].Type == DiffEqual {
-
// This is a single edit surrounded by equalities.
equality1 := diffs[pointer-1].Text
edit := diffs[pointer].Text
@@ -841,7 +802,7 @@ func (dmp *DiffMatchPatch) DiffCleanupSemanticLossless(diffs []Diff) []Diff {
bestScore := diffCleanupSemanticScore(equality1, edit) +
diffCleanupSemanticScore(edit, equality2)
- for len(edit) != 0 && len(equality2) != 0 {
+ for edit != "" && equality2 != "" {
_, sz := utf8.DecodeRuneInString(edit)
if len(equality2) < sz || edit[:sz] != equality2[:sz] {
break
@@ -862,7 +823,7 @@ func (dmp *DiffMatchPatch) DiffCleanupSemanticLossless(diffs []Diff) []Diff {
if diffs[pointer-1].Text != bestEquality1 {
// We have an improvement, save it back to the diff.
- if len(bestEquality1) != 0 {
+ if bestEquality1 != "" {
diffs[pointer-1].Text = bestEquality1
} else {
diffs = splice(diffs, pointer-1, 1)
@@ -870,7 +831,7 @@ func (dmp *DiffMatchPatch) DiffCleanupSemanticLossless(diffs []Diff) []Diff {
}
diffs[pointer].Text = bestEdit
- if len(bestEquality2) != 0 {
+ if bestEquality2 != "" {
diffs[pointer+1].Text = bestEquality2
} else {
diffs = append(diffs[:pointer+1], diffs[pointer+2:]...)
@@ -949,10 +910,9 @@ func (dmp *DiffMatchPatch) DiffCleanupEfficiency(diffs []Diff) []Diff {
if postDel {
sumPres++
}
- if len(lastequality) > 0 &&
+ if lastequality != "" &&
((preIns && preDel && postIns && postDel) ||
((len(lastequality) < dmp.DiffEditCost/2) && sumPres == 3)) {
-
insPoint := equalities.data
// Duplicate record.
@@ -1002,7 +962,6 @@ func (dmp *DiffMatchPatch) DiffCleanupMerge(diffs []Diff) []Diff {
pointer := 0
countDelete := 0
countInsert := 0
- commonlength := 0
textDelete := []rune(nil)
textInsert := []rune(nil)
@@ -1012,24 +971,23 @@ func (dmp *DiffMatchPatch) DiffCleanupMerge(diffs []Diff) []Diff {
countInsert++
textInsert = append(textInsert, []rune(diffs[pointer].Text)...)
pointer++
- break
case DiffDelete:
countDelete++
textDelete = append(textDelete, []rune(diffs[pointer].Text)...)
pointer++
- break
case DiffEqual:
// Upon reaching an equality, check for prior redundancies.
- if countDelete+countInsert > 1 {
+ switch {
+ case countDelete+countInsert > 1:
if countDelete != 0 && countInsert != 0 {
// Factor out any common prefixies.
- commonlength = commonPrefixLength(textInsert, textDelete)
+ commonlength := commonPrefixLength(textInsert, textDelete)
if commonlength != 0 {
x := pointer - countDelete - countInsert
if x > 0 && diffs[x-1].Type == DiffEqual {
diffs[x-1].Text += string(textInsert[:commonlength])
} else {
- diffs = append([]Diff{Diff{DiffEqual, string(textInsert[:commonlength])}}, diffs...)
+ diffs = append([]Diff{{DiffEqual, string(textInsert[:commonlength])}}, diffs...)
pointer++
}
textInsert = textInsert[commonlength:]
@@ -1046,15 +1004,16 @@ func (dmp *DiffMatchPatch) DiffCleanupMerge(diffs []Diff) []Diff {
}
}
// Delete the offending records and add the merged ones.
- if countDelete == 0 {
+ switch {
+ case countDelete == 0:
diffs = splice(diffs, pointer-countInsert,
countDelete+countInsert,
Diff{DiffInsert, string(textInsert)})
- } else if countInsert == 0 {
+ case countInsert == 0:
diffs = splice(diffs, pointer-countDelete,
countDelete+countInsert,
Diff{DiffDelete, string(textDelete)})
- } else {
+ default:
diffs = splice(diffs, pointer-countDelete-countInsert,
countDelete+countInsert,
Diff{DiffDelete, string(textDelete)},
@@ -1068,22 +1027,21 @@ func (dmp *DiffMatchPatch) DiffCleanupMerge(diffs []Diff) []Diff {
if countInsert != 0 {
pointer++
}
- } else if pointer != 0 && diffs[pointer-1].Type == DiffEqual {
+ case pointer != 0 && diffs[pointer-1].Type == DiffEqual:
// Merge this equality with the previous one.
diffs[pointer-1].Text += diffs[pointer].Text
diffs = append(diffs[:pointer], diffs[pointer+1:]...)
- } else {
+ default:
pointer++
}
countInsert = 0
countDelete = 0
textDelete = nil
textInsert = nil
- break
}
}
- if len(diffs[len(diffs)-1].Text) == 0 {
+ if diffs[len(diffs)-1].Text == "" {
diffs = diffs[0 : len(diffs)-1] // Remove the dummy entry at the end.
}
@@ -1105,8 +1063,7 @@ func (dmp *DiffMatchPatch) DiffCleanupMerge(diffs []Diff) []Diff {
} else if strings.HasPrefix(diffs[pointer].Text, diffs[pointer+1].Text) {
// Shift the edit over the next equality.
diffs[pointer-1].Text += diffs[pointer+1].Text
- diffs[pointer].Text =
- diffs[pointer].Text[len(diffs[pointer+1].Text):] + diffs[pointer+1].Text
+ diffs[pointer].Text = diffs[pointer].Text[len(diffs[pointer+1].Text):] + diffs[pointer+1].Text
diffs = splice(diffs, pointer+1, 1)
changes = true
}
@@ -1121,225 +1078,3 @@ func (dmp *DiffMatchPatch) DiffCleanupMerge(diffs []Diff) []Diff {
return diffs
}
-
-// DiffXIndex returns the equivalent location in s2.
-func (dmp *DiffMatchPatch) DiffXIndex(diffs []Diff, loc int) int {
- chars1 := 0
- chars2 := 0
- lastChars1 := 0
- lastChars2 := 0
- lastDiff := Diff{}
- for i := 0; i < len(diffs); i++ {
- aDiff := diffs[i]
- if aDiff.Type != DiffInsert {
- // Equality or deletion.
- chars1 += len(aDiff.Text)
- }
- if aDiff.Type != DiffDelete {
- // Equality or insertion.
- chars2 += len(aDiff.Text)
- }
- if chars1 > loc {
- // Overshot the location.
- lastDiff = aDiff
- break
- }
- lastChars1 = chars1
- lastChars2 = chars2
- }
- if lastDiff.Type == DiffDelete {
- // The location was deleted.
- return lastChars2
- }
- // Add the remaining character length.
- return lastChars2 + (loc - lastChars1)
-}
-
-// DiffPrettyHtml converts a []Diff into a pretty HTML report.
-// It is intended as an example from which to write one's own display functions.
-func (dmp *DiffMatchPatch) DiffPrettyHtml(diffs []Diff) string {
- var buff bytes.Buffer
- for _, diff := range diffs {
- text := strings.Replace(html.EscapeString(diff.Text), "\n", "¶
", -1)
- switch diff.Type {
- case DiffInsert:
- _, _ = buff.WriteString("")
- _, _ = buff.WriteString(text)
- _, _ = buff.WriteString("")
- case DiffDelete:
- _, _ = buff.WriteString("")
- _, _ = buff.WriteString(text)
- _, _ = buff.WriteString("")
- case DiffEqual:
- _, _ = buff.WriteString("")
- _, _ = buff.WriteString(text)
- _, _ = buff.WriteString("")
- }
- }
- return buff.String()
-}
-
-// DiffPrettyText converts a []Diff into a colored text report.
-func (dmp *DiffMatchPatch) DiffPrettyText(diffs []Diff) string {
- var buff bytes.Buffer
- for _, diff := range diffs {
- text := diff.Text
-
- switch diff.Type {
- case DiffInsert:
- _, _ = buff.WriteString("\x1b[32m")
- _, _ = buff.WriteString(text)
- _, _ = buff.WriteString("\x1b[0m")
- case DiffDelete:
- _, _ = buff.WriteString("\x1b[31m")
- _, _ = buff.WriteString(text)
- _, _ = buff.WriteString("\x1b[0m")
- case DiffEqual:
- _, _ = buff.WriteString(text)
- }
- }
-
- return buff.String()
-}
-
-// DiffText1 computes and returns the source text (all equalities and deletions).
-func (dmp *DiffMatchPatch) DiffText1(diffs []Diff) string {
- //StringBuilder text = new StringBuilder()
- var text bytes.Buffer
-
- for _, aDiff := range diffs {
- if aDiff.Type != DiffInsert {
- _, _ = text.WriteString(aDiff.Text)
- }
- }
- return text.String()
-}
-
-// DiffText2 computes and returns the destination text (all equalities and insertions).
-func (dmp *DiffMatchPatch) DiffText2(diffs []Diff) string {
- var text bytes.Buffer
-
- for _, aDiff := range diffs {
- if aDiff.Type != DiffDelete {
- _, _ = text.WriteString(aDiff.Text)
- }
- }
- return text.String()
-}
-
-// DiffLevenshtein computes the Levenshtein distance that is the number of inserted, deleted or substituted characters.
-func (dmp *DiffMatchPatch) DiffLevenshtein(diffs []Diff) int {
- levenshtein := 0
- insertions := 0
- deletions := 0
-
- for _, aDiff := range diffs {
- switch aDiff.Type {
- case DiffInsert:
- insertions += utf8.RuneCountInString(aDiff.Text)
- case DiffDelete:
- deletions += utf8.RuneCountInString(aDiff.Text)
- case DiffEqual:
- // A deletion and an insertion is one substitution.
- levenshtein += max(insertions, deletions)
- insertions = 0
- deletions = 0
- }
- }
-
- levenshtein += max(insertions, deletions)
- return levenshtein
-}
-
-// DiffToDelta crushes the diff into an encoded string which describes the operations required to transform text1 into text2.
-// E.g. =3\t-2\t+ing -> Keep 3 chars, delete 2 chars, insert 'ing'. Operations are tab-separated. Inserted text is escaped using %xx notation.
-func (dmp *DiffMatchPatch) DiffToDelta(diffs []Diff) string {
- var text bytes.Buffer
- for _, aDiff := range diffs {
- switch aDiff.Type {
- case DiffInsert:
- _, _ = text.WriteString("+")
- _, _ = text.WriteString(strings.Replace(url.QueryEscape(aDiff.Text), "+", " ", -1))
- _, _ = text.WriteString("\t")
- break
- case DiffDelete:
- _, _ = text.WriteString("-")
- _, _ = text.WriteString(strconv.Itoa(utf8.RuneCountInString(aDiff.Text)))
- _, _ = text.WriteString("\t")
- break
- case DiffEqual:
- _, _ = text.WriteString("=")
- _, _ = text.WriteString(strconv.Itoa(utf8.RuneCountInString(aDiff.Text)))
- _, _ = text.WriteString("\t")
- break
- }
- }
- delta := text.String()
- if len(delta) != 0 {
- // Strip off trailing tab character.
- delta = delta[0 : utf8.RuneCountInString(delta)-1]
- delta = unescaper.Replace(delta)
- }
- return delta
-}
-
-// DiffFromDelta given the original text1, and an encoded string which describes the operations required to transform text1 into text2, comAdde the full diff.
-func (dmp *DiffMatchPatch) DiffFromDelta(text1 string, delta string) (diffs []Diff, err error) {
- i := 0
- runes := []rune(text1)
-
- for _, token := range strings.Split(delta, "\t") {
- if len(token) == 0 {
- // Blank tokens are ok (from a trailing \t).
- continue
- }
-
- // Each token begins with a one character parameter which specifies the operation of this token (delete, insert, equality).
- param := token[1:]
-
- switch op := token[0]; op {
- case '+':
- // Decode would Diff all "+" to " "
- param = strings.Replace(param, "+", "%2b", -1)
- param, err = url.QueryUnescape(param)
- if err != nil {
- return nil, err
- }
- if !utf8.ValidString(param) {
- return nil, fmt.Errorf("invalid UTF-8 token: %q", param)
- }
-
- diffs = append(diffs, Diff{DiffInsert, param})
- case '=', '-':
- n, err := strconv.ParseInt(param, 10, 0)
- if err != nil {
- return nil, err
- } else if n < 0 {
- return nil, errors.New("Negative number in DiffFromDelta: " + param)
- }
-
- i += int(n)
- // Break out if we are out of bounds, go1.6 can't handle this very well
- if i > len(runes) {
- break
- }
- // Remember that string slicing is by byte - we want by rune here.
- text := string(runes[i-int(n) : i])
-
- if op == '=' {
- diffs = append(diffs, Diff{DiffEqual, text})
- } else {
- diffs = append(diffs, Diff{DiffDelete, text})
- }
- default:
- // Anything else is an error.
- return nil, errors.New("Invalid diff operation in DiffFromDelta: " + string(token[0]))
- }
- }
-
- if i != len(runes) {
- return nil, fmt.Errorf("Delta length (%v) is different from source text length (%v)", i, len(text1))
- }
-
- return diffs, nil
-}
diff --git a/lib/diff/diffmatchpatch/diffmatchpatch.go b/lib/diff/diffmatchpatch/diffmatchpatch.go
new file mode 100644
index 00000000..50b25011
--- /dev/null
+++ b/lib/diff/diffmatchpatch/diffmatchpatch.go
@@ -0,0 +1,35 @@
+// Copyright (c) 2012-2016 The go-diff authors. All rights reserved.
+// https://github.com/sergi/go-diff
+// See the included LICENSE file for license details.
+//
+// go-diff is a Go implementation of Google's Diff, Match, and Patch library
+// Original library is Copyright (c) 2006 Google Inc.
+// http://code.google.com/p/google-diff-match-patch/
+
+// Package diffmatchpatch offers robust algorithms to perform the operations required for synchronising plain text.
+//
+// Absorbed from github.com/sergi/go-diff (via github.com/katbyte/sergi-go-diff,
+// MIT licensed, see LICENSE), trimmed to the diff path used by terrafmt; the
+// match and patch operations have been removed.
+package diffmatchpatch
+
+import (
+ "time"
+)
+
+// DiffMatchPatch holds the configuration for diff-match-patch operations.
+type DiffMatchPatch struct {
+ // Number of seconds to map a diff before giving up (0 for infinity).
+ DiffTimeout time.Duration
+ // Cost of an empty edit operation in terms of edit characters.
+ DiffEditCost int
+}
+
+// New creates a new DiffMatchPatch object with default parameters.
+func New() *DiffMatchPatch {
+ // Defaults.
+ return &DiffMatchPatch{
+ DiffTimeout: time.Second,
+ DiffEditCost: 4,
+ }
+}
diff --git a/vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/stringutil.go b/lib/diff/diffmatchpatch/stringutil.go
similarity index 55%
rename from vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/stringutil.go
rename to lib/diff/diffmatchpatch/stringutil.go
index 265f29cc..231d6f2b 100644
--- a/vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/stringutil.go
+++ b/lib/diff/diffmatchpatch/stringutil.go
@@ -10,20 +10,10 @@ package diffmatchpatch
import (
"strings"
- "unicode/utf8"
)
-// unescaper unescapes selected chars for compatibility with JavaScript's encodeURI.
-// In speed critical applications this could be dropped since the receiving application will certainly decode these fine. Note that this function is case-sensitive. Thus "%3F" would not be unescaped. But this is ok because it is only called with the output of HttpUtility.UrlEncode which returns lowercase hex. Example: "%3f" -> "?", "%24" -> "$", etc.
-var unescaper = strings.NewReplacer(
- "%21", "!", "%7E", "~", "%27", "'",
- "%28", "(", "%29", ")", "%3B", ";",
- "%2F", "/", "%3F", "?", "%3A", ":",
- "%40", "@", "%26", "&", "%3D", "=",
- "%2B", "+", "%24", "$", "%2C", ",", "%23", "#", "%2A", "*")
-
// indexOf returns the first index of pattern in str, starting at str[i].
-func indexOf(str string, pattern string, i int) int {
+func indexOf(str, pattern string, i int) int {
if i > len(str)-1 {
return -1
}
@@ -37,18 +27,6 @@ func indexOf(str string, pattern string, i int) int {
return ind + i
}
-// lastIndexOf returns the last index of pattern in str, starting at str[i].
-func lastIndexOf(str string, pattern string, i int) int {
- if i < 0 {
- return -1
- }
- if i >= len(str) {
- return strings.LastIndex(str, pattern)
- }
- _, size := utf8.DecodeRuneInString(str[i:])
- return strings.LastIndex(str[:i+size], pattern)
-}
-
// runesIndexOf returns the index of pattern in target, starting at target[i].
func runesIndexOf(target, pattern []rune, i int) int {
if i > len(target)-1 {
diff --git a/lib/fmtverbs/fmtverbs_test.go b/lib/fmtverbs/fmtverbs_test.go
index 8c7f8abc..28da3317 100644
--- a/lib/fmtverbs/fmtverbs_test.go
+++ b/lib/fmtverbs/fmtverbs_test.go
@@ -3,7 +3,7 @@ package fmtverbs
import (
"testing"
- "github.com/kylelemons/godebug/diff"
+ "github.com/katbyte/terrafmt/lib/diff"
)
func TestFmtVerbBlock(t *testing.T) {
@@ -716,12 +716,12 @@ resource "other_resource" "test6" {
result := Escape(test.block)
if result != test.expected {
- t.Fatalf("Unexpected escaped result: ('-' actual, '+' expected)\n%s\n", diff.Diff(result, test.expected))
+ t.Fatalf("Unexpected escaped result: ('-' actual, '+' expected)\n%s\n", diff.LineDiff(result, test.expected))
}
roundtrip := Unscape(result)
if roundtrip != test.block {
- t.Fatalf("Did not roundtrip: ('-' actual, '+' expected)\n%s\n", diff.Diff(roundtrip, test.block))
+ t.Fatalf("Did not roundtrip: ('-' actual, '+' expected)\n%s\n", diff.LineDiff(roundtrip, test.block))
}
})
}
diff --git a/vendor/github.com/katbyte/andreyvit-diff/.gitignore b/vendor/github.com/katbyte/andreyvit-diff/.gitignore
deleted file mode 100644
index f96564a0..00000000
--- a/vendor/github.com/katbyte/andreyvit-diff/.gitignore
+++ /dev/null
@@ -1,14 +0,0 @@
-## rubymine project files
-.idea
-
-# Binaries for programs and plugins
-/terrafmt
-
-# Test binary, built with `go test -c`
-*.test
-
-# Output of the go coverage tool, specifically when used with LiteIDE
-*.out
-
-# macOS Finder.app
-.DS_STORE
diff --git a/vendor/github.com/katbyte/andreyvit-diff/README.md b/vendor/github.com/katbyte/andreyvit-diff/README.md
deleted file mode 100644
index 5b52fea8..00000000
--- a/vendor/github.com/katbyte/andreyvit-diff/README.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# diff
-
-Quick'n'easy string diffing functions for Golang based on [github.com/sergi/go-diff](https://github.com/sergi/go-diff). Mainly for diffing strings in tests.
-
-See [the docs on GoDoc](https://godoc.org/github.com/andreyvit/diff).
-
-Get it:
-
- go get -u github.com/andreyvit/diff
-
-Example:
-
- import (
- "strings"
- "testing"
- "github.com/andreyvit/diff"
- )
-
- const expected = `
- ...
- `
-
- func TestFoo(t *testing.T) {
- actual := Foo(...)
- if a, e := strings.TrimSpace(actual), strings.TrimSpace(expected); a != e {
- t.Errorf("Result not as expected:\n%v", diff.LineDiff(e, a))
- }
- }
diff --git a/vendor/github.com/katbyte/andreyvit-diff/doc.go b/vendor/github.com/katbyte/andreyvit-diff/doc.go
deleted file mode 100644
index 98e24708..00000000
--- a/vendor/github.com/katbyte/andreyvit-diff/doc.go
+++ /dev/null
@@ -1,2 +0,0 @@
-// diff provides quick and easy string diffing functions based on github.com/sergi/go-diff, mainly for diffing strings in tests
-package diff
diff --git a/vendor/github.com/katbyte/andreyvit-diff/trim.go b/vendor/github.com/katbyte/andreyvit-diff/trim.go
deleted file mode 100644
index 87871f99..00000000
--- a/vendor/github.com/katbyte/andreyvit-diff/trim.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package diff
-
-import (
- "strings"
-)
-
-// TrimLines applies TrimSpace to each string in the given array.
-func TrimLines(input []string) []string {
- result := make([]string, 0, len(input))
- for _, el := range input {
- result = append(result, strings.TrimSpace(el))
- }
- return result
-}
-
-// TrimLinesInString applies TrimSpace to each line in the given string, and returns the new trimmed string. Empty lines are not removed.
-func TrimLinesInString(input string) string {
- return strings.Join(TrimLines(strings.Split(strings.TrimSpace(input), "\n")), "\n")
-}
diff --git a/vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/diffmatchpatch.go b/vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/diffmatchpatch.go
deleted file mode 100644
index d3acc32c..00000000
--- a/vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/diffmatchpatch.go
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2012-2016 The go-diff authors. All rights reserved.
-// https://github.com/sergi/go-diff
-// See the included LICENSE file for license details.
-//
-// go-diff is a Go implementation of Google's Diff, Match, and Patch library
-// Original library is Copyright (c) 2006 Google Inc.
-// http://code.google.com/p/google-diff-match-patch/
-
-// Package diffmatchpatch offers robust algorithms to perform the operations required for synchronizing plain text.
-package diffmatchpatch
-
-import (
- "time"
-)
-
-// DiffMatchPatch holds the configuration for diff-match-patch operations.
-type DiffMatchPatch struct {
- // Number of seconds to map a diff before giving up (0 for infinity).
- DiffTimeout time.Duration
- // Cost of an empty edit operation in terms of edit characters.
- DiffEditCost int
- // How far to search for a match (0 = exact location, 1000+ = broad match). A match this many characters away from the expected location will add 1.0 to the score (0.0 is a perfect match).
- MatchDistance int
- // When deleting a large block of text (over ~64 characters), how close do the contents have to be to match the expected contents. (0.0 = perfection, 1.0 = very loose). Note that MatchThreshold controls how closely the end points of a delete need to match.
- PatchDeleteThreshold float64
- // Chunk size for context length.
- PatchMargin int
- // The number of bits in an int.
- MatchMaxBits int
- // At what point is no match declared (0.0 = perfection, 1.0 = very loose).
- MatchThreshold float64
-}
-
-// New creates a new DiffMatchPatch object with default parameters.
-func New() *DiffMatchPatch {
- // Defaults.
- return &DiffMatchPatch{
- DiffTimeout: time.Second,
- DiffEditCost: 4,
- MatchThreshold: 0.5,
- MatchDistance: 1000,
- PatchDeleteThreshold: 0.5,
- PatchMargin: 4,
- MatchMaxBits: 32,
- }
-}
diff --git a/vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/match.go b/vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/match.go
deleted file mode 100644
index 17374e10..00000000
--- a/vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/match.go
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright (c) 2012-2016 The go-diff authors. All rights reserved.
-// https://github.com/sergi/go-diff
-// See the included LICENSE file for license details.
-//
-// go-diff is a Go implementation of Google's Diff, Match, and Patch library
-// Original library is Copyright (c) 2006 Google Inc.
-// http://code.google.com/p/google-diff-match-patch/
-
-package diffmatchpatch
-
-import (
- "math"
-)
-
-// MatchMain locates the best instance of 'pattern' in 'text' near 'loc'.
-// Returns -1 if no match found.
-func (dmp *DiffMatchPatch) MatchMain(text, pattern string, loc int) int {
- // Check for null inputs not needed since null can't be passed in C#.
-
- loc = int(math.Max(0, math.Min(float64(loc), float64(len(text)))))
- if text == pattern {
- // Shortcut (potentially not guaranteed by the algorithm)
- return 0
- } else if len(text) == 0 {
- // Nothing to match.
- return -1
- } else if loc+len(pattern) <= len(text) && text[loc:loc+len(pattern)] == pattern {
- // Perfect match at the perfect spot! (Includes case of null pattern)
- return loc
- }
- // Do a fuzzy compare.
- return dmp.MatchBitap(text, pattern, loc)
-}
-
-// MatchBitap locates the best instance of 'pattern' in 'text' near 'loc' using the Bitap algorithm.
-// Returns -1 if no match was found.
-func (dmp *DiffMatchPatch) MatchBitap(text, pattern string, loc int) int {
- // Initialise the alphabet.
- s := dmp.MatchAlphabet(pattern)
-
- // Highest score beyond which we give up.
- scoreThreshold := dmp.MatchThreshold
- // Is there a nearby exact match? (speedup)
- bestLoc := indexOf(text, pattern, loc)
- if bestLoc != -1 {
- scoreThreshold = math.Min(dmp.matchBitapScore(0, bestLoc, loc,
- pattern), scoreThreshold)
- // What about in the other direction? (speedup)
- bestLoc = lastIndexOf(text, pattern, loc+len(pattern))
- if bestLoc != -1 {
- scoreThreshold = math.Min(dmp.matchBitapScore(0, bestLoc, loc,
- pattern), scoreThreshold)
- }
- }
-
- // Initialise the bit arrays.
- matchmask := 1 << uint((len(pattern) - 1))
- bestLoc = -1
-
- var binMin, binMid int
- binMax := len(pattern) + len(text)
- lastRd := []int{}
- for d := 0; d < len(pattern); d++ {
- // Scan for the best match; each iteration allows for one more error. Run a binary search to determine how far from 'loc' we can stray at this error level.
- binMin = 0
- binMid = binMax
- for binMin < binMid {
- if dmp.matchBitapScore(d, loc+binMid, loc, pattern) <= scoreThreshold {
- binMin = binMid
- } else {
- binMax = binMid
- }
- binMid = (binMax-binMin)/2 + binMin
- }
- // Use the result from this iteration as the maximum for the next.
- binMax = binMid
- start := int(math.Max(1, float64(loc-binMid+1)))
- finish := int(math.Min(float64(loc+binMid), float64(len(text))) + float64(len(pattern)))
-
- rd := make([]int, finish+2)
- rd[finish+1] = (1 << uint(d)) - 1
-
- for j := finish; j >= start; j-- {
- var charMatch int
- if len(text) <= j-1 {
- // Out of range.
- charMatch = 0
- } else if _, ok := s[text[j-1]]; !ok {
- charMatch = 0
- } else {
- charMatch = s[text[j-1]]
- }
-
- if d == 0 {
- // First pass: exact match.
- rd[j] = ((rd[j+1] << 1) | 1) & charMatch
- } else {
- // Subsequent passes: fuzzy match.
- rd[j] = ((rd[j+1]<<1)|1)&charMatch | (((lastRd[j+1] | lastRd[j]) << 1) | 1) | lastRd[j+1]
- }
- if (rd[j] & matchmask) != 0 {
- score := dmp.matchBitapScore(d, j-1, loc, pattern)
- // This match will almost certainly be better than any existing match. But check anyway.
- if score <= scoreThreshold {
- // Told you so.
- scoreThreshold = score
- bestLoc = j - 1
- if bestLoc > loc {
- // When passing loc, don't exceed our current distance from loc.
- start = int(math.Max(1, float64(2*loc-bestLoc)))
- } else {
- // Already passed loc, downhill from here on in.
- break
- }
- }
- }
- }
- if dmp.matchBitapScore(d+1, loc, loc, pattern) > scoreThreshold {
- // No hope for a (better) match at greater error levels.
- break
- }
- lastRd = rd
- }
- return bestLoc
-}
-
-// matchBitapScore computes and returns the score for a match with e errors and x location.
-func (dmp *DiffMatchPatch) matchBitapScore(e, x, loc int, pattern string) float64 {
- accuracy := float64(e) / float64(len(pattern))
- proximity := math.Abs(float64(loc - x))
- if dmp.MatchDistance == 0 {
- // Dodge divide by zero error.
- if proximity == 0 {
- return accuracy
- }
-
- return 1.0
- }
- return accuracy + (proximity / float64(dmp.MatchDistance))
-}
-
-// MatchAlphabet initialises the alphabet for the Bitap algorithm.
-func (dmp *DiffMatchPatch) MatchAlphabet(pattern string) map[byte]int {
- s := map[byte]int{}
- charPattern := []byte(pattern)
- for _, c := range charPattern {
- _, ok := s[c]
- if !ok {
- s[c] = 0
- }
- }
- i := 0
-
- for _, c := range charPattern {
- value := s[c] | int(uint(1)< y {
- return x
- }
- return y
-}
diff --git a/vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/operation_string.go b/vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/operation_string.go
deleted file mode 100644
index 533ec0da..00000000
--- a/vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/operation_string.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Code generated by "stringer -type=Operation -trimprefix=Diff"; DO NOT EDIT.
-
-package diffmatchpatch
-
-import "fmt"
-
-const _Operation_name = "DeleteEqualInsert"
-
-var _Operation_index = [...]uint8{0, 6, 11, 17}
-
-func (i Operation) String() string {
- i -= -1
- if i < 0 || i >= Operation(len(_Operation_index)-1) {
- return fmt.Sprintf("Operation(%d)", i+-1)
- }
- return _Operation_name[_Operation_index[i]:_Operation_index[i+1]]
-}
diff --git a/vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/patch.go b/vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/patch.go
deleted file mode 100644
index 223c43c4..00000000
--- a/vendor/github.com/katbyte/sergi-go-diff/diffmatchpatch/patch.go
+++ /dev/null
@@ -1,556 +0,0 @@
-// Copyright (c) 2012-2016 The go-diff authors. All rights reserved.
-// https://github.com/sergi/go-diff
-// See the included LICENSE file for license details.
-//
-// go-diff is a Go implementation of Google's Diff, Match, and Patch library
-// Original library is Copyright (c) 2006 Google Inc.
-// http://code.google.com/p/google-diff-match-patch/
-
-package diffmatchpatch
-
-import (
- "bytes"
- "errors"
- "math"
- "net/url"
- "regexp"
- "strconv"
- "strings"
-)
-
-// Patch represents one patch operation.
-type Patch struct {
- diffs []Diff
- Start1 int
- Start2 int
- Length1 int
- Length2 int
-}
-
-// String emulates GNU diff's format.
-// Header: @@ -382,8 +481,9 @@
-// Indices are printed as 1-based, not 0-based.
-func (p *Patch) String() string {
- var coords1, coords2 string
-
- if p.Length1 == 0 {
- coords1 = strconv.Itoa(p.Start1) + ",0"
- } else if p.Length1 == 1 {
- coords1 = strconv.Itoa(p.Start1 + 1)
- } else {
- coords1 = strconv.Itoa(p.Start1+1) + "," + strconv.Itoa(p.Length1)
- }
-
- if p.Length2 == 0 {
- coords2 = strconv.Itoa(p.Start2) + ",0"
- } else if p.Length2 == 1 {
- coords2 = strconv.Itoa(p.Start2 + 1)
- } else {
- coords2 = strconv.Itoa(p.Start2+1) + "," + strconv.Itoa(p.Length2)
- }
-
- var text bytes.Buffer
- _, _ = text.WriteString("@@ -" + coords1 + " +" + coords2 + " @@\n")
-
- // Escape the body of the patch with %xx notation.
- for _, aDiff := range p.diffs {
- switch aDiff.Type {
- case DiffInsert:
- _, _ = text.WriteString("+")
- case DiffDelete:
- _, _ = text.WriteString("-")
- case DiffEqual:
- _, _ = text.WriteString(" ")
- }
-
- _, _ = text.WriteString(strings.Replace(url.QueryEscape(aDiff.Text), "+", " ", -1))
- _, _ = text.WriteString("\n")
- }
-
- return unescaper.Replace(text.String())
-}
-
-// PatchAddContext increases the context until it is unique, but doesn't let the pattern expand beyond MatchMaxBits.
-func (dmp *DiffMatchPatch) PatchAddContext(patch Patch, text string) Patch {
- if len(text) == 0 {
- return patch
- }
-
- pattern := text[patch.Start2 : patch.Start2+patch.Length1]
- padding := 0
-
- // Look for the first and last matches of pattern in text. If two different matches are found, increase the pattern length.
- for strings.Index(text, pattern) != strings.LastIndex(text, pattern) &&
- len(pattern) < dmp.MatchMaxBits-2*dmp.PatchMargin {
- padding += dmp.PatchMargin
- maxStart := max(0, patch.Start2-padding)
- minEnd := min(len(text), patch.Start2+patch.Length1+padding)
- pattern = text[maxStart:minEnd]
- }
- // Add one chunk for good luck.
- padding += dmp.PatchMargin
-
- // Add the prefix.
- prefix := text[max(0, patch.Start2-padding):patch.Start2]
- if len(prefix) != 0 {
- patch.diffs = append([]Diff{Diff{DiffEqual, prefix}}, patch.diffs...)
- }
- // Add the suffix.
- suffix := text[patch.Start2+patch.Length1 : min(len(text), patch.Start2+patch.Length1+padding)]
- if len(suffix) != 0 {
- patch.diffs = append(patch.diffs, Diff{DiffEqual, suffix})
- }
-
- // Roll back the start points.
- patch.Start1 -= len(prefix)
- patch.Start2 -= len(prefix)
- // Extend the lengths.
- patch.Length1 += len(prefix) + len(suffix)
- patch.Length2 += len(prefix) + len(suffix)
-
- return patch
-}
-
-// PatchMake computes a list of patches.
-func (dmp *DiffMatchPatch) PatchMake(opt ...interface{}) []Patch {
- if len(opt) == 1 {
- diffs, _ := opt[0].([]Diff)
- text1 := dmp.DiffText1(diffs)
- return dmp.PatchMake(text1, diffs)
- } else if len(opt) == 2 {
- text1 := opt[0].(string)
- switch t := opt[1].(type) {
- case string:
- diffs := dmp.DiffMain(text1, t, true)
- if len(diffs) > 2 {
- diffs = dmp.DiffCleanupSemantic(diffs)
- diffs = dmp.DiffCleanupEfficiency(diffs)
- }
- return dmp.PatchMake(text1, diffs)
- case []Diff:
- return dmp.patchMake2(text1, t)
- }
- } else if len(opt) == 3 {
- return dmp.PatchMake(opt[0], opt[2])
- }
- return []Patch{}
-}
-
-// patchMake2 computes a list of patches to turn text1 into text2.
-// text2 is not provided, diffs are the delta between text1 and text2.
-func (dmp *DiffMatchPatch) patchMake2(text1 string, diffs []Diff) []Patch {
- // Check for null inputs not needed since null can't be passed in C#.
- patches := []Patch{}
- if len(diffs) == 0 {
- return patches // Get rid of the null case.
- }
-
- patch := Patch{}
- charCount1 := 0 // Number of characters into the text1 string.
- charCount2 := 0 // Number of characters into the text2 string.
- // Start with text1 (prepatchText) and apply the diffs until we arrive at text2 (postpatchText). We recreate the patches one by one to determine context info.
- prepatchText := text1
- postpatchText := text1
-
- for i, aDiff := range diffs {
- if len(patch.diffs) == 0 && aDiff.Type != DiffEqual {
- // A new patch starts here.
- patch.Start1 = charCount1
- patch.Start2 = charCount2
- }
-
- switch aDiff.Type {
- case DiffInsert:
- patch.diffs = append(patch.diffs, aDiff)
- patch.Length2 += len(aDiff.Text)
- postpatchText = postpatchText[:charCount2] +
- aDiff.Text + postpatchText[charCount2:]
- case DiffDelete:
- patch.Length1 += len(aDiff.Text)
- patch.diffs = append(patch.diffs, aDiff)
- postpatchText = postpatchText[:charCount2] + postpatchText[charCount2+len(aDiff.Text):]
- case DiffEqual:
- if len(aDiff.Text) <= 2*dmp.PatchMargin &&
- len(patch.diffs) != 0 && i != len(diffs)-1 {
- // Small equality inside a patch.
- patch.diffs = append(patch.diffs, aDiff)
- patch.Length1 += len(aDiff.Text)
- patch.Length2 += len(aDiff.Text)
- }
- if len(aDiff.Text) >= 2*dmp.PatchMargin {
- // Time for a new patch.
- if len(patch.diffs) != 0 {
- patch = dmp.PatchAddContext(patch, prepatchText)
- patches = append(patches, patch)
- patch = Patch{}
- // Unlike Unidiff, our patch lists have a rolling context. http://code.google.com/p/google-diff-match-patch/wiki/Unidiff Update prepatch text & pos to reflect the application of the just completed patch.
- prepatchText = postpatchText
- charCount1 = charCount2
- }
- }
- }
-
- // Update the current character count.
- if aDiff.Type != DiffInsert {
- charCount1 += len(aDiff.Text)
- }
- if aDiff.Type != DiffDelete {
- charCount2 += len(aDiff.Text)
- }
- }
-
- // Pick up the leftover patch if not empty.
- if len(patch.diffs) != 0 {
- patch = dmp.PatchAddContext(patch, prepatchText)
- patches = append(patches, patch)
- }
-
- return patches
-}
-
-// PatchDeepCopy returns an array that is identical to a given an array of patches.
-func (dmp *DiffMatchPatch) PatchDeepCopy(patches []Patch) []Patch {
- patchesCopy := []Patch{}
- for _, aPatch := range patches {
- patchCopy := Patch{}
- for _, aDiff := range aPatch.diffs {
- patchCopy.diffs = append(patchCopy.diffs, Diff{
- aDiff.Type,
- aDiff.Text,
- })
- }
- patchCopy.Start1 = aPatch.Start1
- patchCopy.Start2 = aPatch.Start2
- patchCopy.Length1 = aPatch.Length1
- patchCopy.Length2 = aPatch.Length2
- patchesCopy = append(patchesCopy, patchCopy)
- }
- return patchesCopy
-}
-
-// PatchApply merges a set of patches onto the text. Returns a patched text, as well as an array of true/false values indicating which patches were applied.
-func (dmp *DiffMatchPatch) PatchApply(patches []Patch, text string) (string, []bool) {
- if len(patches) == 0 {
- return text, []bool{}
- }
-
- // Deep copy the patches so that no changes are made to originals.
- patches = dmp.PatchDeepCopy(patches)
-
- nullPadding := dmp.PatchAddPadding(patches)
- text = nullPadding + text + nullPadding
- patches = dmp.PatchSplitMax(patches)
-
- x := 0
- // delta keeps track of the offset between the expected and actual location of the previous patch. If there are patches expected at positions 10 and 20, but the first patch was found at 12, delta is 2 and the second patch has an effective expected position of 22.
- delta := 0
- results := make([]bool, len(patches))
- for _, aPatch := range patches {
- expectedLoc := aPatch.Start2 + delta
- text1 := dmp.DiffText1(aPatch.diffs)
- var startLoc int
- endLoc := -1
- if len(text1) > dmp.MatchMaxBits {
- // PatchSplitMax will only provide an oversized pattern in the case of a monster delete.
- startLoc = dmp.MatchMain(text, text1[:dmp.MatchMaxBits], expectedLoc)
- if startLoc != -1 {
- endLoc = dmp.MatchMain(text,
- text1[len(text1)-dmp.MatchMaxBits:], expectedLoc+len(text1)-dmp.MatchMaxBits)
- if endLoc == -1 || startLoc >= endLoc {
- // Can't find valid trailing context. Drop this patch.
- startLoc = -1
- }
- }
- } else {
- startLoc = dmp.MatchMain(text, text1, expectedLoc)
- }
- if startLoc == -1 {
- // No match found. :(
- results[x] = false
- // Subtract the delta for this failed patch from subsequent patches.
- delta -= aPatch.Length2 - aPatch.Length1
- } else {
- // Found a match. :)
- results[x] = true
- delta = startLoc - expectedLoc
- var text2 string
- if endLoc == -1 {
- text2 = text[startLoc:int(math.Min(float64(startLoc+len(text1)), float64(len(text))))]
- } else {
- text2 = text[startLoc:int(math.Min(float64(endLoc+dmp.MatchMaxBits), float64(len(text))))]
- }
- if text1 == text2 {
- // Perfect match, just shove the Replacement text in.
- text = text[:startLoc] + dmp.DiffText2(aPatch.diffs) + text[startLoc+len(text1):]
- } else {
- // Imperfect match. Run a diff to get a framework of equivalent indices.
- diffs := dmp.DiffMain(text1, text2, false)
- if len(text1) > dmp.MatchMaxBits && float64(dmp.DiffLevenshtein(diffs))/float64(len(text1)) > dmp.PatchDeleteThreshold {
- // The end points match, but the content is unacceptably bad.
- results[x] = false
- } else {
- diffs = dmp.DiffCleanupSemanticLossless(diffs)
- index1 := 0
- for _, aDiff := range aPatch.diffs {
- if aDiff.Type != DiffEqual {
- index2 := dmp.DiffXIndex(diffs, index1)
- if aDiff.Type == DiffInsert {
- // Insertion
- text = text[:startLoc+index2] + aDiff.Text + text[startLoc+index2:]
- } else if aDiff.Type == DiffDelete {
- // Deletion
- startIndex := startLoc + index2
- text = text[:startIndex] +
- text[startIndex+dmp.DiffXIndex(diffs, index1+len(aDiff.Text))-index2:]
- }
- }
- if aDiff.Type != DiffDelete {
- index1 += len(aDiff.Text)
- }
- }
- }
- }
- }
- x++
- }
- // Strip the padding off.
- text = text[len(nullPadding) : len(nullPadding)+(len(text)-2*len(nullPadding))]
- return text, results
-}
-
-// PatchAddPadding adds some padding on text start and end so that edges can match something.
-// Intended to be called only from within patchApply.
-func (dmp *DiffMatchPatch) PatchAddPadding(patches []Patch) string {
- paddingLength := dmp.PatchMargin
- nullPadding := ""
- for x := 1; x <= paddingLength; x++ {
- nullPadding += string(x)
- }
-
- // Bump all the patches forward.
- for i := range patches {
- patches[i].Start1 += paddingLength
- patches[i].Start2 += paddingLength
- }
-
- // Add some padding on start of first diff.
- if len(patches[0].diffs) == 0 || patches[0].diffs[0].Type != DiffEqual {
- // Add nullPadding equality.
- patches[0].diffs = append([]Diff{Diff{DiffEqual, nullPadding}}, patches[0].diffs...)
- patches[0].Start1 -= paddingLength // Should be 0.
- patches[0].Start2 -= paddingLength // Should be 0.
- patches[0].Length1 += paddingLength
- patches[0].Length2 += paddingLength
- } else if paddingLength > len(patches[0].diffs[0].Text) {
- // Grow first equality.
- extraLength := paddingLength - len(patches[0].diffs[0].Text)
- patches[0].diffs[0].Text = nullPadding[len(patches[0].diffs[0].Text):] + patches[0].diffs[0].Text
- patches[0].Start1 -= extraLength
- patches[0].Start2 -= extraLength
- patches[0].Length1 += extraLength
- patches[0].Length2 += extraLength
- }
-
- // Add some padding on end of last diff.
- last := len(patches) - 1
- if len(patches[last].diffs) == 0 || patches[last].diffs[len(patches[last].diffs)-1].Type != DiffEqual {
- // Add nullPadding equality.
- patches[last].diffs = append(patches[last].diffs, Diff{DiffEqual, nullPadding})
- patches[last].Length1 += paddingLength
- patches[last].Length2 += paddingLength
- } else if paddingLength > len(patches[last].diffs[len(patches[last].diffs)-1].Text) {
- // Grow last equality.
- lastDiff := patches[last].diffs[len(patches[last].diffs)-1]
- extraLength := paddingLength - len(lastDiff.Text)
- patches[last].diffs[len(patches[last].diffs)-1].Text += nullPadding[:extraLength]
- patches[last].Length1 += extraLength
- patches[last].Length2 += extraLength
- }
-
- return nullPadding
-}
-
-// PatchSplitMax looks through the patches and breaks up any which are longer than the maximum limit of the match algorithm.
-// Intended to be called only from within patchApply.
-func (dmp *DiffMatchPatch) PatchSplitMax(patches []Patch) []Patch {
- patchSize := dmp.MatchMaxBits
- for x := 0; x < len(patches); x++ {
- if patches[x].Length1 <= patchSize {
- continue
- }
- bigpatch := patches[x]
- // Remove the big old patch.
- patches = append(patches[:x], patches[x+1:]...)
- x--
-
- Start1 := bigpatch.Start1
- Start2 := bigpatch.Start2
- precontext := ""
- for len(bigpatch.diffs) != 0 {
- // Create one of several smaller patches.
- patch := Patch{}
- empty := true
- patch.Start1 = Start1 - len(precontext)
- patch.Start2 = Start2 - len(precontext)
- if len(precontext) != 0 {
- patch.Length1 = len(precontext)
- patch.Length2 = len(precontext)
- patch.diffs = append(patch.diffs, Diff{DiffEqual, precontext})
- }
- for len(bigpatch.diffs) != 0 && patch.Length1 < patchSize-dmp.PatchMargin {
- diffType := bigpatch.diffs[0].Type
- diffText := bigpatch.diffs[0].Text
- if diffType == DiffInsert {
- // Insertions are harmless.
- patch.Length2 += len(diffText)
- Start2 += len(diffText)
- patch.diffs = append(patch.diffs, bigpatch.diffs[0])
- bigpatch.diffs = bigpatch.diffs[1:]
- empty = false
- } else if diffType == DiffDelete && len(patch.diffs) == 1 && patch.diffs[0].Type == DiffEqual && len(diffText) > 2*patchSize {
- // This is a large deletion. Let it pass in one chunk.
- patch.Length1 += len(diffText)
- Start1 += len(diffText)
- empty = false
- patch.diffs = append(patch.diffs, Diff{diffType, diffText})
- bigpatch.diffs = bigpatch.diffs[1:]
- } else {
- // Deletion or equality. Only take as much as we can stomach.
- diffText = diffText[:min(len(diffText), patchSize-patch.Length1-dmp.PatchMargin)]
-
- patch.Length1 += len(diffText)
- Start1 += len(diffText)
- if diffType == DiffEqual {
- patch.Length2 += len(diffText)
- Start2 += len(diffText)
- } else {
- empty = false
- }
- patch.diffs = append(patch.diffs, Diff{diffType, diffText})
- if diffText == bigpatch.diffs[0].Text {
- bigpatch.diffs = bigpatch.diffs[1:]
- } else {
- bigpatch.diffs[0].Text =
- bigpatch.diffs[0].Text[len(diffText):]
- }
- }
- }
- // Compute the head context for the next patch.
- precontext = dmp.DiffText2(patch.diffs)
- precontext = precontext[max(0, len(precontext)-dmp.PatchMargin):]
-
- postcontext := ""
- // Append the end context for this patch.
- if len(dmp.DiffText1(bigpatch.diffs)) > dmp.PatchMargin {
- postcontext = dmp.DiffText1(bigpatch.diffs)[:dmp.PatchMargin]
- } else {
- postcontext = dmp.DiffText1(bigpatch.diffs)
- }
-
- if len(postcontext) != 0 {
- patch.Length1 += len(postcontext)
- patch.Length2 += len(postcontext)
- if len(patch.diffs) != 0 && patch.diffs[len(patch.diffs)-1].Type == DiffEqual {
- patch.diffs[len(patch.diffs)-1].Text += postcontext
- } else {
- patch.diffs = append(patch.diffs, Diff{DiffEqual, postcontext})
- }
- }
- if !empty {
- x++
- patches = append(patches[:x], append([]Patch{patch}, patches[x:]...)...)
- }
- }
- }
- return patches
-}
-
-// PatchToText takes a list of patches and returns a textual representation.
-func (dmp *DiffMatchPatch) PatchToText(patches []Patch) string {
- var text bytes.Buffer
- for _, aPatch := range patches {
- _, _ = text.WriteString(aPatch.String())
- }
- return text.String()
-}
-
-// PatchFromText parses a textual representation of patches and returns a List of Patch objects.
-func (dmp *DiffMatchPatch) PatchFromText(textline string) ([]Patch, error) {
- patches := []Patch{}
- if len(textline) == 0 {
- return patches, nil
- }
- text := strings.Split(textline, "\n")
- textPointer := 0
- patchHeader := regexp.MustCompile("^@@ -(\\d+),?(\\d*) \\+(\\d+),?(\\d*) @@$")
-
- var patch Patch
- var sign uint8
- var line string
- for textPointer < len(text) {
-
- if !patchHeader.MatchString(text[textPointer]) {
- return patches, errors.New("Invalid patch string: " + text[textPointer])
- }
-
- patch = Patch{}
- m := patchHeader.FindStringSubmatch(text[textPointer])
-
- patch.Start1, _ = strconv.Atoi(m[1])
- if len(m[2]) == 0 {
- patch.Start1--
- patch.Length1 = 1
- } else if m[2] == "0" {
- patch.Length1 = 0
- } else {
- patch.Start1--
- patch.Length1, _ = strconv.Atoi(m[2])
- }
-
- patch.Start2, _ = strconv.Atoi(m[3])
-
- if len(m[4]) == 0 {
- patch.Start2--
- patch.Length2 = 1
- } else if m[4] == "0" {
- patch.Length2 = 0
- } else {
- patch.Start2--
- patch.Length2, _ = strconv.Atoi(m[4])
- }
- textPointer++
-
- for textPointer < len(text) {
- if len(text[textPointer]) > 0 {
- sign = text[textPointer][0]
- } else {
- textPointer++
- continue
- }
-
- line = text[textPointer][1:]
- line = strings.Replace(line, "+", "%2b", -1)
- line, _ = url.QueryUnescape(line)
- if sign == '-' {
- // Deletion.
- patch.diffs = append(patch.diffs, Diff{DiffDelete, line})
- } else if sign == '+' {
- // Insertion.
- patch.diffs = append(patch.diffs, Diff{DiffInsert, line})
- } else if sign == ' ' {
- // Minor equality.
- patch.diffs = append(patch.diffs, Diff{DiffEqual, line})
- } else if sign == '@' {
- // Start of next patch.
- break
- } else {
- // WTF?
- return patches, errors.New("Invalid patch mode '" + string(sign) + "' in: " + string(line))
- }
- textPointer++
- }
-
- patches = append(patches, patch)
- }
- return patches, nil
-}
diff --git a/vendor/github.com/kylelemons/godebug/LICENSE b/vendor/github.com/kylelemons/godebug/LICENSE
deleted file mode 100644
index d6456956..00000000
--- a/vendor/github.com/kylelemons/godebug/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/vendor/github.com/kylelemons/godebug/diff/diff.go b/vendor/github.com/kylelemons/godebug/diff/diff.go
deleted file mode 100644
index 200e596c..00000000
--- a/vendor/github.com/kylelemons/godebug/diff/diff.go
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright 2013 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package diff implements a linewise diff algorithm.
-package diff
-
-import (
- "bytes"
- "fmt"
- "strings"
-)
-
-// Chunk represents a piece of the diff. A chunk will not have both added and
-// deleted lines. Equal lines are always after any added or deleted lines.
-// A Chunk may or may not have any lines in it, especially for the first or last
-// chunk in a computation.
-type Chunk struct {
- Added []string
- Deleted []string
- Equal []string
-}
-
-func (c *Chunk) empty() bool {
- return len(c.Added) == 0 && len(c.Deleted) == 0 && len(c.Equal) == 0
-}
-
-// Diff returns a string containing a line-by-line unified diff of the linewise
-// changes required to make A into B. Each line is prefixed with '+', '-', or
-// ' ' to indicate if it should be added, removed, or is correct respectively.
-func Diff(A, B string) string {
- aLines := strings.Split(A, "\n")
- bLines := strings.Split(B, "\n")
-
- chunks := DiffChunks(aLines, bLines)
-
- buf := new(bytes.Buffer)
- for _, c := range chunks {
- for _, line := range c.Added {
- fmt.Fprintf(buf, "+%s\n", line)
- }
- for _, line := range c.Deleted {
- fmt.Fprintf(buf, "-%s\n", line)
- }
- for _, line := range c.Equal {
- fmt.Fprintf(buf, " %s\n", line)
- }
- }
- return strings.TrimRight(buf.String(), "\n")
-}
-
-// DiffChunks uses an O(D(N+M)) shortest-edit-script algorithm
-// to compute the edits required from A to B and returns the
-// edit chunks.
-func DiffChunks(a, b []string) []Chunk {
- // algorithm: http://www.xmailserver.org/diff2.pdf
-
- // We'll need these quantities a lot.
- alen, blen := len(a), len(b) // M, N
-
- // At most, it will require len(a) deletions and len(b) additions
- // to transform a into b.
- maxPath := alen + blen // MAX
- if maxPath == 0 {
- // degenerate case: two empty lists are the same
- return nil
- }
-
- // Store the endpoint of the path for diagonals.
- // We store only the a index, because the b index on any diagonal
- // (which we know during the loop below) is aidx-diag.
- // endpoint[maxPath] represents the 0 diagonal.
- //
- // Stated differently:
- // endpoint[d] contains the aidx of a furthest reaching path in diagonal d
- endpoint := make([]int, 2*maxPath+1) // V
-
- saved := make([][]int, 0, 8) // Vs
- save := func() {
- dup := make([]int, len(endpoint))
- copy(dup, endpoint)
- saved = append(saved, dup)
- }
-
- var editDistance int // D
-dLoop:
- for editDistance = 0; editDistance <= maxPath; editDistance++ {
- // The 0 diag(onal) represents equality of a and b. Each diagonal to
- // the left is numbered one lower, to the right is one higher, from
- // -alen to +blen. Negative diagonals favor differences from a,
- // positive diagonals favor differences from b. The edit distance to a
- // diagonal d cannot be shorter than d itself.
- //
- // The iterations of this loop cover either odds or evens, but not both,
- // If odd indices are inputs, even indices are outputs and vice versa.
- for diag := -editDistance; diag <= editDistance; diag += 2 { // k
- var aidx int // x
- switch {
- case diag == -editDistance:
- // This is a new diagonal; copy from previous iter
- aidx = endpoint[maxPath-editDistance+1] + 0
- case diag == editDistance:
- // This is a new diagonal; copy from previous iter
- aidx = endpoint[maxPath+editDistance-1] + 1
- case endpoint[maxPath+diag+1] > endpoint[maxPath+diag-1]:
- // diagonal d+1 was farther along, so use that
- aidx = endpoint[maxPath+diag+1] + 0
- default:
- // diagonal d-1 was farther (or the same), so use that
- aidx = endpoint[maxPath+diag-1] + 1
- }
- // On diagonal d, we can compute bidx from aidx.
- bidx := aidx - diag // y
- // See how far we can go on this diagonal before we find a difference.
- for aidx < alen && bidx < blen && a[aidx] == b[bidx] {
- aidx++
- bidx++
- }
- // Store the end of the current edit chain.
- endpoint[maxPath+diag] = aidx
- // If we've found the end of both inputs, we're done!
- if aidx >= alen && bidx >= blen {
- save() // save the final path
- break dLoop
- }
- }
- save() // save the current path
- }
- if editDistance == 0 {
- return nil
- }
- chunks := make([]Chunk, editDistance+1)
-
- x, y := alen, blen
- for d := editDistance; d > 0; d-- {
- endpoint := saved[d]
- diag := x - y
- insert := diag == -d || (diag != d && endpoint[maxPath+diag-1] < endpoint[maxPath+diag+1])
-
- x1 := endpoint[maxPath+diag]
- var x0, xM, kk int
- if insert {
- kk = diag + 1
- x0 = endpoint[maxPath+kk]
- xM = x0
- } else {
- kk = diag - 1
- x0 = endpoint[maxPath+kk]
- xM = x0 + 1
- }
- y0 := x0 - kk
-
- var c Chunk
- if insert {
- c.Added = b[y0:][:1]
- } else {
- c.Deleted = a[x0:][:1]
- }
- if xM < x1 {
- c.Equal = a[xM:][:x1-xM]
- }
-
- x, y = x0, y0
- chunks[d] = c
- }
- if x > 0 {
- chunks[0].Equal = a[:x]
- }
- if chunks[0].empty() {
- chunks = chunks[1:]
- }
- if len(chunks) == 0 {
- return nil
- }
- return chunks
-}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index ef728b66..dadef79c 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -37,15 +37,6 @@ github.com/hashicorp/hcl/v2/hclwrite
# github.com/inconshreveable/mousetrap v1.1.0
## explicit; go 1.18
github.com/inconshreveable/mousetrap
-# github.com/katbyte/andreyvit-diff v0.0.3
-## explicit; go 1.19
-github.com/katbyte/andreyvit-diff
-# github.com/katbyte/sergi-go-diff v1.2.3
-## explicit; go 1.18
-github.com/katbyte/sergi-go-diff/diffmatchpatch
-# github.com/kylelemons/godebug v1.1.0
-## explicit; go 1.11
-github.com/kylelemons/godebug/diff
# github.com/mitchellh/go-wordwrap v1.0.1
## explicit; go 1.14
github.com/mitchellh/go-wordwrap