summaryrefslogtreecommitdiff
path: root/src/interactive
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2015-09-09 12:02:31 +1000
committerJason Zaugg <jzaugg@gmail.com>2015-09-09 12:02:31 +1000
commit1c42e6bee90b7c444e973726e01b137584dfaad5 (patch)
treecd8dde99091165218e9699ed6550cc8b623371b5 /src/interactive
parent2d025fe2d0c9cd0e01e390055b0531166988f901 (diff)
downloadscala-1c42e6bee90b7c444e973726e01b137584dfaad5.tar.gz
scala-1c42e6bee90b7c444e973726e01b137584dfaad5.tar.bz2
scala-1c42e6bee90b7c444e973726e01b137584dfaad5.zip
More liberal matching in REPL autocompletion
For the SHIFT-impaired: you can just write everything in lowercase, (whisper-case?) and we'll try to DWYM. We treat capital letters that you *do* enter as significant, they can't match a lower case letter in an identifier. Modelled after IntellIJ's completion. I still don't fall into this mode if you enter an exact prefix of a candidate, but we might consider changing that. ``` scala> classOf[String].typ<TAB> getAnnotationsByType getComponentType getDeclaredAnnotationsByType getTypeName getTypeParameters scala> classOf[String].typN<TAB> scala> classOf[String].getTypeName res3: String = java.lang.String scala> def foo(s: str<TAB> scala> def foo(s: String String StringBuffer StringBuilder StringCanBuildFrom StringContext StringFormat StringIndexOutOfBoundsException scala> def foo(s: string<TAB> scala> def foo(s: String String StringBuffer StringBuilder StringCanBuildFrom StringContext StringFormat StringIndexOutOfBoundsException ```
Diffstat (limited to 'src/interactive')
-rw-r--r--src/interactive/scala/tools/nsc/interactive/Global.scala31
1 files changed, 22 insertions, 9 deletions
diff --git a/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala
index ae9d816780..6c8719b5eb 100644
--- a/src/interactive/scala/tools/nsc/interactive/Global.scala
+++ b/src/interactive/scala/tools/nsc/interactive/Global.scala
@@ -1189,18 +1189,31 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
CamelRegex.findAllIn("X" + s).toList match { case head :: tail => head.drop(1) :: tail; case Nil => Nil }
}
def camelMatch(entered: Name): Name => Boolean = {
- val chunks: List[String] = camelComponents(entered.toString)
+ val enteredS = entered.toString
+ val enteredLowercaseSet = enteredS.toLowerCase().toSet
(candidate: Name) => {
- val candidateChunks = camelComponents(candidate.toString)
- val exactCamelMatch =
- (chunks corresponds candidateChunks.take(chunks.length))((x, y) => y.startsWith(x))
- def beanCamelMatch = candidateChunks match {
- case ("get" | "is") :: tail =>
- (chunks corresponds tail.take(chunks.length))((x, y) => y.toLowerCase.startsWith(x.toLowerCase))
- case _ => false
+ def candidateChunks = camelComponents(candidate.toString)
+ // Loosely based on IntelliJ's autocompletion: the user can just write everything in
+ // lowercase, as we'll let `isl` match `GenIndexedSeqLike` or `isLovely`.
+ def lenientMatch(entered: String, candidate: List[String], matchCount: Int): Boolean = {
+ candidate match {
+ case Nil => entered.isEmpty && matchCount > 0
+ case head :: tail =>
+ val enteredAlternatives = Set(entered, entered.capitalize)
+ head.inits.filter(_.length <= entered.length).exists(init =>
+ enteredAlternatives.exists(entered =>
+ lenientMatch(entered.stripPrefix(init), tail, matchCount + (if (init.isEmpty) 0 else 1))
+ )
+ )
+ }
+ }
+ val containsAllEnteredChars = {
+ // Trying to rule out some candidates quickly before the more expensive `lenientMatch`
+ val candidateLowercaseSet = candidate.toString.toLowerCase().toSet
+ enteredLowercaseSet.diff(candidateLowercaseSet).isEmpty
}
- exactCamelMatch || beanCamelMatch
+ containsAllEnteredChars && lenientMatch(enteredS, candidateChunks, 0)
}
}
}