Skip to content

Commit aed0643

Browse files
authored
repl: don't truncate output by default, and allow to configure it (via maxHeight) (#56)
1 parent 5888597 commit aed0643

File tree

7 files changed

+49
-13
lines changed

7 files changed

+49
-13
lines changed

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Scala REPL PlusPlus: a better Scala 3 REPL. With many features inspired by ammon
1616
- [REPL](#repl)
1717
* [Add dependencies with maven coordinates](#add-dependencies-with-maven-coordinates)
1818
* [Importing additional script files interactively](#importing-additional-script-files-interactively)
19+
* [Rendering of output](#rendering-of-output)
1920
- [Scripting](#scripting)
2021
* [Simple "Hello world" script](#simple-hello-world-script)
2122
* [Predef file(s) used in script](#predef-files-used-in-script)
@@ -32,7 +33,6 @@ Scala REPL PlusPlus: a better Scala 3 REPL. With many features inspired by ammon
3233
- [Limitations / Debugging](#limitations--debugging)
3334
* [Why are script line numbers incorrect?](#why-are-script-line-numbers-incorrect)
3435
- [Parameters cheat sheet: the most important ones](#parameters-cheat-sheet-the-most-important-ones)
35-
3636
## Benefits over / comparison with
3737

3838
### Regular Scala REPL
@@ -113,6 +113,19 @@ val foo = 1
113113
println(bar) //1
114114
```
115115

116+
### Rendering of output
117+
118+
Unlike the stock Scala REPL, scala-repl-pp does _not_ truncate the output by default. You can optionally specify the maxHeight parameter though:
119+
```
120+
./scala-repl-pp --maxHeight 5
121+
scala> (1 to 100000).toSeq
122+
val res0: scala.collection.immutable.Range.Inclusive = Range(
123+
1,
124+
2,
125+
3,
126+
...
127+
```
128+
116129
## Scripting
117130

118131
See [ScriptRunnerTest](core/src/test/scala/replpp/scripting/ScriptRunnerTest.scala) for a more complete and in-depth overview.

core/src/main/scala/replpp/Config.scala

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ case class Config(
1111

1212
// repl only
1313
prompt: Option[String] = None,
14-
greeting: String = "Welcome to the scala-repl-pp!",
14+
greeting: String = "Welcome to scala-repl-pp!",
1515
onExitCode: Option[String] = None,
16+
maxHeight: Option[Int] = None,
1617

1718
// script only
1819
scriptFile: Option[Path] = None,
@@ -46,6 +47,10 @@ case class Config(
4647
add("--repo", resolver)
4748
}
4849

50+
maxHeight.foreach { value =>
51+
add("--maxHeight", s"$value")
52+
}
53+
4954
scriptFile.foreach(file => add("--script", file.toString))
5055
command.foreach(cmd => add("--command", cmd))
5156

@@ -100,14 +105,18 @@ object Config {
100105
.text("specify a custom prompt")
101106

102107
opt[String]("greeting")
103-
.valueName("Welcome to the scala-repl-pp!")
108+
.valueName("Welcome to scala-repl-pp!")
104109
.action((x, c) => c.copy(greeting = x))
105110
.text("specify a custom greeting")
106111

107112
opt[String]("onExitCode")
108113
.valueName("""println("bye!")""")
109114
.action((x, c) => c.copy(onExitCode = Option(x)))
110115

116+
opt[Int]("maxHeight")
117+
.action((x, c) => c.copy(maxHeight = Some(x)))
118+
.text("Maximum number lines to print before output gets truncated (default: no limit)")
119+
111120
note("Script execution")
112121

113122
opt[Path]("script")

core/src/main/scala/replpp/InteractiveShell.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ object InteractiveShell {
1717
onExitCode = config.onExitCode,
1818
greeting = Option(config.greeting),
1919
prompt = config.prompt.getOrElse("scala"),
20-
maxPrintElements = Int.MaxValue
20+
maxHeight = config.maxHeight
2121
)
2222

2323
val initialState: State = replDriver.initialState

core/src/main/scala/replpp/PPrinter.scala

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,24 @@ import pprint.{PPrinter, Renderer, Result, Tree, Truncated}
44
import scala.util.matching.Regex
55

66
object PPrinter {
7-
private val pprinter = create()
7+
private var pprinter: pprint.PPrinter = null
8+
private var maxHeight: Int = Int.MaxValue
89

9-
def apply(obj: Object): String =
10-
pprinter(obj).toString
10+
def apply(objectToRender: Object, maxHeight: Int = Int.MaxValue): String = {
11+
val _pprinter = this.synchronized {
12+
// initialise on first use and whenever the maxHeight setting changed
13+
if (pprinter == null || this.maxHeight != maxHeight) {
14+
pprinter = create(maxHeight)
15+
this.maxHeight = maxHeight
16+
}
17+
pprinter
18+
}
19+
_pprinter.apply(objectToRender).render
20+
}
1121

12-
private def create(): pprint.PPrinter = {
22+
private def create(maxHeight: Int): pprint.PPrinter = {
1323
new pprint.PPrinter(
14-
defaultHeight = 99999,
24+
defaultHeight = maxHeight,
1525
colorLiteral = fansi.Attrs.Empty, // leave color highlighting to the repl
1626
colorApplyPrefix = fansi.Attrs.Empty) {
1727

core/src/main/scala/replpp/ReplDriver.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class ReplDriver(args: Array[String],
2727
onExitCode: Option[String] = None,
2828
greeting: Option[String],
2929
prompt: String,
30-
maxPrintElements: Int,
30+
maxHeight: Option[Int] = None,
3131
classLoader: Option[ClassLoader] = None) extends dotty.tools.repl.ReplDriver(args, out, classLoader) {
3232

3333
/** Run REPL with `state` until `:quit` command found
@@ -124,9 +124,10 @@ class ReplDriver(args: Array[String],
124124
// classloader, so we use reflection instead of simply calling `replpp.PPrinter:apply`.
125125
// This is analogous to what happens in dotty.tools.repl.Rendering.
126126
val pprinter = Class.forName("replpp.PPrinter", true, rendering.myClassLoader)
127-
val renderer = pprinter.getMethod("apply", classOf[Object])
128-
(value: Object, maxElements: Int, maxCharacters: Int) =>
129-
renderer.invoke(null, value).asInstanceOf[String].take(maxCharacters)
127+
val renderingMethod = pprinter.getMethod("apply", classOf[Object], classOf[Int])
128+
(objectToRender: Object, maxElements: Int, maxCharacters: Int) => {
129+
renderingMethod.invoke(null, objectToRender, maxHeight.getOrElse(Int.MaxValue)).asInstanceOf[String]
130+
}
130131
}
131132
}
132133

core/src/main/scala/replpp/package.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ package object replpp {
3636
compilerArgs += "-explain" // verbose scalac error messages
3737
compilerArgs += "-deprecation"
3838
if (config.nocolors) compilerArgs ++= Array("-color", "never")
39+
3940
compilerArgs.result()
4041
}
4142

core/src/test/scala/replpp/ConfigTests.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class ConfigTests extends AnyWordSpec with Matchers {
1616
verbose = true,
1717
dependencies = Seq("com.michaelpollmeier:versionsort:1.0.7", "foo:bar:1.2.3"),
1818
resolvers = Seq(apacheRepo, sonatypeRepo),
19+
maxHeight = Some(10000),
1920
scriptFile = Some(Paths.get("/some/script.sc")),
2021
command = Some("someCommand"),
2122
params = Map("param1" -> "value1", "param2" -> "222", "someEquation" -> "40 + 2 = 42"),
@@ -31,6 +32,7 @@ class ConfigTests extends AnyWordSpec with Matchers {
3132
"--dep", "foo:bar:1.2.3",
3233
"--repo", apacheRepo,
3334
"--repo", sonatypeRepo,
35+
"--maxHeight", "10000",
3436
"--script", "/some/script.sc",
3537
"--command", "someCommand",
3638
"--param", "param1=value1",

0 commit comments

Comments
 (0)