diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2015-09-09 12:02:31 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2015-09-09 12:02:31 +1000 |
commit | 1c42e6bee90b7c444e973726e01b137584dfaad5 (patch) | |
tree | cd8dde99091165218e9699ed6550cc8b623371b5 /src/interactive/scala | |
parent | 2d025fe2d0c9cd0e01e390055b0531166988f901 (diff) | |
download | scala-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/scala')
-rw-r--r-- | src/interactive/scala/tools/nsc/interactive/Global.scala | 31 |
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) } } } |