package cmp
import (
)
func ( formatOptions) ( *valueNode) bool {
switch {
case .DiffMode != diffUnknown:
return false
case .NumDiff == 0:
return false
case !.ValueX.IsValid() || !.ValueY.IsValid():
return false
case .NumIgnored > 0:
return false
case .NumTransformed > 0:
return false
case .NumCompared > 1:
return false
case .NumCompared == 1 && .Type.Name() != "":
return false
}
:= .Type
, := .ValueX, .ValueY
if .Kind() == reflect.Interface && !.IsNil() && !.IsNil() && .Elem().Type() == .Elem().Type() {
, = .Elem(), .Elem()
= .Type()
}
switch .Kind() {
case reflect.String:
case reflect.Array, reflect.Slice:
switch .Elem().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
default:
return false
}
if .Kind() == reflect.Slice && (.Len() == 0 || .Len() == 0) {
return false
}
if .NumDiff > .NumSame {
return true
}
default:
return false
}
const = 32
return .Len() >= && .Len() >=
}
func ( formatOptions) ( *valueNode) textNode {
assert(.DiffMode == diffUnknown)
, , := .Type, .ValueX, .ValueY
if .Kind() == reflect.Interface {
, = .Elem(), .Elem()
= .Type()
= .WithTypeMode(emitType)
}
var , string
var , []string
var , , , bool
switch {
case .Kind() == reflect.String:
, = .String(), .String()
= true
case .Kind() == reflect.Slice && .Elem() == byteType:
, = string(.Bytes()), string(.Bytes())
= true
case .Kind() == reflect.Array:
, := reflect.New().Elem(), reflect.New().Elem()
.Set()
.Set()
, = ,
}
if {
var , , , , int
for , := range + {
++
if (unicode.IsPrint() || unicode.IsSpace()) && != utf8.RuneError {
++
}
if == '\n' {
if < - {
= -
}
= + 1
++
}
}
:= ==
= float64() > math.Floor(0.90*float64())
= && >= 4 && <= 1024
= !
if {
= strings.Split(, "\n")
= strings.Split(, "\n")
:= diff.Difference(len(), len(), func(, int) diff.Result {
return diff.BoolResult([] == [])
})
:= diff.Difference(len(), len(), func(, int) diff.Result {
return diff.BoolResult([] == [])
})
:= float64(.Dist()) / float64(len())
:= float64(.Dist()) / float64(len())
:= len(strconv.Quote( + ))
:= len() + len()
:= float64() / float64()
= < 4* || > 1.1
}
}
var textList
var string
switch {
case :
= .formatDiffSlice(
reflect.ValueOf(), reflect.ValueOf(), 1, "line",
func( reflect.Value, diffMode) textRecord {
:= formatString(.Index(0).String())
return textRecord{Diff: , Value: textLine()}
},
)
= "\n"
:= true
:= map[string]bool{}
:= map[string]bool{}
var textList
= append(, textRecord{Value: textLine(`"""`), ElideComma: true})
for , := range {
if !.Value.Equal(textEllipsis) {
, := strconv.Unquote(string(.Value.(textLine)))
= strings.TrimPrefix(strings.TrimSuffix(, "\r"), "\r")
:= strings.Map(func( rune) rune {
if unicode.IsSpace() {
return -1
}
return
}, )
:= func( rune) bool {
return unicode.IsPrint() || == '\t'
}
= !strings.HasPrefix(, `"""`) && !strings.HasPrefix(, "...") && strings.TrimFunc(, ) == ""
switch .Diff {
case diffRemoved:
= && ![]
[] = true
case diffInserted:
= && ![]
[] = true
}
if ! {
break
}
.Value = textLine()
.ElideComma = true
}
if !(.Diff == diffRemoved || .Diff == diffInserted) {
= map[string]bool{}
= map[string]bool{}
}
= append(, )
}
if := [len()-1]; .Diff == diffIdentical && len(.Value.(textLine)) == 0 {
= [:len()-1]
}
= append(, textRecord{Value: textLine(`"""`), ElideComma: true})
if {
var textNode = &textWrap{Prefix: "(", Value: , Suffix: ")"}
switch .Kind() {
case reflect.String:
if != stringType {
= .FormatType(, )
}
case reflect.Slice:
= .WithTypeMode(emitType)
= .FormatType(, )
}
return
}
case :
= .formatDiffSlice(
reflect.ValueOf(), reflect.ValueOf(), 64, "byte",
func( reflect.Value, diffMode) textRecord {
:= formatString(.String())
return textRecord{Diff: , Value: textLine()}
},
)
case :
= .formatDiffSlice(
reflect.ValueOf(), reflect.ValueOf(), 16, "byte",
func( reflect.Value, diffMode) textRecord {
var []string
for := 0; < .Len(); ++ {
= append(, formatHex(.Index().Uint()))
}
:= strings.Join(, ", ")
:= commentString(fmt.Sprintf("%c|%v|", , formatASCII(.String())))
return textRecord{Diff: , Value: textLine(), Comment: }
},
)
default:
var int
if .Elem().Kind() == reflect.Bool {
= 16
} else {
switch .Elem().Bits() {
case 8:
= 16
case 16:
= 12
case 32:
= 8
default:
= 8
}
}
= .formatDiffSlice(
, , , .Elem().Kind().String(),
func( reflect.Value, diffMode) textRecord {
var []string
for := 0; < .Len(); ++ {
switch .Elem().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
= append(, fmt.Sprint(.Index().Int()))
case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
= append(, fmt.Sprint(.Index().Uint()))
case reflect.Uint8, reflect.Uintptr:
= append(, formatHex(.Index().Uint()))
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
= append(, fmt.Sprint(.Index().Interface()))
}
}
:= strings.Join(, ", ")
return textRecord{Diff: , Value: textLine()}
},
)
}
var textNode = &textWrap{Prefix: "{", Value: , Suffix: "}"}
if ! {
if .Kind() == reflect.String {
= .WithTypeMode(emitType)
}
return .FormatType(, )
}
switch .Kind() {
case reflect.String:
= &textWrap{Prefix: "strings.Join(", Value: , Suffix: fmt.Sprintf(", %q)", )}
if != stringType {
= .FormatType(, )
}
case reflect.Slice:
= &textWrap{Prefix: "bytes.Join(", Value: , Suffix: fmt.Sprintf(", %q)", )}
if != bytesType {
= .FormatType(, )
}
}
return
}
func ( string) string {
:= bytes.Repeat([]byte{'.'}, len())
for := 0; < len(); ++ {
if ' ' <= [] && [] <= '~' {
[] = []
}
}
return string()
}
func ( formatOptions) (
, reflect.Value, int, string,
func(reflect.Value, diffMode) textRecord,
) ( textList) {
:= func(, int) bool {
return .Index().Interface() == .Index().Interface()
}
:= diff.Difference(.Len(), .Len(), func(, int) diff.Result {
return diff.BoolResult((, ))
})
:= func( reflect.Value, diffMode) int {
:= .Len()
for .Len() > 0 {
:=
if > .Len() {
= .Len()
}
= append(, (.Slice(0, ), ))
= .Slice(, .Len())
}
return - .Len()
}
var int
:= -1
if .LimitVerbosity {
= (1 << .verbosity()) << 2
.VerbosityLevel--
}
:= coalesceAdjacentEdits(, )
= coalesceInterveningIdentical(, /4)
= cleanupSurroundingIdentical(, )
:= diffStats{Name: }
for , := range {
if >= 0 && >= {
= .Append()
continue
}
if .NumDiff() == 0 {
var , int
:= .NumIgnored + .NumIdentical
for < *numContextRecords && + < && != 0 {
++
}
for < *numContextRecords && + < && != len()-1 {
++
}
if -(+) <= && .NumIgnored == 0 {
= -
}
(.Slice(0, ), diffIdentical)
if > + {
.NumIdentical -= +
.AppendEllipsis()
}
(.Slice(-, ), diffIdentical)
= .Slice(, .Len())
= .Slice(, .Len())
continue
}
:= len()
:= (.Slice(0, .NumIdentical+.NumRemoved+.NumModified), diffRemoved)
= .Slice(, .Len())
:= (.Slice(0, .NumIdentical+.NumInserted+.NumModified), diffInserted)
= .Slice(, .Len())
+= len() -
}
if .IsZero() {
assert(.Len() == 0 && .Len() == 0)
} else {
.AppendEllipsis()
}
return
}
func ( string, diff.EditScript) ( []diffStats) {
var byte
:= func( byte) *diffStats {
if != {
= append(, diffStats{Name: })
=
}
return &[len()-1]
}
for , := range {
switch {
case diff.Identity:
('=').NumIdentical++
case diff.UniqueX:
('!').NumRemoved++
case diff.UniqueY:
('!').NumInserted++
case diff.Modified:
('!').NumModified++
}
}
return
}
func ( []diffStats, int) []diffStats {
, := [:0],
for , := range {
if len() >= 2 && .NumDiff() > 0 {
:= &[len()-2]
:= &[len()-1]
:= &[]
, := .NumRemoved > 0, .NumInserted > 0
, := .NumRemoved > 0, .NumInserted > 0
if (( || ) && ( || )) && .NumIdentical <= {
* = .Append(*).Append(*)
= [:len()-1]
continue
}
}
= append(, )
}
return
}
func ( []diffStats, func(, int) bool) []diffStats {
var , int
for , := range {
if .NumDiff() == 0 {
+= .NumIdentical
+= .NumIdentical
continue
}
:= .NumIdentical + .NumRemoved + .NumModified
:= .NumIdentical + .NumInserted + .NumModified
var , int
for := 0; < && < && (+, +); ++ {
++
}
for := 0; < && < && (+-1-, +-1-); ++ {
++
}
if := + ; > 0 {
if > 0 {
if -1 >= 0 {
[-1].NumIdentical +=
} else {
defer func() {
= append([]diffStats{{Name: [0].Name, NumIdentical: }}, ...)
}()
}
+=
+=
}
if > 0 {
if +1 < len() {
[+1].NumIdentical +=
} else {
defer func() {
= append(, diffStats{Name: [len()-1].Name, NumIdentical: })
}()
}
}
-=
-=
[] = diffStats{Name: .Name, NumRemoved: , NumInserted: }
}
+=
+=
}
return
}