@@ -12,9 +12,30 @@ import util.SourcePosition
12
12
import scala .collection .mutable
13
13
14
14
trait MessageRendering {
15
+ /** Remove ANSI coloring from `str`, useful for getting real length of
16
+ * strings
17
+ *
18
+ * @return string stripped of ANSI escape codes
19
+ */
15
20
def stripColor (str : String ): String =
16
21
str.replaceAll(" \u001B\\ [[;\\ d]*m" , " " )
17
22
23
+ /** When inlining a method call, if there's an error we'd like to get the
24
+ * outer context and the `pos` at which the call was inlined.
25
+ *
26
+ * @return a list of strings with inline locations
27
+ */
28
+ def outer (pos : SourcePosition , prefix : String )(implicit ctx : Context ): List [String ] =
29
+ if (pos.outer.exists) {
30
+ s " $prefix| This location is in code that was inlined at ${pos.outer}" ::
31
+ outer(pos.outer, prefix)
32
+ } else Nil
33
+
34
+ /** Get the sourcelines before and after the position, as well as the offset
35
+ * for rendering line numbers
36
+ *
37
+ * @return (lines before error, lines after error, line numbers offset)
38
+ */
18
39
def sourceLines (pos : SourcePosition )(implicit ctx : Context ): (List [String ], List [String ], Int ) = {
19
40
var maxLen = Int .MinValue
20
41
def render (xs : List [Int ]) =
@@ -33,6 +54,7 @@ trait MessageRendering {
33
54
(render(before), render(after), maxLen)
34
55
}
35
56
57
+ /** The column markers aligned under the error */
36
58
def columnMarker (pos : SourcePosition , offset : Int )(implicit ctx : Context ): String = {
37
59
val prefix = " " * (offset - 1 )
38
60
val whitespace = " " * pos.startColumn
@@ -45,21 +67,30 @@ trait MessageRendering {
45
67
s " $prefix| $whitespace${carets.show}"
46
68
}
47
69
70
+ /** The error message (`msg`) aligned under `pos`
71
+ *
72
+ * @return aligned error message
73
+ */
48
74
def errorMsg (pos : SourcePosition , msg : String , offset : Int )(implicit ctx : Context ): String = {
49
75
val leastWhitespace = msg.lines.foldLeft(Int .MaxValue ) { (minPad, line) =>
50
76
val lineLength = stripColor(line).length
51
- val padding =
52
- math.min(math.max(0 , ctx.settings.pageWidth.value - offset - lineLength), offset + pos.startColumn)
77
+ val currPad = math.min(
78
+ math.max(0 , ctx.settings.pageWidth.value - offset - lineLength),
79
+ offset + pos.startColumn
80
+ )
53
81
54
- if (padding < minPad) padding
55
- else minPad
82
+ math.min(currPad, minPad)
56
83
}
57
84
58
85
msg.lines
59
- .map { line => " " * (offset - 1 ) + " |" + (" " * (leastWhitespace - offset)) + line }
86
+ .map { line => " " * (offset - 1 ) + " |" + (" " * (leastWhitespace - offset)) + line}
60
87
.mkString(sys.props(" line.separator" ))
61
88
}
62
89
90
+ /** The separator between errors containing the source file and error type
91
+ *
92
+ * @return separator containing error location and kind
93
+ */
63
94
def posStr (pos : SourcePosition , diagnosticLevel : String , message : Message )(implicit ctx : Context ): String =
64
95
if (pos.exists) Blue ({
65
96
val file = pos.source.file.toString
@@ -76,28 +107,32 @@ trait MessageRendering {
76
107
(" -" * math.max(ctx.settings.pageWidth.value - stripColor(prefix).length, 0 ))
77
108
}).show else " "
78
109
110
+ /** Explanation rendered under "Explanation" header */
79
111
def explanation (m : Message )(implicit ctx : Context ): String = {
80
- val sb = new StringBuilder (hl """ |
81
- | ${Blue (" Explanation" )}
82
- | ${Blue (" ===========" )}""" .stripMargin)
112
+ val sb = new StringBuilder (
113
+ hl """ |
114
+ | ${Blue (" Explanation" )}
115
+ | ${Blue (" ===========" )}"""
116
+ )
83
117
sb.append('\n ' ).append(m.explanation)
84
118
if (m.explanation.lastOption != Some ('\n ' )) sb.append('\n ' )
85
119
sb.toString
86
120
}
87
121
122
+ /** The whole message rendered from `msg` */
88
123
def messageAndPos (msg : Message , pos : SourcePosition , diagnosticLevel : String )(implicit ctx : Context ): String = {
89
124
val sb = mutable.StringBuilder .newBuilder
90
125
sb.append(posStr(pos, diagnosticLevel, msg)).append('\n ' )
91
126
if (pos.exists) {
92
127
val (srcBefore, srcAfter, offset) = sourceLines(pos)
93
128
val marker = columnMarker(pos, offset)
94
129
val err = errorMsg(pos, msg.msg, offset)
95
- sb.append((srcBefore ::: marker :: err :: srcAfter).mkString(" \n " ))
130
+ sb.append((srcBefore ::: marker :: err :: outer(pos, " " * (offset - 1 )) ::: srcAfter).mkString(" \n " ))
96
131
} else sb.append(msg.msg)
97
132
sb.toString
98
133
}
99
134
100
- def diagnosticLevel (cont : MessageContainer ): String = {
135
+ def diagnosticLevel (cont : MessageContainer ): String =
101
136
cont match {
102
137
case m : Error => " Error"
103
138
case m : FeatureWarning => " Feature Warning"
@@ -107,5 +142,4 @@ trait MessageRendering {
107
142
case m : Warning => " Warning"
108
143
case m : Info => " Info"
109
144
}
110
- }
111
145
}
0 commit comments