summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/interpreter/Completion.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-01-26 22:14:15 +0000
committerPaul Phillips <paulp@improving.org>2010-01-26 22:14:15 +0000
commitf6183b63f28a199b7888949963a8d6984d54c3b1 (patch)
tree8eb557773e913669e7ebac6a720392602fe72481 /src/compiler/scala/tools/nsc/interpreter/Completion.scala
parent8856f21f59ff735db7951901a799300a5affd9cc (diff)
downloadscala-f6183b63f28a199b7888949963a8d6984d54c3b1.tar.gz
scala-f6183b63f28a199b7888949963a8d6984d54c3b1.tar.bz2
scala-f6183b63f28a199b7888949963a8d6984d54c3b1.zip
Refinements to the recent repl patches.
few more things, like literals (1.<tab>, "abc".<tab>). A completion aware case class walker which leverages the names of the case fields for completion. For instance: :power val x = new ProductCompletion(mkTree("def f(x: Int, y: Int) = f(5, 10) + f(10, 20)") x.<tab> mods name rhs tparams tpt vparamss x.rhs.fun.<tab> name qualifier scala> x.rhs.fun.qualifier res3: scala.tools.nsc.ast.Trees$Apply = f(5, 10)
Diffstat (limited to 'src/compiler/scala/tools/nsc/interpreter/Completion.scala')
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Completion.scala168
1 files changed, 112 insertions, 56 deletions
diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
index dc544ed657..f9e6b33763 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
@@ -21,10 +21,22 @@ package interpreter
import jline._
import java.net.URL
import java.util.{ List => JList }
+import java.lang.reflect
+
+trait ForwardingCompletion extends CompletionAware {
+ def forwardTo: Option[CompletionAware]
+
+ override def completions() = forwardTo map (_.completions()) getOrElse Nil
+ override def follow(s: String) = forwardTo flatMap (_ follow s)
+}
// REPL completor - queries supplied interpreter for valid
// completions based on current contents of buffer.
-class Completion(repl: Interpreter) extends Completor {
+class Completion(repl: Interpreter) {
+ self =>
+
+ import repl.isInitialized
+
private def asURLs(xs: List[String]) = xs map (x => io.File(x).toURL)
private def classPath = (
// compiler jars, scala-library.jar etc.
@@ -37,75 +49,119 @@ class Completion(repl: Interpreter) extends Completor {
val ids = new IdentCompletion(repl)
// the top level packages we know about
val pkgs = new PackageCompletion(classPath)
-
- // TODO - restore top level availability of scala.* java.lang.* scala.Predef
- // Old code:
- //
- // def membersOfPredef() = membersOfId("scala.Predef")
- //
- // def javaLangToHide(s: String) = (
- // (s endsWith "Exception") ||
- // (s endsWith "Error") ||
- // (s endsWith "Impl") ||
- // (s startsWith "CharacterData") ||
- // !existsAndPublic("java.lang." + s)
- // )
- //
- // def scalaToHide(s: String) =
- // (List("Tuple", "Product", "Function") exists (x => (x + """\d+""").r findPrefixMatchOf s isDefined)) ||
- // (List("Exception", "Error") exists (s endsWith _))
- //
- // import reflect.Modifier.{ isPrivate, isProtected, isPublic, isStatic }
- // private def isSingleton(x: Int, isJava: Boolean) = !isJava || isStatic(x)
- // private def existsAndPublic(s: String): Boolean =
- // (dottedPaths containsKey s) || {
- // val clazz =
- // try Class.forName(s)
- // catch { case _: ClassNotFoundException | _: SecurityException => return false }
- //
- // isPublic(clazz.getModifiers)
- // }
-
- // the high level analysis
- def analyze(_buffer: String, clist: JList[String]): Int = {
- val parsed = new Parsed(_buffer)
- import parsed._
-
- val candidates = List(ids, pkgs) flatMap (_ completionsFor buffer)
- candidates foreach (clist add _)
- position
+ // members of Predef
+ val predef = new StaticCompletion("scala.Predef") {
+ override def filterNotFunction(s: String) = (
+ (s contains "2") ||
+ (s startsWith "wrap") ||
+ (s endsWith "Wrapper") ||
+ (s endsWith "Ops")
+ )
+ }
+ // members of scala.*
+ val scalalang = new pkgs.SubCompletor("scala") with ForwardingCompletion {
+ def forwardTo = pkgs follow "scala"
+ val arityClasses = {
+ val names = List("Tuple", "Product", "Function")
+ val expanded = for (name <- names ; index <- 0 to 22 ; dollar <- List("", "$")) yield name + index + dollar
+
+ Set(expanded: _*)
+ }
+
+ override def filterNotFunction(s: String) = {
+ val parsed = new Parsed(s)
+
+ (arityClasses contains parsed.unqualifiedPart) ||
+ (s endsWith "Exception") ||
+ (s endsWith "Error")
+ }
+ }
+ // members of java.lang.*
+ val javalang = new pkgs.SubCompletor("java.lang") with ForwardingCompletion {
+ def forwardTo = pkgs follow "java.lang"
+ import reflect.Modifier.isPublic
+ private def existsAndPublic(s: String): Boolean = {
+ val name = if (s contains ".") s else "java.lang." + s
+ val clazz = classForName(name) getOrElse (return false)
+
+ isPublic(clazz.getModifiers)
+ }
+ override def filterNotFunction(s: String) = {
+ (s endsWith "Exception") ||
+ (s endsWith "Error") ||
+ (s endsWith "Impl") ||
+ (s startsWith "CharacterData")
+ }
+ override def completions() = super.completions() filter existsAndPublic
}
+ val literals = new LiteralCompletion {
+ val global = repl.compiler
+ val parent = self
+ }
+
+ // the list of completion aware objects which should be consulted
+ val topLevel: List[CompletionAware] = List(ids, pkgs, predef, scalalang, javalang, literals)
+ def topLevelFor(buffer: String) = topLevel flatMap (_ completionsFor buffer)
// chasing down results which won't parse
def execute(line: String): Option[Any] = {
val parsed = new Parsed(line)
import parsed._
- if (!isQualified)
- return None
-
- for (topLevel <- List(ids, pkgs) ; exec <- topLevel executionFor buffer)
- return Some(exec)
-
- None
+ if (!isQualified) None
+ else {
+ (ids executionFor buffer) orElse
+ (pkgs executionFor buffer)
+ }
}
// override if history is available
def lastCommand: Option[String] = None
- // For recording the buffer on the last tab hit
- private var lastTab: (String, String) = (null, null)
+ // jline's entry point
+ lazy val jline: ArgumentCompletor = {
+ // TODO - refine the delimiters
+ //
+ // public static interface ArgumentDelimiter {
+ // ArgumentList delimit(String buffer, int argumentPosition);
+ // boolean isDelimiter(String buffer, int pos);
+ // }
+ val delimiters = new ArgumentCompletor.AbstractArgumentDelimiter {
+ // val delimChars = "(){},`; \t".toArray
+ val delimChars = "{},`; \t".toArray
+ def isDelimiterChar(s: String, pos: Int) = delimChars contains s.charAt(pos)
+ }
+
+ returning(new ArgumentCompletor(new JLineCompletion, delimiters))(_ setStrict false)
+ }
+
+ class JLineCompletion extends Completor {
+ // For recording the buffer on the last tab hit
+ private var lastTab: (String, String) = (null, null)
+
+ // Does this represent two consecutive tabs?
+ def isConsecutiveTabs(buf: String) = (buf, lastCommand orNull) == lastTab
+
+ // verbosity goes up with consecutive tabs
+ // TODO - actually implement.
+ private var verbosity = 0
+
+ // This is jline's entry point for completion.
+ override def complete(_buffer: String, cursor: Int, candidates: JList[String]): Int = {
+ if (!isInitialized)
+ return cursor
- // Does this represent two consecutive tabs?
- def isConsecutiveTabs(buf: String) = (buf, lastCommand orNull) == lastTab
+ // println("_buffer = %s, cursor = %d".format(_buffer, cursor))
+ verbosity = if (isConsecutiveTabs(_buffer)) verbosity + 1 else 0
+ lastTab = (_buffer, lastCommand orNull)
- // This is jline's entry point for completion.
- override def complete(_buffer: String, cursor: Int, candidates: JList[String]): Int = {
- // println("_buffer = %s, cursor = %d".format(_buffer, cursor))
- val verbose = isConsecutiveTabs(_buffer)
- lastTab = (_buffer, lastCommand orNull)
+ // parse the command buffer
+ val parsed = new Parsed(_buffer)
+ import parsed._
- // modify the buffer in place and returns the cursor position
- analyze(_buffer, candidates)
+ // modify in place and return the position
+ topLevelFor(buffer) foreach (candidates add _)
+ position
+ }
}
}