package multilinediff import ( "fmt" "strings" "github.com/google/go-cmp/cmp" ) type diffType int const ( diffTypeEqual diffType = iota diffTypeChange diffTypeAdd ) type diffLine struct { diff diffType old string new string } func (l diffLine) toLine(length int) string { line := "" switch l.diff { case diffTypeChange: line += "- " case diffTypeAdd: line += "+ " default: line += " " } line += l.old for i := 0; i < length-len(l.old); i++ { line += " " } line += " " line += l.new return line } type Reporter struct { LineSep string path cmp.Path lines []diffLine diffCount int } func (r *Reporter) PushStep(ps cmp.PathStep) { r.path = append(r.path, ps) } func (r *Reporter) Report(rs cmp.Result) { line := diffLine{} vOld, vNew := r.path.Last().Values() if !rs.Equal() { r.diffCount++ if vOld.IsValid() { line.diff = diffTypeChange line.old = fmt.Sprintf("%+v", vOld) } if vNew.IsValid() { if line.diff == diffTypeEqual { line.diff = diffTypeAdd } line.new = fmt.Sprintf("%+v", vNew) } } else { line.old = fmt.Sprintf("%+v", vOld) line.new = fmt.Sprintf("%+v", vOld) } r.lines = append(r.lines, line) } func (r *Reporter) PopStep() { r.path = r.path[:len(r.path)-1] } func (r *Reporter) String() string { maxLen := 0 for _, l := range r.lines { if len(l.old) > maxLen { maxLen = len(l.old) } } diffLines := []string{} for _, l := range r.lines { diffLines = append(diffLines, l.toLine(maxLen)) } return strings.Join(diffLines, r.LineSep) }