aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/gotest.tools/internal/format
diff options
context:
space:
mode:
authorMichael Muré <batolettre@gmail.com>2018-09-30 11:10:03 +0200
committerGitHub <noreply@github.com>2018-09-30 11:10:03 +0200
commitd71bb7dd7632780cf5aad5fda84027fa03a9d0f0 (patch)
treedba6c3c0bab18f41e21cd36a9fe05d1d27a574d4 /vendor/gotest.tools/internal/format
parent8fdd6bf99c111c3756056e87ffd9209875ac5c1f (diff)
parentbad9cda969b49bf1bce6799056476ac4684892df (diff)
downloadgit-bug-d71bb7dd7632780cf5aad5fda84027fa03a9d0f0.tar.gz
Merge pull request #54 from MichaelMure/editablecomment
Core support for editable comments
Diffstat (limited to 'vendor/gotest.tools/internal/format')
-rw-r--r--vendor/gotest.tools/internal/format/diff.go161
-rw-r--r--vendor/gotest.tools/internal/format/format.go27
2 files changed, 188 insertions, 0 deletions
diff --git a/vendor/gotest.tools/internal/format/diff.go b/vendor/gotest.tools/internal/format/diff.go
new file mode 100644
index 00000000..c938c97b
--- /dev/null
+++ b/vendor/gotest.tools/internal/format/diff.go
@@ -0,0 +1,161 @@
+package format
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+ "unicode"
+
+ "gotest.tools/internal/difflib"
+)
+
+const (
+ contextLines = 2
+)
+
+// DiffConfig for a unified diff
+type DiffConfig struct {
+ A string
+ B string
+ From string
+ To string
+}
+
+// UnifiedDiff is a modified version of difflib.WriteUnifiedDiff with better
+// support for showing the whitespace differences.
+func UnifiedDiff(conf DiffConfig) string {
+ a := strings.SplitAfter(conf.A, "\n")
+ b := strings.SplitAfter(conf.B, "\n")
+ groups := difflib.NewMatcher(a, b).GetGroupedOpCodes(contextLines)
+ if len(groups) == 0 {
+ return ""
+ }
+
+ buf := new(bytes.Buffer)
+ writeFormat := func(format string, args ...interface{}) {
+ buf.WriteString(fmt.Sprintf(format, args...))
+ }
+ writeLine := func(prefix string, s string) {
+ buf.WriteString(prefix + s)
+ }
+ if hasWhitespaceDiffLines(groups, a, b) {
+ writeLine = visibleWhitespaceLine(writeLine)
+ }
+ formatHeader(writeFormat, conf)
+ for _, group := range groups {
+ formatRangeLine(writeFormat, group)
+ for _, opCode := range group {
+ in, out := a[opCode.I1:opCode.I2], b[opCode.J1:opCode.J2]
+ switch opCode.Tag {
+ case 'e':
+ formatLines(writeLine, " ", in)
+ case 'r':
+ formatLines(writeLine, "-", in)
+ formatLines(writeLine, "+", out)
+ case 'd':
+ formatLines(writeLine, "-", in)
+ case 'i':
+ formatLines(writeLine, "+", out)
+ }
+ }
+ }
+ return buf.String()
+}
+
+// hasWhitespaceDiffLines returns true if any diff groups is only different
+// because of whitespace characters.
+func hasWhitespaceDiffLines(groups [][]difflib.OpCode, a, b []string) bool {
+ for _, group := range groups {
+ in, out := new(bytes.Buffer), new(bytes.Buffer)
+ for _, opCode := range group {
+ if opCode.Tag == 'e' {
+ continue
+ }
+ for _, line := range a[opCode.I1:opCode.I2] {
+ in.WriteString(line)
+ }
+ for _, line := range b[opCode.J1:opCode.J2] {
+ out.WriteString(line)
+ }
+ }
+ if removeWhitespace(in.String()) == removeWhitespace(out.String()) {
+ return true
+ }
+ }
+ return false
+}
+
+func removeWhitespace(s string) string {
+ var result []rune
+ for _, r := range s {
+ if !unicode.IsSpace(r) {
+ result = append(result, r)
+ }
+ }
+ return string(result)
+}
+
+func visibleWhitespaceLine(ws func(string, string)) func(string, string) {
+ mapToVisibleSpace := func(r rune) rune {
+ switch r {
+ case '\n':
+ case ' ':
+ return '·'
+ case '\t':
+ return '▷'
+ case '\v':
+ return '▽'
+ case '\r':
+ return '↵'
+ case '\f':
+ return '↓'
+ default:
+ if unicode.IsSpace(r) {
+ return '�'
+ }
+ }
+ return r
+ }
+ return func(prefix, s string) {
+ ws(prefix, strings.Map(mapToVisibleSpace, s))
+ }
+}
+
+func formatHeader(wf func(string, ...interface{}), conf DiffConfig) {
+ if conf.From != "" || conf.To != "" {
+ wf("--- %s\n", conf.From)
+ wf("+++ %s\n", conf.To)
+ }
+}
+
+func formatRangeLine(wf func(string, ...interface{}), group []difflib.OpCode) {
+ first, last := group[0], group[len(group)-1]
+ range1 := formatRangeUnified(first.I1, last.I2)
+ range2 := formatRangeUnified(first.J1, last.J2)
+ wf("@@ -%s +%s @@\n", range1, range2)
+}
+
+// Convert range to the "ed" format
+func formatRangeUnified(start, stop int) string {
+ // Per the diff spec at http://www.unix.org/single_unix_specification/
+ beginning := start + 1 // lines start numbering with one
+ length := stop - start
+ if length == 1 {
+ return fmt.Sprintf("%d", beginning)
+ }
+ if length == 0 {
+ beginning-- // empty ranges begin at line just before the range
+ }
+ return fmt.Sprintf("%d,%d", beginning, length)
+}
+
+func formatLines(writeLine func(string, string), prefix string, lines []string) {
+ for _, line := range lines {
+ writeLine(prefix, line)
+ }
+ // Add a newline if the last line is missing one so that the diff displays
+ // properly.
+ if !strings.HasSuffix(lines[len(lines)-1], "\n") {
+ writeLine("", "\n")
+ }
+}
diff --git a/vendor/gotest.tools/internal/format/format.go b/vendor/gotest.tools/internal/format/format.go
new file mode 100644
index 00000000..8f6494f9
--- /dev/null
+++ b/vendor/gotest.tools/internal/format/format.go
@@ -0,0 +1,27 @@
+package format // import "gotest.tools/internal/format"
+
+import "fmt"
+
+// Message accepts a msgAndArgs varargs and formats it using fmt.Sprintf
+func Message(msgAndArgs ...interface{}) string {
+ switch len(msgAndArgs) {
+ case 0:
+ return ""
+ case 1:
+ return fmt.Sprintf("%v", msgAndArgs[0])
+ default:
+ return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
+ }
+}
+
+// WithCustomMessage accepts one or two messages and formats them appropriately
+func WithCustomMessage(source string, msgAndArgs ...interface{}) string {
+ custom := Message(msgAndArgs...)
+ switch {
+ case custom == "":
+ return source
+ case source == "":
+ return custom
+ }
+ return fmt.Sprintf("%s: %s", source, custom)
+}