diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2015-09-02 13:23:44 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2015-09-02 20:59:35 +1000 |
commit | f279894a3efe84b85e9becfd0ce96aaa0c21bfbd (patch) | |
tree | a6848021a9b1e733d02cffdb45b08da68a4d4a8a /src/repl/scala/tools/nsc/interpreter/Imports.scala | |
parent | 9a3089bd4ac68db798ac006731ebd1b99e9aaaff (diff) | |
download | scala-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/Imports.scala')
-rw-r--r-- | src/repl/scala/tools/nsc/interpreter/Imports.scala | 8 |
1 files changed, 5 insertions, 3 deletions
diff --git a/src/repl/scala/tools/nsc/interpreter/Imports.scala b/src/repl/scala/tools/nsc/interpreter/Imports.scala index 5b231d94b6..5742c1d0d8 100644 --- a/src/repl/scala/tools/nsc/interpreter/Imports.scala +++ b/src/repl/scala/tools/nsc/interpreter/Imports.scala @@ -95,7 +95,8 @@ trait Imports { * last one imported is actually usable. */ case class ComputedImports(header: String, prepend: String, append: String, access: String) - protected def importsCode(wanted: Set[Name], wrapper: Request#Wrapper, definesClass: Boolean): ComputedImports = { + + protected def importsCode(wanted: Set[Name], wrapper: Request#Wrapper, definesClass: Boolean, generousImports: Boolean): ComputedImports = { val header, code, trailingBraces, accessPath = new StringBuilder val currentImps = mutable.HashSet[Name]() var predefEscapes = false // only emit predef import header if name not resolved in history, loosely @@ -116,8 +117,9 @@ trait Imports { def keepHandler(handler: MemberHandler) = handler match { // While defining classes in class based mode - implicits are not needed. case h: ImportHandler if isClassBased && definesClass => h.importedNames.exists(x => wanted.contains(x)) - case _: ImportHandler => true - case x => x.definesImplicit || (x.definedNames exists wanted) + case _: ImportHandler => true + case x if generousImports => x.definesImplicit || (x.definedNames exists (d => wanted.exists(w => d.startsWith(w)))) + case x => x.definesImplicit || (x.definedNames exists wanted) } reqs match { |