Skip to content

Commit

Permalink
bugfix: focus correct workspace folder
Browse files Browse the repository at this point in the history
  • Loading branch information
kasiaMarek committed Oct 20, 2023
1 parent 07f75c4 commit df3fa6c
Show file tree
Hide file tree
Showing 11 changed files with 164 additions and 33 deletions.
11 changes: 7 additions & 4 deletions metals/src/main/scala/scala/meta/internal/bsp/BspConnector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import scala.meta.internal.builds.SbtBuildTool
import scala.meta.internal.builds.ShellRunner
import scala.meta.internal.metals.BloopServers
import scala.meta.internal.metals.BuildServerConnection
import scala.meta.internal.metals.ConnectionBspStatus
import scala.meta.internal.metals.Messages
import scala.meta.internal.metals.Messages.BspSwitch
import scala.meta.internal.metals.MetalsEnrichments._
Expand All @@ -36,6 +37,7 @@ class BspConnector(
bspConfigGenerator: BspConfigGenerator,
currentConnection: () => Option[BuildServerConnection],
restartBspServer: () => Future[Boolean],
bspStatus: ConnectionBspStatus,
)(implicit ec: ExecutionContext) {

/**
Expand Down Expand Up @@ -83,6 +85,7 @@ class BspConnector(
bspTraceRoot: AbsolutePath,
addLivenessMonitor: Boolean,
): Future[Option[BuildServerConnection]] = {
def bspStatusOpt = Option.when(addLivenessMonitor)(bspStatus)
scribe.info("Attempting to connect to the build server...")
resolve() match {
case ResolvedNone =>
Expand All @@ -94,7 +97,7 @@ class BspConnector(
projectRoot,
bspTraceRoot,
userConfiguration,
addLivenessMonitor,
bspStatusOpt,
)
.map(Some(_))
case ResolvedBspOne(details)
Expand All @@ -118,7 +121,7 @@ class BspConnector(
projectRoot,
bspTraceRoot,
details,
addLivenessMonitor,
bspStatusOpt,
)
_ <-
if (shouldReload) connection.workspaceReload()
Expand All @@ -130,7 +133,7 @@ class BspConnector(
case ResolvedBspOne(details) =>
tables.buildServers.chooseServer(details.getName())
bspServers
.newServer(projectRoot, bspTraceRoot, details, addLivenessMonitor)
.newServer(projectRoot, bspTraceRoot, details, bspStatusOpt)
.map(Some(_))
case ResolvedMultiple(_, availableServers) =>
val distinctServers = availableServers
Expand Down Expand Up @@ -167,7 +170,7 @@ class BspConnector(
projectRoot,
bspTraceRoot,
item,
addLivenessMonitor,
bspStatusOpt,
)
} yield Some(conn)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import scala.meta.internal.io.FileIO
import scala.meta.internal.metals.BuildServerConnection
import scala.meta.internal.metals.Cancelable
import scala.meta.internal.metals.ClosableOutputStream
import scala.meta.internal.metals.ConnectionBspStatus
import scala.meta.internal.metals.JdkSources
import scala.meta.internal.metals.MetalsBuildClient
import scala.meta.internal.metals.MetalsEnrichments._
Expand Down Expand Up @@ -69,7 +70,7 @@ final class BspServers(
projectDirectory: AbsolutePath,
bspTraceRoot: AbsolutePath,
details: BspConnectionDetails,
addLivenessMonitor: Boolean,
bspStatusOpt: Option[ConnectionBspStatus],
): Future[BuildServerConnection] = {

def newConnection(): Future[SocketConnection] = {
Expand Down Expand Up @@ -143,7 +144,7 @@ final class BspServers(
tables.dismissedNotifications.ReconnectBsp,
config,
details.getName(),
addLivenessMonitor,
bspStatusOpt,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ final class BloopServers(
projectRoot: AbsolutePath,
bspTraceRoot: AbsolutePath,
userConfiguration: UserConfiguration,
addLivenessMonitor: Boolean,
bspStatusOpt: Option[ConnectionBspStatus],
): Future[BuildServerConnection] = {
val bloopVersion = userConfiguration.currentBloopVersion
BuildServerConnection
Expand All @@ -95,7 +95,7 @@ final class BloopServers(
tables.dismissedNotifications.ReconnectBsp,
config,
name,
addLivenessMonitor,
bspStatusOpt,
)
}

Expand Down
36 changes: 36 additions & 0 deletions metals/src/main/scala/scala/meta/internal/metals/BspStatus.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package scala.meta.internal.metals

import java.util.Collections
import java.util.concurrent.atomic.AtomicReference

import scala.meta.internal.metals.clients.language.MetalsLanguageClient
import scala.meta.internal.metals.clients.language.MetalsStatusParams
import scala.meta.io.AbsolutePath

class BspStatus(client: MetalsLanguageClient, isBspStatusProvider: Boolean) {
val focusedFolder: AtomicReference[Option[AbsolutePath]] =
new AtomicReference(None)
val messages: java.util.Map[AbsolutePath, MetalsStatusParams] =
Collections.synchronizedMap(
new java.util.HashMap[AbsolutePath, MetalsStatusParams]
)

def status(folder: AbsolutePath, params: MetalsStatusParams): Unit = {
messages.put(folder, params)
if (focusedFolder.get().isEmpty || focusedFolder.get().contains(folder)) {
client.metalsStatus(params)
}
}

def focus(folder: AbsolutePath): Unit = {
if (isBspStatusProvider) {
val prev = focusedFolder.getAndSet(Some(folder))
if (!prev.contains(folder)) {
client.metalsStatus(
messages.getOrDefault(folder, ConnectionBspStatus.disconnectedParams)
)
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ object BuildServerConnection {
reconnectNotification: DismissedNotifications#Notification,
config: MetalsServerConfig,
serverName: String,
addLivenessMonitor: Boolean = false,
bspStatusOpt: Option[ConnectionBspStatus] = None,
retry: Int = 5,
supportsWrappedSources: Option[Boolean] = None,
)(implicit
Expand All @@ -454,12 +454,8 @@ object BuildServerConnection {
def setupServer(): Future[LauncherConnection] = {
connect().map { case conn @ SocketConnection(_, output, input, _, _) =>
val tracePrinter = Trace.setupTracePrinter("BSP", bspTraceRoot)
val bspStatusOpt =
if (addLivenessMonitor)
Some(new ConnectionBspStatus(languageClient, serverName, config.icons))
else None
val requestMonitorOpt =
bspStatusOpt.map(new RequestMonitorImpl(_))
bspStatusOpt.map(new RequestMonitorImpl(_, serverName))
val wrapper: MessageConsumer => MessageConsumer =
requestMonitorOpt.map(_.wrapper).getOrElse(identity)
val launcher =
Expand Down Expand Up @@ -497,6 +493,7 @@ object BuildServerConnection {
config.metalsToIdleTime,
config.pingInterval,
bspStatus,
serverName,
)

LauncherConnection(
Expand Down Expand Up @@ -535,7 +532,7 @@ object BuildServerConnection {
reconnectNotification,
config,
serverName,
addLivenessMonitor,
bspStatusOpt,
retry - 1,
)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,31 @@ package scala.meta.internal.metals

import java.util.concurrent.atomic.AtomicBoolean

import scala.meta.internal.metals.clients.language.MetalsLanguageClient
import scala.meta.internal.metals.clients.language.MetalsStatusParams
import scala.meta.internal.metals.clients.language.StatusType
import scala.meta.io.AbsolutePath

class ConnectionBspStatus(
client: MetalsLanguageClient,
serverName: String,
bspStatus: BspStatus,
folderPath: AbsolutePath,
icons: Icons,
) {
private val isServerResponsive = new AtomicBoolean(false)
val status: MetalsStatusParams => Unit = bspStatus.status(folderPath, _)

def connected(): Unit =
def connected(serverName: String): Unit =
if (isServerResponsive.compareAndSet(false, true))
client.metalsStatus(ConnectionBspStatus.connectedParams(serverName, icons))
def noResponse(): Unit =
status(ConnectionBspStatus.connectedParams(serverName, icons))
def noResponse(serverName: String): Unit =
if (isServerResponsive.compareAndSet(true, false)) {
scribe.debug("server liveness monitor detected no response")
client.metalsStatus(ConnectionBspStatus.noResponseParams(serverName, icons))
status(ConnectionBspStatus.noResponseParams(serverName, icons))
}
def disconnected(): Unit = client.metalsStatus(ConnectionBspStatus.disconnectedParams)

def disconnected(): Unit = {
isServerResponsive.set(false)
status(ConnectionBspStatus.disconnectedParams)
}

def isBuildServerResponsive: Boolean = isServerResponsive.get()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ class MetalsLspService(
folder: AbsolutePath,
folderVisibleName: Option[String],
headDoctor: HeadDoctor,
bspStatus: BspStatus,
) extends Folder(folder, folderVisibleName, isKnownMetalsProject = true)
with Cancelable
with TextDocumentService {
Expand Down Expand Up @@ -423,6 +424,9 @@ class MetalsLspService(
clientConfig.initialConfig,
)

private val connectionBspStatus =
new ConnectionBspStatus(bspStatus, folder, clientConfig.icons())

private val bspServers: BspServers = new BspServers(
folder,
charset,
Expand All @@ -445,6 +449,7 @@ class MetalsLspService(
bspConfigGenerator,
() => bspSession.map(_.mainConnection),
restartBspServer,
connectionBspStatus,
)

private val workspaceSymbols: WorkspaceSymbolProvider =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ trait RequestMonitor {
def lastIncoming: Option[Long]
}

class RequestMonitorImpl(bspStatus: ConnectionBspStatus) extends RequestMonitor {
class RequestMonitorImpl(bspStatus: ConnectionBspStatus, serverName: String)
extends RequestMonitor {
@volatile private var lastOutgoing_ : Option[Long] = None
@volatile private var lastIncoming_ : Option[Long] = None

Expand All @@ -40,7 +41,7 @@ class RequestMonitorImpl(bspStatus: ConnectionBspStatus) extends RequestMonitor

private def outgoingMessage() = lastOutgoing_ = now
private def incomingMessage(): Unit = {
bspStatus.connected()
bspStatus.connected(serverName)
lastIncoming_ = now
}
private def now = Some(System.currentTimeMillis())
Expand All @@ -55,6 +56,7 @@ class ServerLivenessMonitor(
metalsIdleInterval: Duration,
pingInterval: Duration,
bspStatus: ConnectionBspStatus,
serverName: String,
) {
@volatile private var lastPing: Long = 0
val scheduler: ScheduledExecutorService = Executors.newScheduledThreadPool(1)
Expand All @@ -70,7 +72,7 @@ class ServerLivenessMonitor(
def notResponding = lastIncoming > (pingInterval.toMillis * 2)
if (!metalsIsIdle) {
if (lastPingOk && notResponding) {
bspStatus.noResponse()
bspStatus.noResponse(serverName)
}
scribe.debug("server liveness monitor: pinging build server...")
lastPing = now
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import scala.meta.internal.metals.MetalsLspService
import scala.meta.internal.metals.WindowStateDidChangeParams
import scala.meta.internal.metals.clients.language.ConfiguredLanguageClient
import scala.meta.internal.metals.clients.language.MetalsLanguageClient
import scala.meta.internal.metals.config.StatusBarState
import scala.meta.internal.metals.debug.BuildTargetNotFoundException
import scala.meta.internal.metals.debug.BuildTargetUndefinedException
import scala.meta.internal.metals.debug.DebugProvider
Expand Down Expand Up @@ -150,6 +151,18 @@ class WorkspaceLspService(
languageClient,
)

private val bspStatus = new BspStatus(
languageClient,
isBspStatusProvider = clientConfig.bspStatusBarState() == StatusBarState.On,
)

def setFocusedDocument(newFocusedDocument: Option[AbsolutePath]): Unit = {
newFocusedDocument
.flatMap(getServiceForOpt)
.foreach(service => bspStatus.focus(service.path))
focusedDocument = newFocusedDocument
}

def createService(folder: Folder): MetalsLspService =
folder match {
case Folder(uri, name) =>
Expand All @@ -168,6 +181,7 @@ class WorkspaceLspService(
uri,
name,
doctor,
bspStatus,
)
}

Expand Down Expand Up @@ -318,7 +332,7 @@ class WorkspaceLspService(
focusedDocument.foreach(recentlyFocusedFiles.add)
val uri = params.getTextDocument.getUri
val path = uri.toAbsolutePath
focusedDocument = Some(path)
setFocusedDocument(Some(path))
val service = getServiceForOpt(path)
.orElse {
if (path.filename.isScalaOrJavaFilename) {
Expand All @@ -338,7 +352,7 @@ class WorkspaceLspService(
override def didClose(params: DidCloseTextDocumentParams): Unit = {
val path = params.getTextDocument.getUri.toAbsolutePath
if (focusedDocument.contains(path)) {
focusedDocument = recentlyFocusedFiles.pollRecent()
setFocusedDocument(recentlyFocusedFiles.pollRecent())
}
getServiceFor(params.getTextDocument().getUri()).didClose(params)
}
Expand Down Expand Up @@ -605,7 +619,7 @@ class WorkspaceLspService(
}
uriOpt match {
case Some(uri) =>
focusedDocument = Some(uri.toAbsolutePath)
setFocusedDocument(Some(uri.toAbsolutePath))
getServiceFor(uri).didFocus(uri)
case None =>
CompletableFuture.completedFuture(DidFocusResult.NoBuildTarget)
Expand Down
Loading

0 comments on commit df3fa6c

Please sign in to comment.