@@ -54,7 +54,39 @@ object AssertionError {
5454 case DiffElement .InBoth (x) => render0(" " , x, fansi.Attrs .Empty )
5555 case DiffElement .InFirst (x) => renderRed(x)
5656 case DiffElement .InSecond (x) => renderGreen(x)
57- case DiffElement .Diff (x, y) => renderRed(x) ++ renderGreen(y)
57+ case DiffElement .Diff (x, y) =>
58+ // Within any adjacent blocks of differing text, do a char-by-char
59+ // diff between the two versions so we can underline the characters
60+ // that differ between them
61+ val subDiff = StringDiff .diff(x.map(_.plainText).mkString, y.map(_.plainText).mkString)
62+ val sectionsX = subDiff.collect{
63+ case DiffElement .InBoth (x) => (false , x.length)
64+ case DiffElement .InFirst (x) => (true , x.length)
65+ case DiffElement .Diff (x, y) => (true , x.length)
66+ }
67+
68+ val sectionsY = subDiff.collect{
69+ case DiffElement .InBoth (x) => (false , x.length)
70+ case DiffElement .InSecond (x) => (true , x.length)
71+ case DiffElement .Diff (x, y) => (true , y.length)
72+ }
73+
74+ def sectionsToOverlays (sections : Seq [(Boolean , Int )]) = {
75+ val buffer = collection.mutable.Buffer .empty[(fansi.Attrs , Int , Int )]
76+ var index = 0
77+ for ((underline, length) <- sections) {
78+ val nextIndex = index + length
79+ if (underline) buffer.append((fansi.Underlined .On , index, nextIndex))
80+ index = nextIndex
81+ }
82+ buffer.toSeq
83+ }
84+
85+ val overlaysX = sectionsToOverlays(sectionsX)
86+ val overlaysY = sectionsToOverlays(sectionsY)
87+
88+ renderRed(splitLines(fansi.Str .join(x).overlayAll(overlaysX))) ++
89+ renderGreen(splitLines(fansi.Str .join(y).overlayAll(overlaysY)))
5890 }
5991 }
6092 def render (msgPrefix : String , captured : Seq [TestValue ]) = {
0 commit comments