Skip to content

Commit

Permalink
if folders removed reload all services
Browse files Browse the repository at this point in the history
  • Loading branch information
kasiaMarek committed May 7, 2024
1 parent c3a0e2b commit 3369e64
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,31 @@ import scala.meta.internal.metals.logging.MetalsLogger
class WorkspaceFolders(
initialFolders: List[Folder],
createService: Folder => MetalsLspService,
shutdownMetals: () => Future[Unit],
redirectSystemOut: Boolean,
initialServerConfig: MetalsServerConfig,
userConfigSync: UserConfigurationSync,
)(implicit ec: ExecutionContext) {

private val folderServices: AtomicReference[WorkspaceFoldersServices] = {
private val allFolders: AtomicReference[List[Folder]] =
new AtomicReference(initialFolders)
private val folderServices: AtomicReference[WorkspaceFoldersServices] =
new AtomicReference(initServices(initialFolders))

def getFolderServices: List[MetalsLspService] = folderServices.get().services
def nonScalaProjects: List[Folder] = folderServices.get().nonScalaFolders

def initServices(folders: List[Folder]): WorkspaceFoldersServices = {
val (scalaProjects, nonScalaProjects) =
initialFolders.partition(_.isMetalsProject)
folders.partition(_.isMetalsProject)
val scalaServices =
scalaProjects
.filterNot(
_.optDelegatePath.exists(path => scalaProjects.exists(_.path == path))
)
.map(createService)
new AtomicReference(
WorkspaceFoldersServices(scalaServices, nonScalaProjects)
)
WorkspaceFoldersServices(scalaServices, nonScalaProjects)
}

def getFolderServices: List[MetalsLspService] = folderServices.get().services
def nonScalaProjects: List[Folder] = folderServices.get().nonScalaFolders

def changeFolderServices(
toRemove: List[Folder],
toAdd: List[Folder],
Expand All @@ -44,8 +46,10 @@ class WorkspaceFolders(
def shouldBeRemoved(folder: Folder) =
actualToRemove.exists(_.path == folder.path)

allFolders.updateAndGet(_.filterNot(shouldBeRemoved) ++ toAdd)

val actualToAdd = toAdd.filterNot { folder =>
findDelegate(getFolderServices, folder) match {
findDelegate(getFolderServices.filterNot(shouldBeRemoved), folder) match {
case Some(service) =>
DelegateSetting.writeDeleteSetting(folder.path, service.path)
true
Expand All @@ -54,43 +58,39 @@ class WorkspaceFolders(
}
}

val WorkspaceFoldersServices(prev, _) =
folderServices.getAndUpdate {
case WorkspaceFoldersServices(
services,
nonScalaProjects,
) =>
val filteredServices = services.filterNot(shouldBeRemoved)

val (newScala, newNonScala) = actualToAdd
.filterNot(isIn(services ++ nonScalaProjects, _))
.partition(_.isMetalsProject)

val allNewScala = newScala.map(createService)

val updatedServices = filteredServices ++ allNewScala

val updatedNonScala =
nonScalaProjects.filterNot(shouldBeRemoved) ++ newNonScala

WorkspaceFoldersServices(
updatedServices,
updatedNonScala,
)
val servicesToInit =
if (actualToRemove.isEmpty) {
val WorkspaceFoldersServices(prev, _) =
folderServices.getAndUpdate {
case WorkspaceFoldersServices(
services,
nonScalaProjects,
) =>
val (newScala, newNonScala) = actualToAdd
.filterNot(isIn(services ++ nonScalaProjects, _))
.partition(_.isMetalsProject)

val allNewScala = newScala.map(createService)

WorkspaceFoldersServices(
services ++ allNewScala,
nonScalaProjects ++ newNonScala,
)
}
getFolderServices.filterNot(isIn(prev, _))
} else {
val WorkspaceFoldersServices(prev, _) =
folderServices.getAndUpdate(_ => initServices(allFolders.get()))

prev.foreach(_.onShutdown())
getFolderServices
}

if (getFolderServices.isEmpty) {
shutdownMetals()
} else {
setupLogger()

val services = getFolderServices.filterNot(isIn(prev, _))
for {
_ <- userConfigSync.initSyncUserConfiguration(services)
_ <- Future.sequence(services.map(_.initialized()))
_ <- Future(prev.filter(shouldBeRemoved).foreach(_.onShutdown()))
} yield ()
}
setupLogger()
for {
_ <- userConfigSync.initSyncUserConfiguration(servicesToInit)
_ <- Future.sequence(servicesToInit.map(_.initialized()))
} yield ()
}

def convertToScalaProject(folder: Folder): Option[MetalsLspService] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,6 @@ class WorkspaceLspService(
new WorkspaceFolders(
folders,
createService,
() => shutdown().asScala,
redirectSystemOut,
serverInputs.initialServerConfig,
userConfigSync,
Expand Down Expand Up @@ -1317,6 +1316,12 @@ class Folder(
isKnownMetalsProject || path.resolve(".metals").exists || path
.isMetalsProject()

/**
* A workspace folder might be a project reference for an other project.
* In that case all its commands will be delegated to the main project's service.
* We keep the path to main project's root in a dedicated setting, so even
* before the main project is imported, this folder is known to be a reference.
*/
lazy val optDelegatePath: Option[AbsolutePath] =
DelegateSetting.readDeleteSetting(path)

Expand Down

0 comments on commit 3369e64

Please sign in to comment.