From 0dbdaf8b1fb64806d35c18b362184293d46c89cb Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 9 Sep 2015 16:23:51 +1000 Subject: Hide some completion candidates on the first TAB When `foo.`, assume you don't want to see the inherited members from Any_ and universally applicable extension methods like `ensuring`. Hitting a second time includes them in the results. --- .../interpreter/PresentationCompilerCompleter.scala | 19 +++++++++++++++---- .../scala/tools/nsc/interpreter/CompletionTest.scala | 9 +++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/repl/scala/tools/nsc/interpreter/PresentationCompilerCompleter.scala b/src/repl/scala/tools/nsc/interpreter/PresentationCompilerCompleter.scala index 7cff24cfa3..01735aed3a 100644 --- a/src/repl/scala/tools/nsc/interpreter/PresentationCompilerCompleter.scala +++ b/src/repl/scala/tools/nsc/interpreter/PresentationCompilerCompleter.scala @@ -71,15 +71,26 @@ class PresentationCompilerCompleter(intp: IMain) extends Completion with ScalaCo val found = result.completionsAt(cursor) match { case NoResults => Completion.NoCandidates case r => - def isInterpreterWrapperMember(m: Member): Boolean = - definitions.isUniversalMember(m.sym) && nme.isReplWrapperName(m.prefix.typeSymbol.name) - val matching = r.matchingResults().filterNot(isInterpreterWrapperMember) + def shouldHide(m: Member): Boolean = { + val isUniversal = definitions.isUniversalMember(m.sym) + def viaUniversalExtensionMethod = m match { + case t: TypeMember if t.implicitlyAdded && t.viaView.info.params.head.info.bounds.isEmptyBounds => true + case _ => false + } + ( + isUniversal && nme.isReplWrapperName(m.prefix.typeSymbol.name) + || isUniversal && tabCount == 0 && r.name.isEmpty + || viaUniversalExtensionMethod && tabCount == 0 && r.name.isEmpty + ) + } + + val matching = r.matchingResults().filterNot(shouldHide) val tabAfterCommonPrefixCompletion = lastCommonPrefixCompletion.contains(buf.substring(0, cursor)) && matching.exists(_.symNameDropLocal == r.name) val doubleTab = tabCount > 0 && matching.forall(_.symNameDropLocal == r.name) if (tabAfterCommonPrefixCompletion || doubleTab) defStringCandidates(matching, r.name) else if (matching.isEmpty) { // Lenient matching based on camel case and on eliding JavaBean "get" / "is" boilerplate - val camelMatches: List[Member] = r.matchingResults(CompletionResult.camelMatch(_)).filterNot(isInterpreterWrapperMember) + val camelMatches: List[Member] = r.matchingResults(CompletionResult.camelMatch(_)).filterNot(shouldHide) val memberCompletions = camelMatches.map(_.symNameDropLocal.decoded).distinct.sorted def allowCompletion = ( (memberCompletions.size == 1) diff --git a/test/junit/scala/tools/nsc/interpreter/CompletionTest.scala b/test/junit/scala/tools/nsc/interpreter/CompletionTest.scala index 534d5ddc3a..5b35c37c7f 100644 --- a/test/junit/scala/tools/nsc/interpreter/CompletionTest.scala +++ b/test/junit/scala/tools/nsc/interpreter/CompletionTest.scala @@ -133,6 +133,15 @@ class CompletionTest { checkExact(completer, " 1.toHexString //print")(EmptyString, "scala.Predef.intWrapper(1).toHexString // : String") } + @Test + def firstCompletionWithNoPrefixHidesUniversalMethodsAndExtensionMethods(): Unit = { + val intp = newIMain() + val completer = new PresentationCompilerCompleter(intp) + checkExact(completer, "case class C(a: Int, b: Int) { this.")("a", "b") + assert(Set("asInstanceOf", "==").diff(completer.complete("case class C(a: Int, b: Int) { this.").candidates.toSet).isEmpty) + checkExact(completer, "case class D(a: Int, b: Int) { this.a")("a", "asInstanceOf") + } + def checkExact(completer: PresentationCompilerCompleter, before: String, after: String = "")(expected: String*): Unit = { assertEquals(expected.toSet, completer.complete(before, after).candidates.toSet) } -- cgit v1.2.3