Skip to content

Commit 22a9bb1

Browse files
committed
try to propagate cancel
1 parent 87f4585 commit 22a9bb1

18 files changed

+168
-132
lines changed

metals/src/main/scala/scala/meta/internal/bsp/BspConfigGenerator.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import scala.util.control.NonFatal
1010
import scala.meta.internal.bsp.BspConfigGenerationStatus._
1111
import scala.meta.internal.builds.BuildServerProvider
1212
import scala.meta.internal.builds.ShellRunner
13+
import scala.meta.internal.metals.CancelableFuture
1314
import scala.meta.internal.metals.Directories
1415
import scala.meta.internal.metals.Messages.BspProvider
1516
import scala.meta.internal.metals.MetalsEnrichments._
@@ -31,7 +32,7 @@ final class BspConfigGenerator(
3132
def runUnconditionally(
3233
buildTool: BuildServerProvider,
3334
args: List[String],
34-
): Future[BspConfigGenerationStatus] =
35+
): CancelableFuture[BspConfigGenerationStatus] =
3536
shellRunner
3637
.run(
3738
s"${buildTool.buildServerName} bspConfig",

metals/src/main/scala/scala/meta/internal/bsp/BspConnector.scala

+1
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ class BspConnector(
159159
args => bspConfigGenerator.runUnconditionally(bsp, args),
160160
statusBar,
161161
)
162+
.future
162163
.flatMap { _ =>
163164
connect(
164165
projectRoot,

metals/src/main/scala/scala/meta/internal/builds/BloopInstall.scala

+17-11
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@ import java.util.concurrent.TimeUnit
44

55
import scala.concurrent.ExecutionContext
66
import scala.concurrent.Future
7+
import scala.concurrent.Promise
78

89
import scala.meta.internal.builds.Digest.Status
910
import scala.meta.internal.metals.BuildInfo
11+
import scala.meta.internal.metals.CancelSwitch
12+
import scala.meta.internal.metals.CancelableFuture
1013
import scala.meta.internal.metals.Confirmation
14+
import scala.meta.internal.metals.Interruptable
15+
import scala.meta.internal.metals.Interruptable._
1116
import scala.meta.internal.metals.Messages._
1217
import scala.meta.internal.metals.MetalsEnrichments._
1318
import scala.meta.internal.metals.Tables
@@ -37,14 +42,14 @@ final class BloopInstall(
3742

3843
def runUnconditionally(
3944
buildTool: BloopInstallProvider
40-
): Future[WorkspaceLoadedStatus] = {
45+
): CancelableFuture[WorkspaceLoadedStatus] = {
4146
buildTool.bloopInstall(
4247
workspace,
4348
args => {
4449
scribe.info(s"running '${args.mkString(" ")}'")
4550
val process =
4651
runArgumentsUnconditionally(buildTool, args, userConfig().javaHome)
47-
process.foreach { e =>
52+
process.future.foreach { e =>
4853
if (e.isFailed) {
4954
// Record the exact command that failed to help troubleshooting.
5055
scribe.error(s"$buildTool command failed: ${args.mkString(" ")}")
@@ -59,7 +64,7 @@ final class BloopInstall(
5964
buildTool: BloopInstallProvider,
6065
args: List[String],
6166
javaHome: Option[String],
62-
): Future[WorkspaceLoadedStatus] = {
67+
): CancelableFuture[WorkspaceLoadedStatus] = {
6368
persistChecksumStatus(Status.Started, buildTool)
6469
val processFuture = shellRunner
6570
.run(
@@ -81,7 +86,7 @@ final class BloopInstall(
8186
case ExitCodes.Cancel => WorkspaceLoadedStatus.Cancelled
8287
case result => WorkspaceLoadedStatus.Failed(result)
8388
}
84-
processFuture.foreach { result =>
89+
processFuture.future.foreach { result =>
8590
try result.toChecksumStatus.foreach(persistChecksumStatus(_, buildTool))
8691
catch {
8792
case _: InterruptedException =>
@@ -112,35 +117,36 @@ final class BloopInstall(
112117
def runIfApproved(
113118
buildTool: BloopInstallProvider,
114119
digest: String,
115-
): Future[WorkspaceLoadedStatus] =
120+
): CancelableFuture[WorkspaceLoadedStatus] =
116121
synchronized {
117122
oldInstallResult(digest) match {
118123
case Some(result)
119124
if result != WorkspaceLoadedStatus.Duplicate(Status.Requested) =>
120125
scribe.info(s"skipping build import with status '${result.name}'")
121-
Future.successful(result)
126+
CancelableFuture.successful(result)
122127
case _ =>
123128
if (userConfig().shouldAutoImportNewProject) {
124129
runUnconditionally(buildTool)
125130
} else {
126131
scribe.debug("Awaiting user response...")
127-
for {
132+
implicit val cancelSwitch = CancelSwitch(Promise[Unit]())
133+
(for {
128134
userResponse <- requestImport(
129135
buildTools,
130136
buildTool,
131137
languageClient,
132138
digest,
133-
)
139+
).withInterrupt
134140
installResult <- {
135141
if (userResponse.isYes) {
136-
runUnconditionally(buildTool)
142+
runUnconditionally(buildTool).withInterrupt
137143
} else {
138144
// Don't spam the user with requests during rapid build changes.
139145
notification.dismiss(2, TimeUnit.MINUTES)
140-
Future.successful(WorkspaceLoadedStatus.Rejected)
146+
Interruptable.successful(WorkspaceLoadedStatus.Rejected)
141147
}
142148
}
143-
} yield installResult
149+
} yield installResult).toCancellable
144150
}
145151
}
146152
}

metals/src/main/scala/scala/meta/internal/builds/BloopInstallProvider.scala

+3-4
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ package scala.meta.internal.builds
22
import java.io.IOException
33
import java.nio.file.Files
44

5-
import scala.concurrent.Future
6-
5+
import scala.meta.internal.metals.CancelableFuture
76
import scala.meta.internal.metals.MetalsEnrichments._
87
import scala.meta.io.AbsolutePath
98

@@ -18,8 +17,8 @@ trait BloopInstallProvider extends BuildTool {
1817
*/
1918
def bloopInstall(
2019
workspace: AbsolutePath,
21-
systemProcess: List[String] => Future[WorkspaceLoadedStatus],
22-
): Future[WorkspaceLoadedStatus] = {
20+
systemProcess: List[String] => CancelableFuture[WorkspaceLoadedStatus],
21+
): CancelableFuture[WorkspaceLoadedStatus] = {
2322
cleanupStaleConfig()
2423
systemProcess(bloopInstallArgs(workspace))
2524
}

metals/src/main/scala/scala/meta/internal/builds/BuildServerProvider.scala

+9-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import scala.annotation.nowarn
44
import scala.concurrent.Future
55

66
import scala.meta.internal.bsp.BspConfigGenerationStatus._
7+
import scala.meta.internal.metals.CancelableFuture
78
import scala.meta.internal.metals.Messages
89
import scala.meta.internal.metals.StatusBar
910
import scala.meta.io.AbsolutePath
@@ -20,12 +21,16 @@ trait BuildServerProvider extends BuildTool {
2021
@nowarn("msg=parameter statusBar in method generateBspConfig is never used")
2122
def generateBspConfig(
2223
workspace: AbsolutePath,
23-
systemProcess: List[String] => Future[BspConfigGenerationStatus],
24+
systemProcess: List[String] => CancelableFuture[
25+
BspConfigGenerationStatus
26+
],
2427
statusBar: StatusBar,
25-
): Future[BspConfigGenerationStatus] =
28+
): CancelableFuture[BspConfigGenerationStatus] =
2629
createBspFileArgs(workspace).map(systemProcess).getOrElse {
27-
Future.successful(
28-
Failed(Right(Messages.NoBspSupport.toString()))
30+
CancelableFuture(
31+
Future.successful(
32+
Failed(Right(Messages.NoBspSupport.toString()))
33+
)
2934
)
3035
}
3136

metals/src/main/scala/scala/meta/internal/builds/NewProjectProvider.scala

+1
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ class NewProjectProvider(
134134
javaHome,
135135
javaOptsMap = javaOpts,
136136
)
137+
.future
137138
.flatMap {
138139
case ExitCodes.Success =>
139140
askForWindow(projectPath)

metals/src/main/scala/scala/meta/internal/builds/SbtBuildTool.scala

+6-4
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,11 @@ case class SbtBuildTool(
6666

6767
override def generateBspConfig(
6868
workspace: AbsolutePath,
69-
systemProcess: List[String] => Future[BspConfigGenerationStatus],
69+
systemProcess: List[String] => CancelableFuture[
70+
BspConfigGenerationStatus
71+
],
7072
statusBar: StatusBar,
71-
): Future[BspConfigGenerationStatus] = {
73+
): CancelableFuture[BspConfigGenerationStatus] = {
7274
cleanUpPlugins()
7375
super.generateBspConfig(workspace, systemProcess, statusBar)
7476
}
@@ -107,7 +109,7 @@ case class SbtBuildTool(
107109

108110
def shutdownBspServer(
109111
shellRunner: ShellRunner
110-
): Future[Int] = {
112+
): CancelableFuture[Int] = {
111113
val shutdownArgs =
112114
composeArgs(List("--client", "shutdown"), projectRoot, projectRoot.toNIO)
113115
scribe.info(s"running ${shutdownArgs.mkString(" ")}")
@@ -272,7 +274,7 @@ case class SbtBuildTool(
272274
if (promise.isCompleted) {
273275
// executes when user chooses `restart` after the timeout
274276
restartSbtBuildServer()
275-
} else shutdownBspServer(shellRunner).ignoreValue
277+
} else shutdownBspServer(shellRunner).future.ignoreValue
276278
case _ =>
277279
promise.trySuccess(())
278280
Future.successful(())

metals/src/main/scala/scala/meta/internal/builds/ScalaCliBuildTool.scala

+6-5
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ package scala.meta.internal.builds
22

33
import java.security.MessageDigest
44

5-
import scala.concurrent.Future
6-
75
import scala.meta.internal.bsp.BspConfigGenerationStatus._
86
import scala.meta.internal.metals.BuildInfo
7+
import scala.meta.internal.metals.CancelableFuture
98
import scala.meta.internal.metals.Directories
109
import scala.meta.internal.metals.MetalsEnrichments._
1110
import scala.meta.internal.metals.StatusBar
@@ -26,9 +25,11 @@ case class ScalaCliBuildTool(
2625

2726
override def generateBspConfig(
2827
workspace: AbsolutePath,
29-
systemProcess: List[String] => Future[BspConfigGenerationStatus],
28+
systemProcess: List[String] => CancelableFuture[
29+
BspConfigGenerationStatus
30+
],
3031
statusBar: StatusBar,
31-
): Future[BspConfigGenerationStatus] =
32+
): CancelableFuture[BspConfigGenerationStatus] =
3233
createBspFileArgs(workspace).map(systemProcess).getOrElse {
3334
// fallback to creating `.bsp/scala-cli.json` that starts JVM launcher
3435
val bspConfig =
@@ -37,7 +38,7 @@ case class ScalaCliBuildTool(
3738
bspConfig.writeText(
3839
ScalaCli.scalaCliBspJsonContent(projectRoot = projectRoot.toString())
3940
)
40-
Future.successful(Generated)
41+
CancelableFuture.successful(Generated)
4142
}
4243

4344
override def createBspFileArgs(

metals/src/main/scala/scala/meta/internal/builds/ShellRunner.scala

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import java.io.File
44

55
import scala.concurrent.Await
66
import scala.concurrent.ExecutionContext
7-
import scala.concurrent.Future
87
import scala.concurrent.Promise
98
import scala.concurrent.duration.DurationInt
109
import scala.language.postfixOps
1110
import scala.util.Properties
1211

1312
import scala.meta.internal.metals.Cancelable
13+
import scala.meta.internal.metals.CancelableFuture
1414
import scala.meta.internal.metals.JavaBinary
1515
import scala.meta.internal.metals.JdkSources
1616
import scala.meta.internal.metals.MetalsEnrichments._
@@ -45,7 +45,7 @@ class ShellRunner(time: Time, workDoneProvider: WorkDoneProgress)(implicit
4545
processErr: String => Unit = scribe.error(_),
4646
propagateError: Boolean = false,
4747
javaOptsMap: Map[String, String] = Map.empty,
48-
): Future[Int] = {
48+
): CancelableFuture[Int] = {
4949

5050
val classpathSeparator = if (Properties.isWin) ";" else ":"
5151
val classpath = Fetch
@@ -92,7 +92,7 @@ class ShellRunner(time: Time, workDoneProvider: WorkDoneProgress)(implicit
9292
processErr: String => Unit = scribe.error(_),
9393
propagateError: Boolean = false,
9494
logInfo: Boolean = true,
95-
): Future[Int] = {
95+
): CancelableFuture[Int] = {
9696
val elapsed = new Timer(time)
9797
val env = additionalEnv ++ JdkSources.envVariables(javaHome)
9898
val ps = SystemProcess.run(
@@ -125,7 +125,7 @@ class ShellRunner(time: Time, workDoneProvider: WorkDoneProgress)(implicit
125125
result.trySuccess(code)
126126
}
127127
result.future.onComplete(_ => cancelables.remove(newCancelable))
128-
result.future
128+
CancelableFuture(result.future, newCancelable)
129129
}
130130

131131
}

metals/src/main/scala/scala/meta/internal/metals/CancelableFuture.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import scala.concurrent.ExecutionContext
44
import scala.concurrent.Future
55
import scala.util.Try
66

7-
case class CancelableFuture[T](
7+
case class CancelableFuture[+T](
88
future: Future[T],
99
cancelable: Cancelable = Cancelable.empty,
1010
) extends Cancelable {

0 commit comments

Comments
 (0)