summaryrefslogtreecommitdiff
path: root/src/repl/scala/tools/nsc/interpreter/ILoop.scala
diff options
context:
space:
mode:
authorSom Snytt <som.snytt@gmail.com>2016-02-25 13:41:20 -0800
committerSom Snytt <som.snytt@gmail.com>2016-05-20 17:01:34 -0700
commit99dad60d984d3f72338f3bad4c4fe905090edd51 (patch)
treec70abab26b1116869e02606abac1167232ab28f4 /src/repl/scala/tools/nsc/interpreter/ILoop.scala
parent0d0671ae10ef552d66861248fa087306c960520e (diff)
downloadscala-99dad60d984d3f72338f3bad4c4fe905090edd51.tar.gz
scala-99dad60d984d3f72338f3bad4c4fe905090edd51.tar.bz2
scala-99dad60d984d3f72338f3bad4c4fe905090edd51.zip
SI-7898 Read user input during REPL warmup
The compiler is created on main thread and user input is read on an aux thread (opposite to currently). Fixes completion when `-i` is supplied. Now `-i` means pasted and new option `-I` means line-by-line. The temporary reader uses postInit to swap in the underlying reader. Completion is disabled for the temporary reader, rather than blocking while it waits for a compiler. But manically hitting tab is one way of knowing exactly when completion is live.
Diffstat (limited to 'src/repl/scala/tools/nsc/interpreter/ILoop.scala')
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ILoop.scala165
1 files changed, 109 insertions, 56 deletions
diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
index adac438b37..adaf3a5d25 100644
--- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
@@ -175,10 +175,19 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
echo("\n" + msg)
in.redrawLine()
}
- protected def echo(msg: String) = {
+ protected var mum = false
+ protected def echo(msg: String) = if (!mum) {
out println msg
out.flush()
}
+ // turn off intp reporter and our echo
+ def mumly[A](op: =>A): A =
+ if (isReplDebug) op
+ else intp beSilentDuring {
+ val saved = mum
+ mum = true
+ try op finally mum = saved
+ }
/** Search the history */
def searchHistory(_cmdline: String) {
@@ -408,12 +417,13 @@ 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(): LineResult = {
+ final def loop(): LineResult = loop(readOneLine())
+
+ @tailrec final def loop(line: String): LineResult = {
import LineResults._
- readOneLine() match {
- case null => EOF
- case line => if (try processLine(line) catch crashRecovery) loop() else ERR
- }
+ if (line == null) EOF
+ else if (try processLine(line) catch crashRecovery) loop(readOneLine())
+ else ERR
}
/** interpret all lines from a specified file */
@@ -829,19 +839,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
}
}
- // runs :load `file` on any files passed via -i
- def loadFiles(settings: Settings) = settings match {
- case settings: GenericRunnerSettings =>
- for (filename <- settings.loadfiles.value) {
- val cmd = ":load " + filename
- command(cmd)
- addReplay(cmd)
- echo("")
- }
- case _ =>
- }
-
- /** Tries to create a JLineReader, falling back to SimpleReader,
+ /** Tries to create a jline.InteractiveReader, falling back to SimpleReader,
* unless settings or properties are such that it should start with SimpleReader.
* The constructor of the InteractiveReader must take a Completion strategy,
* supplied as a `() => Completion`; the Completion object provides a concrete Completer.
@@ -885,49 +883,104 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
}
}
- private def loopPostInit() {
- // Bind intp somewhere out of the regular namespace where
- // we can get at it in generated code.
- intp.quietBind(NamedParam[IMain]("$intp", intp)(tagOfIMain, classTag[IMain]))
- // Auto-run code via some setting.
- ( replProps.replAutorunCode.option
- flatMap (f => io.File(f).safeSlurp())
- foreach (intp quietRun _)
- )
- // classloader and power mode setup
- intp.setContextClassLoader()
- if (isReplPower) {
- replProps.power setValue true
- unleashAndSetPhase()
- asyncMessage(power.banner)
- }
- // SI-7418 Now, and only now, can we enable TAB completion.
- in.postInit()
- }
-
- // start an interpreter with the given settings
+ /** Start an interpreter with the given settings.
+ * @return true if successful
+ */
def process(settings: Settings): Boolean = savingContextLoader {
- this.settings = settings
- createInterpreter()
- // sets in to some kind of reader depending on environmental cues
- in = in0.fold(chooseReader(settings))(r => SimpleReader(r, out, interactive = true))
- globalFuture = future {
- intp.initializeSynchronous()
- loopPostInit()
- !intp.reporter.hasErrors
+ def newReader = in0.fold(chooseReader(settings))(r => SimpleReader(r, out, interactive = true))
+
+ /** Reader to use before interpreter is online. */
+ def preLoop = {
+ val sr = SplashReader(newReader) { r =>
+ in = r
+ in.postInit()
+ }
+ in = sr
+ SplashLoop(sr, prompt)
}
- loadFiles(settings)
- printWelcome()
- try loop() match {
- case LineResults.EOF => out print Properties.shellInterruptedString
- case _ =>
+ /* Actions to cram in parallel while collecting first user input at prompt.
+ * Run with output muted both from ILoop and from the intp reporter.
+ */
+ def loopPostInit(): Unit = mumly {
+ // Bind intp somewhere out of the regular namespace where
+ // we can get at it in generated code.
+ intp.quietBind(NamedParam[IMain]("$intp", intp)(tagOfIMain, classTag[IMain]))
+
+ // add a help function for anyone who types "help" instead of ":help". Easily shadowed.
+ //addHelp()
+
+ // Auto-run code via some setting.
+ ( replProps.replAutorunCode.option
+ flatMap (f => File(f).safeSlurp())
+ foreach (intp quietRun _)
+ )
+ // power mode setup
+ if (isReplPower) {
+ replProps.power setValue true
+ unleashAndSetPhase()
+ asyncMessage(power.banner)
+ }
+ loadInitFiles()
+ // SI-7418 Now, and only now, can we enable TAB completion.
+ in.postInit()
+ }
+ def loadInitFiles(): Unit = settings match {
+ case settings: GenericRunnerSettings =>
+ for (f <- settings.loadfiles.value) {
+ loadCommand(f)
+ addReplay(s":load $f")
+ }
+ for (f <- settings.pastefiles.value) {
+ pasteCommand(f)
+ addReplay(s":paste $f")
+ }
+ case _ =>
+ }
+ // TODO: wait until after startup to enable obnoxious settings
+ def withSuppressedSettings[A](body: =>A): A = {
+ body
}
- catch AbstractOrMissingHandler()
- finally closeInterpreter()
+ def startup(): String = withSuppressedSettings {
+ // starting
+ printWelcome()
- true
+ // let them start typing
+ val splash = preLoop
+ splash.start()
+
+ // while we go fire up the REPL
+ try {
+ createInterpreter()
+ intp.initializeSynchronous()
+ globalFuture = Future successful true
+ if (intp.reporter.hasErrors) {
+ echo("Interpreter encountered errors during initialization!")
+ null
+ } else {
+ loopPostInit()
+ val line = splash.line // what they typed in while they were waiting
+ if (line == null) { // they ^D
+ try out print Properties.shellInterruptedString
+ finally closeInterpreter()
+ }
+ line
+ }
+ } finally splash.stop()
+ }
+ this.settings = settings
+ startup() match {
+ case null => false
+ case line =>
+ try loop(line) match {
+ case LineResults.EOF => out print Properties.shellInterruptedString
+ case _ =>
+ }
+ catch AbstractOrMissingHandler()
+ finally closeInterpreter()
+ true
+ }
}
@deprecated("Use `process` instead", "2.9.0")