diff --git a/mtags/src/main/scala-2/scala/meta/internal/pc/CompletionProvider.scala b/mtags/src/main/scala-2/scala/meta/internal/pc/CompletionProvider.scala index b775b066535..ea69503706c 100644 --- a/mtags/src/main/scala-2/scala/meta/internal/pc/CompletionProvider.scala +++ b/mtags/src/main/scala-2/scala/meta/internal/pc/CompletionProvider.scala @@ -45,18 +45,29 @@ class CompletionProvider( def completions(): CompletionList = { val filename = params.uri().toString() - val unit = addCompilationUnit( - code = params.text, - filename = filename, - cursor = Some(params.offset), - cursorName = cursorName - ) + def baseCompletions( + // handling issues in `f(_.) where f has more than one parameter` + retryWithComa: Boolean = true, + addComma: Boolean = false + ): (Position, (InterestingMembers, CompletionPosition, l.Range, String)) = { + val unit = addCompilationUnit( + code = params.text, + filename = filename, + cursor = Some(params.offset), + cursorName = cursorName, + withComma = addComma + ) - val pos = unit.position(params.offset) - val isSnippet = isSnippetEnabled(pos, params.text()) + val pos = unit.position(params.offset) - val (i, completion, editRange, query) = safeCompletionsAt(pos, params.uri()) + val result @ (i, _, _, _) = + safeCompletionsAt(pos, params.uri()) + if (i.results.nonEmpty || !retryWithComa) (pos, result) + else baseCompletions(retryWithComa = false, addComma = true) + } + val (pos, (i, completion, editRange, query)) = baseCompletions() + val isSnippet = isSnippetEnabled(pos, params.text()) val start = inferIdentStart(pos, params.text()) val end = inferIdentEnd(pos, params.text()) val oldText = params.text().substring(start, end) diff --git a/mtags/src/main/scala-2/scala/meta/internal/pc/MetalsGlobal.scala b/mtags/src/main/scala-2/scala/meta/internal/pc/MetalsGlobal.scala index 242da2b9761..598e1611b3b 100644 --- a/mtags/src/main/scala-2/scala/meta/internal/pc/MetalsGlobal.scala +++ b/mtags/src/main/scala-2/scala/meta/internal/pc/MetalsGlobal.scala @@ -625,11 +625,23 @@ class MetalsGlobal( code: String, filename: String, cursor: Option[Int], - cursorName: String = CURSOR + cursorName: String = CURSOR, + withComma: Boolean = false ): RichCompilationUnit = { + // helps to deal with f(_.) where f has a second parameter + def nextIsParen(offset: Int): Boolean = { + val next = code(offset) + if (next == ')') true + else if (next == ' ' && offset + 1 < code.size) nextIsParen(offset + 1) + else false + } val codeWithCursor = cursor match { case Some(offset) => - code.take(offset) + cursorName + code.drop(offset) + val inside = + if (withComma && offset < code.size && nextIsParen(offset)) + cursorName + "," + else cursorName + code.take(offset) + inside + code.drop(offset) case _ => code } val unit = newCompilationUnit(codeWithCursor, filename) diff --git a/tests/cross/src/test/scala/tests/pc/CompletionIssueSuite.scala b/tests/cross/src/test/scala/tests/pc/CompletionIssueSuite.scala index dfc4ab0ff92..44c8ee35418 100644 --- a/tests/cross/src/test/scala/tests/pc/CompletionIssueSuite.scala +++ b/tests/cross/src/test/scala/tests/pc/CompletionIssueSuite.scala @@ -273,6 +273,25 @@ class CompletionIssueSuite extends BaseCompletionSuite { "match" ) + check( + "higher-order", + """| + |class Foo { + | def Bar: Double = 2.0 + | def Baz: Double = 1.0 + |} + | + |object Bar { + | def higherOrder2(f: Foo => Double, s: String): Nothing = ??? + | higherOrder2(_.@@) + |} + |""".stripMargin, + """|Bar: Double + |Baz: Double + |""".stripMargin, + topLines = Some(2) + ) + // The tests shows `x$1` but it's because the dependency is not indexed checkEdit( "default-java-override",