summaryrefslogtreecommitdiff
path: root/src/repl/scala/tools/nsc/interpreter/ILoop.scala
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2015-09-02 13:23:44 +1000
committerJason Zaugg <jzaugg@gmail.com>2015-09-02 20:59:35 +1000
commitf279894a3efe84b85e9becfd0ce96aaa0c21bfbd (patch)
treea6848021a9b1e733d02cffdb45b08da68a4d4a8a /src/repl/scala/tools/nsc/interpreter/ILoop.scala
parent9a3089bd4ac68db798ac006731ebd1b99e9aaaff (diff)
downloadscala-f279894a3efe84b85e9becfd0ce96aaa0c21bfbd.tar.gz
scala-f279894a3efe84b85e9becfd0ce96aaa0c21bfbd.tar.bz2
scala-f279894a3efe84b85e9becfd0ce96aaa0c21bfbd.zip
Use the presentation compiler to drive REPL tab completion
The old implementation is still avaiable under a flag, but we'll remove it in due course. Design goal: - Push as much code in src/interactive as possible to enable reuse outside of the REPL - Don't entangle the REPL completion with JLine. The enclosed test case drives the REPL and autocompletion programatically. - Don't hard code UI choices, like how to render symbols or how to filter candidates. When completion is requested, we wrap the entered code into the same "interpreter wrapper" synthetic code as is done for regular execution. We then start a throwaway instance of the presentation compiler, which takes this as its one and only source file, and has a classpath formed from the REPL's classpath and the REPL's output directory (by default, this is in memory). We can then typecheck the tree, and find the position in the synthetic source corresponding to the cursor location. This is enough to use the new completion APIs in the presentation compiler to prepare a list of candidates. We go to extra lengths to allow completion of partially typed identifiers that appear to be keywords, e.g `global.def` should offer `definitions`. Two secret handshakes are included; move the the end of the line, type `// print<TAB>` and you'll see the post-typer tree. `// typeAt 4 6<TAB>` shows the type of the range position within the buffer. The enclosed unit test exercises most of the new functionality.
Diffstat (limited to 'src/repl/scala/tools/nsc/interpreter/ILoop.scala')
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ILoop.scala27
1 files changed, 16 insertions, 11 deletions
diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
index a0cc116df8..f934bbe46c 100644
--- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
@@ -1,8 +1,7 @@
/* NSC -- new Scala compiler
- * Copyright 2005-2013 LAMP/EPFL
+ * Copyright 2005-2015 LAMP/EPFL
* @author Alexander Spoon
*/
-
package scala
package tools.nsc
package interpreter
@@ -819,9 +818,10 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
case _ =>
}
- /** Tries to create a JLineReader, falling back to SimpleReader:
- * unless settings or properties are such that it should start
- * with SimpleReader.
+ /** Tries to create a JLineReader, 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.
*/
def chooseReader(settings: Settings): InteractiveReader = {
if (settings.Xnojline || Properties.isEmacsShell) SimpleReader()
@@ -829,20 +829,25 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
type Completer = () => Completion
type ReaderMaker = Completer => InteractiveReader
- def instantiate(className: String): ReaderMaker = completer => {
- if (settings.debug) Console.println(s"Trying to instantiate a InteractiveReader from $className")
+ def instantiater(className: String): ReaderMaker = completer => {
+ if (settings.debug) Console.println(s"Trying to instantiate an InteractiveReader from $className")
Class.forName(className).getConstructor(classOf[Completer]).
newInstance(completer).
asInstanceOf[InteractiveReader]
}
- def mkReader(maker: ReaderMaker) =
- if (settings.noCompletion) maker(() => NoCompletion)
- else maker(() => new JLineCompletion(intp)) // JLineCompletion is a misnomer -- it's not tied to jline
+ def mkReader(maker: ReaderMaker) = maker { () =>
+ settings.completion.value match {
+ case _ if settings.noCompletion => NoCompletion
+ case "none" => NoCompletion
+ case "adhoc" => new JLineCompletion(intp) // JLineCompletion is a misnomer; it's not tied to jline
+ case "pc" | _ => new PresentationCompilerCompleter(intp)
+ }
+ }
def internalClass(kind: String) = s"scala.tools.nsc.interpreter.$kind.InteractiveReader"
val readerClasses = sys.props.get("scala.repl.reader").toStream ++ Stream(internalClass("jline"), internalClass("jline_embedded"))
- val readers = readerClasses map (cls => Try { mkReader(instantiate(cls)) })
+ val readers = readerClasses map (cls => Try { mkReader(instantiater(cls)) })
val reader = (readers collect { case Success(reader) => reader } headOption) getOrElse SimpleReader()