Skip to content

Commit

Permalink
feat(intellij): automatically download the language server if it's no…
Browse files Browse the repository at this point in the history
…t found
  • Loading branch information
chrissimon-au committed Mar 11, 2024
1 parent fad50b8 commit 38db4b7
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 4 deletions.
6 changes: 5 additions & 1 deletion src/intellij/contextive/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ plugins {
}

group = "tech.contextive"
version = "1.11.0-beta"
version = "1.10.5"

repositories {
mavenCentral()
}

dependencies {
implementation("net.lingala.zip4j:zip4j:2.11.5")
}

// Configure Gradle IntelliJ Plugin
// Read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html
intellij {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
package tech.contextive.contextive

import com.intellij.execution.configurations.GeneralCommandLine
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.lsp.api.LspServerSupportProvider
import com.intellij.platform.lsp.api.ProjectWideLspServerDescriptor

private val LOG = logger<ContextiveLspServerSupportProvider>()

class ContextiveLspServerSupportProvider : LspServerSupportProvider {
override fun fileOpened(project: Project, file: VirtualFile, serverStarter: LspServerSupportProvider.LspServerStarter) {
override fun fileOpened(
project: Project,
file: VirtualFile,
serverStarter: LspServerSupportProvider.LspServerStarter
) {
serverStarter.ensureServerStarted(ContextiveLspServerDescriptor(project))
}

}

private class ContextiveLspServerDescriptor(project: Project) : ProjectWideLspServerDescriptor(project, "Contextive") {
override fun isSupportedFile(file: VirtualFile) = true
override fun createCommandLine(): GeneralCommandLine = GeneralCommandLine("Contextive.LanguageServer")
override fun createCommandLine(): GeneralCommandLine =
downloadLanguageServerIfNotFound().run { GeneralCommandLine(this.toString()) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package tech.contextive.contextive

import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.extensions.PluginId
import net.lingala.zip4j.io.inputstream.ZipInputStream
import net.lingala.zip4j.model.LocalFileHeader
import java.io.FileOutputStream
import java.net.URI
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.attribute.PosixFilePermission
import kotlin.io.path.exists
import kotlin.io.path.getPosixFilePermissions
import kotlin.io.path.setPosixFilePermissions


private val LOG = logger<LanguageServerDownloader>()

private const val LANGUAGE_SERVER_TEMPLATE =
"/~https://github.com/dev-cycles/contextive/releases/download/v%s/Contextive.LanguageServer-%s-%s-%1\$s.zip"
private const val CONTEXTIVE_ID = "tech.contextive.contextive"

private fun getOsCode(): String = System.getProperty("os.name").lowercase().run {
when {
"win" in this -> "win"
"mac" in this -> "osx"
else -> "linux"
}
}

private fun getArchCode(): String = System.getProperty("os.arch").lowercase().run {
when {
"aarch64" in this -> "arm64"
else -> "x64"
}
}

private fun getLanguageServerFileName(): String = "Contextive.LanguageServer" + getOsCode().run {
when {
"win" in this -> ".exe"
else -> ""
}
}

fun getLsPath(): Path =
PluginManagerCore
.getPlugin(PluginId.getId(CONTEXTIVE_ID))!!.run {
this.pluginPath.resolve("language-server")
.resolve(this.version).resolve(getLanguageServerFileName())
}


private fun downloadLanguageServer(languageServerZipUrl: String, lsPath: Path) {
var localFileHeader: LocalFileHeader?
val readBuffer = ByteArray(4096)
var readLen: Int

var destination = lsPath.parent

LOG.info("Downloading LanguageServer from $languageServerZipUrl")
Files.createDirectories(destination)
val zipInputStream = ZipInputStream(URI(languageServerZipUrl).toURL().openStream())
while (zipInputStream.nextEntry.also { localFileHeader = it } != null) {
val extractedFile = destination.resolve(localFileHeader!!.fileName).toFile()
LOG.info("Extracting `${localFileHeader!!.fileName}` to `${extractedFile.path}`")
FileOutputStream(extractedFile).use { outputStream ->
while (zipInputStream.read(readBuffer).also { readLen = it } != -1) {
outputStream.write(readBuffer, 0, readLen)
}
}
}
lsPath.setPosixFilePermissions(lsPath.getPosixFilePermissions().plus(PosixFilePermission.OWNER_EXECUTE))
LOG.info("LanguageServer downloaded and extracted.")
}

fun downloadLanguageServerIfNotFound(): Path {
val lsPath = getLsPath()
val plugin = PluginManagerCore.getPlugin(PluginId.getId(CONTEXTIVE_ID))!!
LOG.info("Looking for LanguageServer at `${lsPath}`")
if (!lsPath.exists()) {
val url = LANGUAGE_SERVER_TEMPLATE.format(plugin.version, getOsCode(), getArchCode())
downloadLanguageServer(url, lsPath)
} else {
LOG.info("Found LanguageServer, not downloading.")
}
return lsPath
}

class LanguageServerDownloader
3 changes: 2 additions & 1 deletion src/vscode/contextive/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
!test/index.js
**/*.vsix
dist
out
out
.idea

0 comments on commit 38db4b7

Please sign in to comment.