Diff is a silly diff implementation that compares the provided slices and returns a diff of them.
(want, got []T)
| 16 | // Diff is a silly diff implementation |
| 17 | // that compares the provided slices and returns a diff of them. |
| 18 | func Diff[T comparable](want, got []T) string { |
| 19 | // We want to pad diff output with line number in the format: |
| 20 | // |
| 21 | // - 1 | line 1 |
| 22 | // + 2 | line 2 |
| 23 | // |
| 24 | // To do that, we need to know the longest line number. |
| 25 | longest := max(len(want), len(got)) |
| 26 | lineFormat := fmt.Sprintf("%%s %%-%dd | %%v\n", len(strconv.Itoa(longest))) // e.g. "%-2d | %s%v\n" |
| 27 | const ( |
| 28 | minus = "-" |
| 29 | plus = "+" |
| 30 | equal = " " |
| 31 | ) |
| 32 | |
| 33 | var buf strings.Builder |
| 34 | writeLine := func(idx int, kind string, v T) { |
| 35 | fmt.Fprintf(&buf, lineFormat, kind, idx+1, v) |
| 36 | } |
| 37 | |
| 38 | var lastEqs []T |
| 39 | for i := 0; i < len(want) || i < len(got); i++ { |
| 40 | if i < len(want) && i < len(got) && want[i] == got[i] { |
| 41 | lastEqs = append(lastEqs, want[i]) |
| 42 | continue |
| 43 | } |
| 44 | |
| 45 | // If there are any equal lines before this, show up to 3 of them. |
| 46 | if len(lastEqs) > 0 { |
| 47 | start := max(len(lastEqs)-3, 0) |
| 48 | for j, eq := range lastEqs[start:] { |
| 49 | writeLine(i-3+j, equal, eq) |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | if i < len(want) { |
| 54 | writeLine(i, minus, want[i]) |
| 55 | } |
| 56 | if i < len(got) { |
| 57 | writeLine(i, plus, got[i]) |
| 58 | } |
| 59 | |
| 60 | lastEqs = nil |
| 61 | } |
| 62 | |
| 63 | return buf.String() |
| 64 | } |