summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/Properties.scala4
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ILoop.scala65
-rw-r--r--src/repl/scala/tools/nsc/interpreter/LoopCommands.scala4
-rw-r--r--src/repl/scala/tools/nsc/interpreter/SimpleReader.scala29
4 files changed, 67 insertions, 35 deletions
diff --git a/src/compiler/scala/tools/nsc/Properties.scala b/src/compiler/scala/tools/nsc/Properties.scala
index bec686ec05..9f160e2485 100644
--- a/src/compiler/scala/tools/nsc/Properties.scala
+++ b/src/compiler/scala/tools/nsc/Properties.scala
@@ -14,7 +14,9 @@ object Properties extends scala.util.PropertiesTrait {
// settings based on jar properties, falling back to System prefixed by "scala."
def residentPromptString = scalaPropOrElse("resident.prompt", "\nnsc> ")
def shellPromptString = scalaPropOrElse("shell.prompt", "\nscala> ")
- def shellInterruptedString = scalaPropOrElse("shell.interrupted", ":quit\n")
+ // message to display at EOF (which by default ends with
+ // a newline so as not to break the user's terminal)
+ def shellInterruptedString = scalaPropOrElse("shell.interrupted", f":quit$lineSeparator")
// derived values
def isEmacsShell = propOrEmpty("env.emacs") != ""
diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
index 6e18682494..1c751c8a9f 100644
--- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
@@ -392,23 +392,23 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
true
}
+ // after process line, OK continue, ERR break, or EOF all done
+ object LineResults extends Enumeration {
+ type LineResult = Value
+ val EOF, ERR, OK = Value
+ }
+ import LineResults.LineResult
+
// return false if repl should exit
def processLine(line: String): Boolean = {
import scala.concurrent.duration._
Await.ready(globalFuture, 10.minutes) // Long timeout here to avoid test failures under heavy load.
- if (line eq null) {
- // SI-4563: this means the console was properly interrupted (Ctrl+D usually)
- // so we display the output message (which by default ends with
- // a newline so as not to break the user's terminal)
- if (in.interactive) out.print(Properties.shellInterruptedString)
-
- false
- } else (command(line) match {
+ command(line) match {
case Result(false, _) => false
case Result(_, Some(line)) => addReplay(line) ; true
case _ => true
- })
+ }
}
private def readOneLine() = {
@@ -426,18 +426,22 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
* command() for each line of input, and stops when
* command() returns false.
*/
- @tailrec final def loop() {
- if ( try processLine(readOneLine()) catch crashRecovery )
- loop()
+ @tailrec final def loop(): LineResult = {
+ import LineResults._
+ readOneLine() match {
+ case null => EOF
+ case line => if (try processLine(line) catch crashRecovery) loop() else ERR
+ }
}
/** interpret all lines from a specified file */
- def interpretAllFrom(file: File) {
+ def interpretAllFrom(file: File, verbose: Boolean = false) {
savingReader {
savingReplayStack {
file applyReader { reader =>
- in = SimpleReader(reader, out, interactive = false)
- echo("Loading " + file + "...")
+ in = if (verbose) new SimpleReader(reader, out, interactive = true) with EchoReader
+ else SimpleReader(reader, out, interactive = false)
+ echo(s"Loading $file...")
loop()
}
}
@@ -592,13 +596,17 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
res
}
- def loadCommand(arg: String) = {
- var shouldReplay: Option[String] = None
- withFile(arg)(f => {
- interpretAllFrom(f)
- shouldReplay = Some(":load " + arg)
- })
- Result(keepRunning = true, shouldReplay)
+ def loadCommand(arg: String): Result = {
+ def run(file: String, verbose: Boolean) = withFile(file) { f =>
+ interpretAllFrom(f, verbose)
+ Result recording s":load $arg"
+ } getOrElse Result.default
+
+ words(arg) match {
+ case "-v" :: file :: Nil => run(file, verbose = true)
+ case file :: Nil => run(file, verbose = false)
+ case _ => echo("usage: :load -v file") ; Result.default
+ }
}
def saveCommand(filename: String): Result = (
@@ -685,13 +693,13 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
}
val code = file match {
case Some(name) =>
- withFile(name)(f => {
+ withFile(name) { f =>
shouldReplay = Some(s":paste $arg")
val s = f.slurp.trim
if (s.isEmpty) echo(s"File contains no code: $f")
else echo(s"Pasting file $f...")
s
- }) getOrElse ""
+ } getOrElse ""
case None =>
echo("// Entering paste mode (ctrl-D to finish)\n")
val text = (readWhile(_ => true) mkString "\n").trim
@@ -820,7 +828,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
)
catch {
case ex @ (_: Exception | _: NoClassDefFoundError) =>
- echo("Failed to created JLineReader: " + ex + "\nFalling back to SimpleReader.")
+ echo(f"Failed to created JLineReader: ${ex}%nFalling back to SimpleReader.")
SimpleReader()
}
}
@@ -847,6 +855,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
case _ =>
}
}
+
+ // start an interpreter with the given settings
def process(settings: Settings): Boolean = savingContextLoader {
this.settings = settings
createInterpreter()
@@ -861,7 +871,10 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
loadFiles(settings)
printWelcome()
- try loop()
+ try loop() match {
+ case LineResults.EOF => out print Properties.shellInterruptedString
+ case _ =>
+ }
catch AbstractOrMissingHandler()
finally closeInterpreter()
diff --git a/src/repl/scala/tools/nsc/interpreter/LoopCommands.scala b/src/repl/scala/tools/nsc/interpreter/LoopCommands.scala
index 12d6ee5112..f177816b30 100644
--- a/src/repl/scala/tools/nsc/interpreter/LoopCommands.scala
+++ b/src/repl/scala/tools/nsc/interpreter/LoopCommands.scala
@@ -76,6 +76,9 @@ trait LoopCommands {
// the default result means "keep running, and don't record that line"
val default = Result(keepRunning = true, None)
+ // "keep running, and record this line"
+ def recording(line: String) = Result(keepRunning = true, Option(line))
+
// most commands do not want to micromanage the Result, but they might want
// to print something to the console, so we accomodate Unit and String returns.
implicit def resultFromUnit(x: Unit): Result = default
@@ -85,4 +88,3 @@ trait LoopCommands {
}
}
}
-
diff --git a/src/repl/scala/tools/nsc/interpreter/SimpleReader.scala b/src/repl/scala/tools/nsc/interpreter/SimpleReader.scala
index 6634dc6944..49b8433a8c 100644
--- a/src/repl/scala/tools/nsc/interpreter/SimpleReader.scala
+++ b/src/repl/scala/tools/nsc/interpreter/SimpleReader.scala
@@ -22,14 +22,19 @@ extends InteractiveReader
def reset() = ()
def redrawLine() = ()
- def readOneLine(prompt: String): String = {
- if (interactive) {
- out.print(prompt)
- out.flush()
- }
- in.readLine()
+
+ // InteractiveReader internals
+ protected def readOneLine(prompt: String): String = {
+ echo(prompt)
+ readOneLine()
+ }
+ protected def readOneKey(prompt: String) = sys.error("No char-based input in SimpleReader")
+
+ protected def readOneLine(): String = in.readLine()
+ protected def echo(s: String): Unit = if (interactive) {
+ out.print(s)
+ out.flush()
}
- def readOneKey(prompt: String) = sys.error("No char-based input in SimpleReader")
}
object SimpleReader {
@@ -39,3 +44,13 @@ object SimpleReader {
def apply(in: BufferedReader = defaultIn, out: JPrintWriter = defaultOut, interactive: Boolean = true): SimpleReader =
new SimpleReader(in, out, interactive)
}
+
+// pretend we are a console for verbose purposes
+trait EchoReader extends SimpleReader {
+ // if there is more input, then maybe echo the prompt and the input
+ override def readOneLine(prompt: String) = {
+ val input = readOneLine()
+ if (input != null) echo(f"$prompt$input%n")
+ input
+ }
+}