FormatDiffSlice prints a diff for the slices (or strings) represented by v. This provides custom-tailored logic to make printing of differences in textual strings and slices of primitive kinds more readable.
(v *valueNode)
| 88 | // This provides custom-tailored logic to make printing of differences in |
| 89 | // textual strings and slices of primitive kinds more readable. |
| 90 | func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { |
| 91 | assert(opts.DiffMode == diffUnknown) |
| 92 | t, vx, vy := v.Type, v.ValueX, v.ValueY |
| 93 | if t.Kind() == reflect.Interface { |
| 94 | vx, vy = vx.Elem(), vy.Elem() |
| 95 | t = vx.Type() |
| 96 | opts = opts.WithTypeMode(emitType) |
| 97 | } |
| 98 | |
| 99 | // Auto-detect the type of the data. |
| 100 | var sx, sy string |
| 101 | var ssx, ssy []string |
| 102 | var isString, isMostlyText, isPureLinedText, isBinary bool |
| 103 | switch { |
| 104 | case t.Kind() == reflect.String: |
| 105 | sx, sy = vx.String(), vy.String() |
| 106 | isString = true |
| 107 | case t.Kind() == reflect.Slice && t.Elem() == byteType: |
| 108 | sx, sy = string(vx.Bytes()), string(vy.Bytes()) |
| 109 | isString = true |
| 110 | case t.Kind() == reflect.Array: |
| 111 | // Arrays need to be addressable for slice operations to work. |
| 112 | vx2, vy2 := reflect.New(t).Elem(), reflect.New(t).Elem() |
| 113 | vx2.Set(vx) |
| 114 | vy2.Set(vy) |
| 115 | vx, vy = vx2, vy2 |
| 116 | } |
| 117 | if isString { |
| 118 | var numTotalRunes, numValidRunes, numLines, lastLineIdx, maxLineLen int |
| 119 | for i, r := range sx + sy { |
| 120 | numTotalRunes++ |
| 121 | if (unicode.IsPrint(r) || unicode.IsSpace(r)) && r != utf8.RuneError { |
| 122 | numValidRunes++ |
| 123 | } |
| 124 | if r == '\n' { |
| 125 | if maxLineLen < i-lastLineIdx { |
| 126 | maxLineLen = i - lastLineIdx |
| 127 | } |
| 128 | lastLineIdx = i + 1 |
| 129 | numLines++ |
| 130 | } |
| 131 | } |
| 132 | isPureText := numValidRunes == numTotalRunes |
| 133 | isMostlyText = float64(numValidRunes) > math.Floor(0.90*float64(numTotalRunes)) |
| 134 | isPureLinedText = isPureText && numLines >= 4 && maxLineLen <= 1024 |
| 135 | isBinary = !isMostlyText |
| 136 | |
| 137 | // Avoid diffing by lines if it produces a significantly more complex |
| 138 | // edit script than diffing by bytes. |
| 139 | if isPureLinedText { |
| 140 | ssx = strings.Split(sx, "\n") |
| 141 | ssy = strings.Split(sy, "\n") |
| 142 | esLines := diff.Difference(len(ssx), len(ssy), func(ix, iy int) diff.Result { |
| 143 | return diff.BoolResult(ssx[ix] == ssy[iy]) |
| 144 | }) |
| 145 | esBytes := diff.Difference(len(sx), len(sy), func(ix, iy int) diff.Result { |
| 146 | return diff.BoolResult(sx[ix] == sy[iy]) |
| 147 | }) |
no test coverage detected