/
SuperMethodCodeLens.scala
105 lines (93 loc) 路 3.21 KB
/
SuperMethodCodeLens.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package scala.meta.internal.metals.codelenses
import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import scala.meta.internal.implementation.SuperMethodProvider
import scala.meta.internal.implementation.TextDocumentWithPath
import scala.meta.internal.metals.Buffers
import scala.meta.internal.metals.ClientConfiguration
import scala.meta.internal.metals.MetalsEnrichments._
import scala.meta.internal.metals.ServerCommands
import scala.meta.internal.metals.UserConfiguration
import scala.meta.internal.parsing.Trees
import scala.meta.internal.semanticdb.Scala._
import scala.meta.internal.semanticdb.SymbolInformation
import scala.meta.internal.semanticdb.SymbolOccurrence
import scala.meta.internal.semanticdb.TextDocument
import scala.meta.io.AbsolutePath
import org.eclipse.{lsp4j => l}
final class SuperMethodCodeLens(
buffers: Buffers,
userConfig: () => UserConfiguration,
clientConfig: ClientConfiguration,
trees: Trees,
)(implicit val ec: ExecutionContext)
extends CodeLens {
override def isEnabled: Boolean = userConfig().superMethodLensesEnabled
override def codeLenses(
textDocumentWithPath: TextDocumentWithPath
): Future[Seq[l.CodeLens]] = Future {
val textDocument = textDocumentWithPath.textDocument
val path = textDocumentWithPath.filePath
def search(query: String) = textDocument.symbols.find(_.symbol == query)
val distance = buffers.tokenEditDistance(path, textDocument.text, trees)
for {
occurrence <- textDocument.occurrences
if occurrence.role.isDefinition
symbol = occurrence.symbol
gotoSuperMethod <- createSuperMethodCommand(
symbol,
search,
textDocument,
path,
).toIterable
range <-
occurrence.range
.flatMap(r => distance.toRevisedStrict(r).map(_.toLsp))
.toList
} yield new l.CodeLens(range, gotoSuperMethod, null)
}
private def createSuperMethodCommand(
symbol: String,
findSymbol: String => Option[SymbolInformation],
textDocument: TextDocument,
path: AbsolutePath,
): Option[l.Command] = {
for {
symbolInformation <- findSymbol(symbol)
gotoParentSymbol <- SuperMethodProvider.findSuperForMethodOrField(
symbolInformation
)
command <- convertToSuperMethodCommand(
gotoParentSymbol,
symbolInformation.displayName,
textDocument,
path,
)
} yield command
}
private def convertToSuperMethodCommand(
symbol: String,
name: String,
textDocument: TextDocument,
path: AbsolutePath,
): Option[l.Command] = {
if (symbol.isLocal)
textDocument.occurrences.collectFirst {
case SymbolOccurrence(
Some(range),
`symbol`,
SymbolOccurrence.Role.DEFINITION,
) =>
val location = new l.Location(path.toURI.toString(), range.toLsp)
val command = ServerCommands.GotoPosition.toLsp(location)
command.setTitle(s"${clientConfig.icons.findsuper} ${name}")
command
}
else
Some {
val command = ServerCommands.GotoSymbol.toLsp(symbol)
command.setTitle(s"${clientConfig.icons.findsuper} ${name}")
command
}
}
}