Skip to content

Commit 7bf6b7d

Browse files
authored
Consider rendering prefix when pretty printing values in the REPL (#24118)
Previously the initial `val res0: Seq[Int] =` was not considered, so the pretty-printed value when appended to it could over-run the 100-column limit of the REPL. This PR properly takes the last line of the prefix (which can have multiple lines) and passes it to `PPrinter.apply`'s `initialOffset` so the first line considers the prefix and wraps earlier as necessary Tested manually with `Seq.tabulate(22)(identity)`. The single-line output (below) is 104 characters, exceeding the 100 char default limit. With this PR, it properly wraps, while without this PR it doesn't, and you instead need to go all the way up to `Seq.tabulate(27)(identity)` for it to wrap ```scala val res0: Seq[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21) ```
1 parent 903cdf9 commit 7bf6b7d

File tree

1 file changed

+18
-5
lines changed

1 file changed

+18
-5
lines changed

compiler/src/dotty/tools/repl/Rendering.scala

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,23 @@ private[repl] class Rendering(parentClassLoader: Option[ClassLoader] = None):
5353
else str.substring(0, str.offsetByCodePoints(0, maxPrintCharacters - 1))
5454

5555
/** Return a String representation of a value we got from `classLoader()`. */
56-
private[repl] def replStringOf(sym: Symbol, value: Object)(using Context): String = {
56+
private[repl] def replStringOf(value: Object, prefixLength: Int)(using Context): String = {
5757
// pretty-print things with 100 cols 50 rows by default,
58-
dotty.shaded.pprint.PPrinter.BlackWhite.apply(value, width = 100, height = 50).plainText
58+
dotty.shaded.pprint.PPrinter.BlackWhite
59+
.apply(
60+
value,
61+
width = 100,
62+
height = 50,
63+
initialOffset = prefixLength
64+
)
65+
.plainText
5966
}
6067

6168
/** Load the value of the symbol using reflection.
6269
*
6370
* Calling this method evaluates the expression using reflection
6471
*/
65-
private def valueOf(sym: Symbol)(using Context): Option[String] =
72+
private def valueOf(sym: Symbol, prefixLength: Int)(using Context): Option[String] =
6673
val objectName = sym.owner.fullName.encode.toString.stripSuffix("$")
6774
val resObj: Class[?] = Class.forName(objectName, true, classLoader())
6875
val symValue = resObj
@@ -71,7 +78,7 @@ private[repl] class Rendering(parentClassLoader: Option[ClassLoader] = None):
7178
.flatMap(result => rewrapValueClass(sym.info.classSymbol, result.invoke(null)))
7279
symValue
7380
.filter(_ => sym.is(Flags.Method) || sym.info != defn.UnitType)
74-
.map(value => stripReplPrefix(replStringOf(sym, value)))
81+
.map(value => stripReplPrefix(replStringOf(value, prefixLength)))
7582

7683
private def stripReplPrefix(s: String): String =
7784
if (s.startsWith(REPL_WRAPPER_NAME_PREFIX))
@@ -108,7 +115,13 @@ private[repl] class Rendering(parentClassLoader: Option[ClassLoader] = None):
108115
try
109116
Right(
110117
if d.symbol.is(Flags.Lazy) then Some(msg(dcl))
111-
else valueOf(d.symbol).map(value => msg(s"$dcl = $value"))
118+
else {
119+
val prefix = s"$dcl = "
120+
// Prefix can have multiple lines, only consider the last one
121+
// when determining the initial column offset for pretty-printing
122+
val prefixLength = prefix.linesIterator.toSeq.lastOption.getOrElse("").length
123+
valueOf(d.symbol, prefixLength).map(value => msg(s"$prefix$value"))
124+
}
112125
)
113126
catch case e: ReflectiveOperationException => Left(e)
114127
end renderVal

0 commit comments

Comments
 (0)