Skip to content

Commit

Permalink
merge queue for starting lsp servers
Browse files Browse the repository at this point in the history
  • Loading branch information
van800 committed Jan 19, 2024
1 parent 8bacda2 commit e697471
Showing 1 changed file with 61 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import com.intellij.platform.lsp.api.LspCommunicationChannel
import com.intellij.platform.lsp.api.LspServerManager
import com.intellij.platform.lsp.api.LspServerSupportProvider
import com.intellij.platform.lsp.api.ProjectWideLspServerDescriptor
import com.intellij.util.ui.update.MergingUpdateQueue
import com.intellij.util.ui.update.Update
import com.jetbrains.rd.platform.util.idea.LifetimedService
import com.jetbrains.rd.util.lifetime.Lifetime
import com.jetbrains.rd.util.lifetime.SequentialLifetimes
import com.jetbrains.rd.util.lifetime.isAlive
import com.jetbrains.rd.util.reactive.adviseNotNull
Expand All @@ -26,38 +27,71 @@ import java.net.Socket
import java.util.concurrent.atomic.AtomicBoolean

@Service(Service.Level.PROJECT)
class LspPreparationService(val project: Project): LifetimedService() {
class LspProjectService(val project: Project) : LifetimedService() {
var isScheduled: AtomicBoolean = AtomicBoolean(false)

companion object {
fun getInstance(project: Project) = project.service<LspPreparationService>()
fun getInstance(project: Project) = project.service<LspProjectService>()
}

val sequentialLifetimes = SequentialLifetimes(project.lifetime)
val mergingUpdateQueue: MergingUpdateQueue = MergingUpdateQueue("GodotLspServerSupportProviderMergingUpdateQueue", 1000, true, null).setRestartTimerOnAdd(true)
val mergingUpdateQueueAction: Update = object : Update("restartServerIfNeeded") {
override fun run() {
restartServer(project)
}
}

private fun restartServer(project: Project) {
LspServerManager.getInstance(project).stopServers(GodotLspServerSupportProvider::class.java)
thisLogger().info("startServersIfNeeded")
LspServerManager.getInstance(project).startServersIfNeeded(GodotLspServerSupportProvider::class.java)
}

private fun pingSocket(port: Int): Boolean {
return try {
thisLogger().info("pingSocket1")
Socket().use { socket ->
thisLogger().info("pingSocket2")
socket.connect(InetSocketAddress("127.0.0.1", port))
true
}
} catch (e: IOException) {
false
}
}
}
class GodotLspServerSupportProvider : LspServerSupportProvider {

private val sequentialLifetimes = SequentialLifetimes(Lifetime.Eternal)
class GodotLspServerSupportProvider : LspServerSupportProvider {

override fun fileOpened(project: Project, file: VirtualFile, serverStarter: LspServerSupportProvider.LspServerStarter) {
if (Util.isGdFile(file)) {
val discoverer = GodotProjectDiscoverer.getInstance(project)
if (discoverer.lspConnectionMode.value != LanguageServerConnectionMode.Never
&& discoverer.godotPath.value != null && discoverer.remoteHostPort.value != null
&& discoverer.godotDescriptor.value != null)
{
val lspService = LspProjectService.getInstance(project)
if (allReady(discoverer)) {
thisLogger().info("ensureServerStarted")
serverStarter.ensureServerStarted(GodotLspServerDescriptor(project)) // this does not start the server, if fileOpened already ended
}
else if (LspPreparationService.getInstance(project).isScheduled.compareAndSet(false, true)){
val lifetime = sequentialLifetimes.next()
} else if (lspService.isScheduled.compareAndSet(false, true)) {
val lifetime = lspService.sequentialLifetimes.next()
project.lifetime.onTerminationIfAlive { if (lifetime.isAlive) lifetime.terminate() }
discoverer.lspConnectionMode.adviseNotNull(lifetime) { lspConnectionMode ->
if (lspConnectionMode == LanguageServerConnectionMode.Never) {
LspServerManager.getInstance(project).stopServers(this.javaClass)
return@adviseNotNull
}
discoverer.useDynamicPort.adviseNotNull(lifetime) { useDynamicPort ->
discoverer.godotDescriptor.adviseNotNull(lifetime) {
discoverer.godotPath.adviseNotNull(lifetime) {

scheduleStartIfNeeded(project)
}
discoverer.useDynamicPort.adviseNotNull(lifetime) {
scheduleStartIfNeeded(project)
}
discoverer.godotDescriptor.adviseNotNull(lifetime) {
scheduleStartIfNeeded(project)
}
discoverer.godotPath.adviseNotNull(lifetime) {
scheduleStartIfNeeded(project)
}

// todo: restore
// if (lspConnectionMode == LanguageServerConnectionMode.ConnectRunningEditor) {
// thisLogger().info("fileOpened6 ${remoteHostPort}")
Expand All @@ -71,34 +105,25 @@ class GodotLspServerSupportProvider : LspServerSupportProvider {
// delay(500)
// serverStarter.ensureServerStarted(GodotLspServerDescriptor(project))
// }.noAwait()
// } else {

thisLogger().info("startServersIfNeeded")
LspServerManager.getInstance(project).startServersIfNeeded(this.javaClass)
// }
}
}
}
}
}
}
}

private fun pingSocket(port: Int): Boolean {
return try {
thisLogger().info("pingSocket1")
Socket().use { socket ->
thisLogger().info("pingSocket2")
socket.connect(InetSocketAddress("127.0.0.1", port))
true
}
} catch (e: IOException) {
false
}
private fun allReady(discoverer: GodotProjectDiscoverer) = (
discoverer.lspConnectionMode.value != LanguageServerConnectionMode.Never
&& discoverer.godotPath.value != null
&& discoverer.remoteHostPort.value != null
&& discoverer.godotDescriptor.value != null)

private fun scheduleStartIfNeeded(project: Project) {
val lspProjectService = LspProjectService.getInstance(project)
val discoverer = GodotProjectDiscoverer.getInstance(project)
if (!allReady(discoverer)) return
lspProjectService.mergingUpdateQueue.queue(lspProjectService.mergingUpdateQueueAction)
}

private class GodotLspServerDescriptor(project: Project) : ProjectWideLspServerDescriptor(project, "Godot") {

val discoverer = GodotProjectDiscoverer.getInstance(project)
val lspConnectionMode by lazy { discoverer.lspConnectionMode.value }
val remoteHostPort by lazy { if (useDynamicPort!!) NetUtils.findFreePort(500050, setOf()) else discoverer.remoteHostPort.value }
Expand All @@ -118,8 +143,7 @@ class GodotLspServerSupportProvider : LspServerSupportProvider {
override val lspCommunicationChannel: LspCommunicationChannel
get() {
thisLogger().info("lspCommunicationChannel port=$remoteHostPort, mode=$lspConnectionMode")
return LspCommunicationChannel.Socket(remoteHostPort!!,
lspConnectionMode == LanguageServerConnectionMode.StartEditorHeadless)
return LspCommunicationChannel.Socket(remoteHostPort!!, lspConnectionMode == LanguageServerConnectionMode.StartEditorHeadless)
}
}
}

0 comments on commit e697471

Please sign in to comment.