1
1
package dotty .tools .dotc
2
2
package printing
3
- import core .Contexts .Context
4
3
import language .implicitConversions
5
4
6
5
object Texts {
@@ -12,7 +11,7 @@ object Texts {
12
11
def relems : List [Text ]
13
12
14
13
def isEmpty : Boolean = this match {
15
- case Str (s) => s.isEmpty
14
+ case Str (s, _ ) => s.isEmpty
16
15
case Fluid (relems) => relems forall (_.isEmpty)
17
16
case Vertical (relems) => relems.isEmpty
18
17
}
@@ -25,7 +24,7 @@ object Texts {
25
24
def close = new Closed (relems)
26
25
27
26
def remaining (width : Int ): Int = this match {
28
- case Str (s) =>
27
+ case Str (s, _ ) =>
29
28
width - s.length
30
29
case Fluid (Nil ) =>
31
30
width
@@ -37,15 +36,15 @@ object Texts {
37
36
}
38
37
39
38
def lastLine : String = this match {
40
- case Str (s) => s
39
+ case Str (s, _ ) => s
41
40
case _ => relems.head.lastLine
42
41
}
43
42
44
43
def appendToLastLine (that : Text ): Text = that match {
45
- case Str (s2) =>
44
+ case Str (s2, lines1 ) =>
46
45
this match {
47
- case Str (s1) => Str (s1 + s2)
48
- case Fluid (Str (s1) :: prev) => Fluid (Str (s1 + s2) :: prev)
46
+ case Str (s1, lines2 ) => Str (s1 + s2, lines1 union lines2 )
47
+ case Fluid (Str (s1, lines2 ) :: prev) => Fluid (Str (s1 + s2, lines1 union lines2 ) :: prev)
49
48
case Fluid (relems) => Fluid (that :: relems)
50
49
}
51
50
case Fluid (relems) =>
@@ -66,7 +65,7 @@ object Texts {
66
65
}
67
66
68
67
def layout (width : Int ): Text = this match {
69
- case Str (_) =>
68
+ case Str (s, _) =>
70
69
this
71
70
case Fluid (relems) =>
72
71
((Str (" " ): Text ) /: relems.reverse)(_.append(width)(_))
@@ -75,13 +74,13 @@ object Texts {
75
74
}
76
75
77
76
def map (f : String => String ): Text = this match {
78
- case Str (s) => Str (f(s))
77
+ case Str (s, lines ) => Str (f(s), lines )
79
78
case Fluid (relems) => Fluid (relems map (_ map f))
80
79
case Vertical (relems) => Vertical (relems map (_ map f))
81
80
}
82
81
83
82
def stripPrefix (pre : String ): Text = this match {
84
- case Str (s) =>
83
+ case Str (s, _ ) =>
85
84
if (s.startsWith(pre)) s drop pre.length else s
86
85
case Fluid (relems) =>
87
86
val elems = relems.reverse
@@ -94,26 +93,40 @@ object Texts {
94
93
}
95
94
96
95
private def indented : Text = this match {
97
- case Str (s) => Str ((" " * indentMargin) + s)
96
+ case Str (s, lines ) => Str ((" " * indentMargin) + s, lines )
98
97
case Fluid (relems) => Fluid (relems map (_.indented))
99
98
case Vertical (relems) => Vertical (relems map (_.indented))
100
99
}
101
100
102
- def print (sb : StringBuilder ): Unit = this match {
103
- case Str (s) =>
101
+ def print (sb : StringBuilder , numberWidth : Int ): Unit = this match {
102
+ case Str (s, lines) =>
103
+ if (numberWidth != 0 ) {
104
+ val ln = lines.show
105
+ val pad = (numberWidth - ln.length - 1 )
106
+ assert(pad >= 0 )
107
+ sb.append(" " * pad)
108
+ sb.append(ln)
109
+ sb.append(" |" )
110
+ }
104
111
sb.append(s)
105
112
case _ =>
106
113
var follow = false
107
114
for (elem <- relems.reverse) {
108
115
if (follow) sb.append(" \n " )
109
- elem.print(sb)
116
+ elem.print(sb, numberWidth )
110
117
follow = true
111
118
}
112
119
}
113
120
114
- def mkString (width : Int ): String = {
121
+ def maxLine : Int = this match {
122
+ case Str (_, lines) => lines.end
123
+ case _ => (- 1 /: relems)((acc, relem) => acc max relem.maxLine)
124
+ }
125
+
126
+ def mkString (width : Int , withLineNumbers : Boolean ): String = {
115
127
val sb = new StringBuilder
116
- layout(width).print(sb)
128
+ val numberWidth = if (withLineNumbers) (2 * maxLine.toString.length) + 2 else 0
129
+ layout(width - numberWidth).print(sb, numberWidth)
117
130
sb.toString
118
131
}
119
132
@@ -155,7 +168,7 @@ object Texts {
155
168
def lines (xs : Traversable [Text ]) = Vertical (xs.toList.reverse)
156
169
}
157
170
158
- case class Str (s : String ) extends Text {
171
+ case class Str (s : String , lineRange : LineRange = EmptyLineRange ) extends Text {
159
172
override def relems : List [Text ] = List (this )
160
173
}
161
174
@@ -165,4 +178,15 @@ object Texts {
165
178
class Closed (relems : List [Text ]) extends Fluid (relems)
166
179
167
180
implicit def stringToText (s : String ): Text = Str (s)
181
+
182
+ /** Inclusive line range */
183
+ case class LineRange (start : Int , end : Int ) {
184
+ def union (that : LineRange ): LineRange = LineRange (start min that.start, end max that.end)
185
+ def show : String =
186
+ if (start == end) (start + 1 ).toString
187
+ else if (start < end) s " ${start + 1 }- ${end + 1 }"
188
+ else " " // empty range
189
+ }
190
+
191
+ object EmptyLineRange extends LineRange (Int .MaxValue , Int .MinValue )
168
192
}
0 commit comments