Skip to content

Commit cd36bdc

Browse files
committed
Support diffs on strings that already have colors
1 parent d23ae39 commit cd36bdc

File tree

1 file changed

+39
-33
lines changed

1 file changed

+39
-33
lines changed

compiler/src/dotty/tools/dotc/util/DiffUtil.scala

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,27 @@ import scala.collection.mutable
55

66
object DiffUtil {
77

8-
private final val ANSI_DEFAULT = "\u001B[0m"
9-
private final val ANSI_RED = "\u001B[31m"
10-
private final val ANSI_GREEN = "\u001B[32m"
11-
private final val ANSI_EOF = "\u001B[2m"
12-
13-
private final val DELETION_COLOR = ANSI_RED
14-
private final val ADDITION_COLOR = ANSI_GREEN
15-
168
val EOF = new String("EOF") // Unique string up to reference
179

1810
@tailrec private def splitTokens(str: String, acc: List[String] = Nil): List[String] = {
1911
if (str == "") {
2012
acc.reverse
2113
} else {
2214
val head = str.charAt(0)
23-
val (token, rest) = if (Character.isAlphabetic(head) || Character.isDigit(head)) {
24-
str.span(c => Character.isAlphabetic(c) || Character.isDigit(c))
25-
} else if (Character.isMirrored(head) || Character.isWhitespace(head)) {
26-
str.splitAt(1)
27-
} else {
28-
str.span { c =>
29-
!Character.isAlphabetic(c) && !Character.isDigit(c) &&
30-
!Character.isMirrored(c) && !Character.isWhitespace(c)
15+
val (token, rest) =
16+
if (head == '\u001b') { // ansi color token
17+
val splitIndex = str.indexOf('m') + 1
18+
(str.substring(0, splitIndex), str.substring(splitIndex))
19+
} else if (Character.isAlphabetic(head) || Character.isDigit(head)) {
20+
str.span(c => Character.isAlphabetic(c) || Character.isDigit(c) && c != '\u001b')
21+
} else if (Character.isMirrored(head) || Character.isWhitespace(head)) {
22+
str.splitAt(1)
23+
} else {
24+
str.span { c =>
25+
!Character.isAlphabetic(c) && !Character.isDigit(c) &&
26+
!Character.isMirrored(c) && !Character.isWhitespace(c) && c != '\u001b'
27+
}
3128
}
32-
}
3329
splitTokens(rest, token :: acc)
3430
}
3531
}
@@ -48,14 +44,14 @@ object DiffUtil {
4844
case Unmodified(str) => str
4945
case Inserted(str) =>
5046
totalChange += str.length
51-
ADDITION_COLOR + str + ANSI_DEFAULT
47+
added(str)
5248
}.mkString
5349

5450
val fnd = diffAct.collect {
5551
case Unmodified(str) => str
5652
case Inserted(str) =>
5753
totalChange += str.length
58-
DELETION_COLOR + str + ANSI_DEFAULT
54+
deleted(str)
5955
}.mkString
6056

6157
(fnd, exp, totalChange.toDouble / (expected.length + found.length))
@@ -69,25 +65,21 @@ object DiffUtil {
6965
}
7066

7167
val expectedDiff =
72-
if (expected eq EOF) ANSI_EOF + expected + ANSI_DEFAULT
68+
if (expected eq EOF) eof()
7369
else diff.collect {
7470
case Unmodified(str) => str
75-
case Inserted(str) =>
76-
ADDITION_COLOR + str + ANSI_DEFAULT
77-
case Modified(_, str) =>
78-
ADDITION_COLOR + str + ANSI_DEFAULT
71+
case Inserted(str) => added(str)
72+
case Modified(_, str) => added(str)
7973
case Deleted(_) => ""
8074
}.mkString
8175

8276
val actualDiff =
83-
if (actual eq EOF) ANSI_EOF + actual + ANSI_DEFAULT
77+
if (actual eq EOF) eof()
8478
else diff.collect {
8579
case Unmodified(str) => str
8680
case Inserted(_) => ""
87-
case Modified(str, _) =>
88-
DELETION_COLOR + str + ANSI_DEFAULT
89-
case Deleted(str) =>
90-
DELETION_COLOR + str + ANSI_DEFAULT
81+
case Modified(str, _) => deleted(str)
82+
case Deleted(str) => deleted(str)
9183
}.mkString
9284

9385
val pad = " " * 0.max(expectedSize - expected.length)
@@ -103,13 +95,27 @@ object DiffUtil {
10395

10496
diff.collect {
10597
case Unmodified(str) => str
106-
case Inserted(str) => ADDITION_COLOR + str + ANSI_DEFAULT
107-
case Modified(old, str) if printDiffDel => DELETION_COLOR + old + ADDITION_COLOR + str + ANSI_DEFAULT
108-
case Modified(_, str) => ADDITION_COLOR + str + ANSI_DEFAULT
109-
case Deleted(str) if printDiffDel => DELETION_COLOR + str + ANSI_DEFAULT
98+
case Inserted(str) => added(str)
99+
case Modified(old, str) if printDiffDel => deleted(str) + added(str)
100+
case Modified(_, str) => added(str)
101+
case Deleted(str) if printDiffDel => deleted(str)
110102
}.mkString
111103
}
112104

105+
private def added(str: String): String = bgColored(str, Console.GREEN_B)
106+
private def deleted(str: String) = bgColored(str, Console.RED_B)
107+
private def bgColored(str: String, color: String): String = {
108+
if (str.isEmpty) ""
109+
else {
110+
val (spaces, rest) = str.span(c => Character.isSpaceChar(c) || c == '\n')
111+
if (spaces.isEmpty) {
112+
val (text, rest2) = str.span(c => !Character.isSpaceChar(c) && c != '\n')
113+
color + text + Console.RESET + bgColored(rest2, color)
114+
} else spaces + bgColored(rest, color)
115+
}
116+
}
117+
private def eof() = "\u001B[51m" + "EOF" + Console.RESET
118+
113119
private sealed trait Patch
114120
private final case class Unmodified(str: String) extends Patch
115121
private final case class Modified(original: String, str: String) extends Patch

0 commit comments

Comments
 (0)