/
MetalsDriver.scala
56 lines (48 loc) 路 2.07 KB
/
MetalsDriver.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
package scala.meta.internal.pc
import java.net.URI
import java.util as ju
import dotty.tools.dotc.interactive.InteractiveDriver
import dotty.tools.dotc.reporting.Diagnostic
import dotty.tools.dotc.util.SourceFile
/**
* MetalsDriver is a wrapper class that provides a compilation cache for InteractiveDriver.
* MetalsDriver skips running compilation if
* - the target URI of `run` is the same as the previous target URI
* - the content didn't change since the last compilation.
*
* This compilation cache enables Metals to skip compilation and re-use
* the typed tree under the situation like developers
* sequentially hover on the symbols in the same file without any changes.
*
* Note: we decided to cache only if the target URI is the same as in the previous run
* because of `InteractiveDriver.currentCtx` that should return the context that
* refers to the last compiled source file.
* It would be ideal if we could update currentCtx even when we skip the compilation,
* but we struggled to do that. See the discussion https://github.com/scalameta/metals/pull/4225#discussion_r941138403
* To avoid the complexity related to currentCtx,
* we decided to cache only when the target URI only if the same as the previous run.
*/
class MetalsDriver(
override val settings: List[String]
) extends InteractiveDriver(settings):
@volatile private var lastCompiledURI: URI = _
private def alreadyCompiled(uri: URI, content: Array[Char]): Boolean =
compilationUnits.get(uri) match
case Some(unit)
if lastCompiledURI == uri &&
ju.Arrays.equals(unit.source.content(), content) =>
true
case _ => false
override def run(uri: URI, source: SourceFile): List[Diagnostic] =
val diags =
if alreadyCompiled(uri, source.content) then Nil
else super.run(uri, source)
lastCompiledURI = uri
diags
override def run(uri: URI, sourceCode: String): List[Diagnostic] =
val diags =
if alreadyCompiled(uri, sourceCode.toCharArray()) then Nil
else super.run(uri, sourceCode)
lastCompiledURI = uri
diags
end MetalsDriver