Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: improve BiomePackage and LSP startup logic #129

Merged
merged 1 commit into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 36 additions & 36 deletions src/main/kotlin/com/github/biomejs/intellijbiome/BiomePackage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.github.biomejs.intellijbiome.settings.BiomeSettings
import com.github.biomejs.intellijbiome.settings.ConfigurationMode
import com.intellij.javascript.nodejs.interpreter.NodeJsInterpreterManager
import com.intellij.javascript.nodejs.util.NodePackage
import com.intellij.javascript.nodejs.util.NodePackageDescriptor
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import kotlinx.coroutines.future.await
Expand All @@ -14,12 +15,32 @@ import java.nio.file.Paths
private val versionRegex: Regex = Regex("\\d{1,2}\\.\\d{1,2}\\.\\d{1,3}")

class BiomePackage(private val project: Project) {
private val interpreter = NodeJsInterpreterManager.getInstance(project).interpreter
private val nodePackage: NodePackage?
get() {
return NodePackage.findDefaultPackage(project, "@biomejs/biome", interpreter)
private val packageName = "@biomejs/biome"
private val packageDescription = NodePackageDescriptor(packageName)

fun getPackage(virtualFile: VirtualFile?): NodePackage? {
if (virtualFile != null) {
val available = packageDescription.listAvailable(
project,
NodeJsInterpreterManager.getInstance(project).interpreter,
virtualFile,
false,
true
)
if (available.isNotEmpty()) {
return available[0]
}
}

var pkg = packageDescription.findUnambiguousDependencyPackage(project) ?: NodePackage.findDefaultPackage(
project,
packageName,
NodeJsInterpreterManager.getInstance(project).interpreter
)

return pkg
}

fun configPath(file: VirtualFile): String? {
val settings = BiomeSettings.getInstance(project)
val configurationMode = settings.configurationMode
Expand All @@ -35,26 +56,29 @@ class BiomePackage(private val project: Project) {
val configurationMode = settings.configurationMode
return when (configurationMode) {
ConfigurationMode.DISABLED -> null
ConfigurationMode.AUTOMATIC -> nodePackage?.getVersion(project)?.toString()
ConfigurationMode.MANUAL -> getBinaryVersion(binaryPath(null, true))
ConfigurationMode.AUTOMATIC -> getPackage(null)?.version?.toString()
ConfigurationMode.MANUAL -> getBinaryVersion(settings.executablePath)
}
}

fun binaryPath(configPath: String?,
showVersion: Boolean): String? {
fun binaryPath(
configPath: String?,
virtualFile: VirtualFile,
showVersion: Boolean,
): String? {
val settings = BiomeSettings.getInstance(project)
val configurationMode = settings.configurationMode
return when (configurationMode) {
ConfigurationMode.DISABLED -> null // don't try to find the executable path if the configuration file does not exist.
// This will prevent start LSP and formatting in case if biome is not used in the project.
ConfigurationMode.AUTOMATIC -> if (configPath != null || showVersion) findBiomeExecutable() else null // if configuration mode is manual, return the executable path if it is not empty string.
ConfigurationMode.AUTOMATIC -> if (configPath != null || showVersion) findBiomeExecutable(virtualFile) else null // if configuration mode is manual, return the executable path if it is not empty string.
// Otherwise, try to find the executable path.
ConfigurationMode.MANUAL -> if (settings.executablePath == "") findBiomeExecutable() else settings.executablePath
ConfigurationMode.MANUAL -> settings.executablePath
}
}

private fun findBiomeExecutable(): String? {
val path = nodePackage?.getAbsolutePackagePathToRequire(project)
private fun findBiomeExecutable(virtualFile: VirtualFile?): String? {
val path = getPackage(virtualFile)?.getAbsolutePackagePathToRequire(project)
if (path != null) {
return Paths.get(path, "bin/biome").toString()
}
Expand Down Expand Up @@ -95,28 +119,4 @@ class BiomePackage(private val project: Project) {
}
return null
}

fun compareVersion(version1: String,
version2: String): Int {
// standardize nightly versions like 1.9.5-nightly.81fdedb to 1.9.5
val cleanVersion1 = version1.split("-").first()
val cleanVersion2 = version2.split("-").first()
val parts1 = cleanVersion1.split(".").map { it.toInt() }
val parts2 = cleanVersion2.split(".").map { it.toInt() }

val maxLength = maxOf(parts1.size, parts2.size)

for (i in 0 until maxLength) {
val v1 = if (i < parts1.size) parts1[i] else 0
val v2 = if (i < parts2.size) parts2[i] else 0

when {
v1 < v2 -> return -1
v1 > v2 -> return 1
}
}

return 0
}

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.github.biomejs.intellijbiome

import com.github.biomejs.intellijbiome.extensions.isNodeScript
import com.github.biomejs.intellijbiome.settings.BiomeSettings
import com.github.biomejs.intellijbiome.settings.ConfigurationMode
import com.intellij.execution.ExecutionException
import com.intellij.javascript.nodejs.interpreter.NodeJsInterpreterManager
import com.intellij.javascript.nodejs.interpreter.local.NodeJsLocalInterpreter
import com.intellij.javascript.nodejs.interpreter.wsl.WslNodeInterpreter
import com.intellij.lang.javascript.JavaScriptBundle
import com.intellij.openapi.project.Project
import java.io.File

class BiomeTargetRunBuilder(val project: Project) {
fun getBuilder(
Expand All @@ -17,16 +17,17 @@ class BiomeTargetRunBuilder(val project: Project) {
throw ExecutionException(BiomeBundle.message("biome.language.server.not.found"))
}

val executableFile = File(executable)
val settings = BiomeSettings.getInstance(project)
val configurationMode = settings.configurationMode

val builder: ProcessCommandBuilder = if (executableFile.isFile && executableFile.isNodeScript()) {
val builder: ProcessCommandBuilder = if (configurationMode == ConfigurationMode.MANUAL) {
GeneralProcessCommandBuilder()
} else {
val interpreter = NodeJsInterpreterManager.getInstance(project).interpreter
if (interpreter !is NodeJsLocalInterpreter && interpreter !is WslNodeInterpreter) {
throw ExecutionException(JavaScriptBundle.message("lsp.interpreter.error"))
}
NodeProcessCommandBuilder(project, interpreter)
} else {
GeneralProcessCommandBuilder()
}

return builder.setExecutable(executable).setWorkingDirectory(project.basePath).setCharset(Charsets.UTF_8)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ import com.intellij.util.SmartList
) {
val currentConfigPath = project.service<BiomeServerService>().getCurrentConfigPath()
if (currentConfigPath != null) {
val executable = BiomePackage(project).binaryPath(currentConfigPath, false) ?: return
val executable = BiomePackage(project).binaryPath(currentConfigPath, file, false) ?: return
serverStarter.ensureServerStarted(BiomeLspServerDescriptor(project, executable, currentConfigPath))
return
}

val configPath = BiomePackage(project).configPath(file)
val executable = BiomePackage(project).binaryPath(configPath, false) ?: return
val executable = BiomePackage(project).binaryPath(configPath, file, false) ?: return
serverStarter.ensureServerStarted(BiomeLspServerDescriptor(project, executable, configPath))
}

Expand All @@ -45,7 +45,8 @@ import com.intellij.util.SmartList
@Suppress("UnstableApiUsage") private class BiomeLspServerDescriptor(project: Project,
val executable: String,
val configPath: String?) : ProjectWideLspServerDescriptor(project, "Biome") {
private val targetRunBuilder = BiomeTargetRunBuilder(project)
private val targetRunBuilder: BiomeTargetRunBuilder
get() = BiomeTargetRunBuilder(project)

override fun isSupportedFile(file: VirtualFile): Boolean {
return BiomeSettings.getInstance(project).fileSupported(file)
Expand Down