33"""
44
55import asyncio
6+ import dataclasses
67import json
78import logging
89import os
2021from multilspy .multilspy_utils import PlatformUtils
2122
2223
24+ @dataclasses .dataclass
25+ class KotlinRuntimeDependencyPaths :
26+ """
27+ Stores the paths to the runtime dependencies of Kotlin Language Server
28+ """
29+ java_path : str
30+ java_home_path : str
31+ kotlin_executable_path : str
32+
33+
2334class KotlinLanguageServer (LanguageServer ):
2435 """
2536 Provides Kotlin specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Kotlin.
@@ -29,16 +40,24 @@ def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_
2940 """
3041 Creates a Kotlin Language Server instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
3142 """
32- kotlin_executable_path = self .setup_runtime_dependencies (logger , config )
43+ runtime_dependency_paths = self .setup_runtime_dependencies (logger , config )
44+ self .runtime_dependency_paths = runtime_dependency_paths
45+
46+ # Create command to execute the Kotlin Language Server script
47+ cmd = f'"{ self .runtime_dependency_paths .kotlin_executable_path } "'
48+
49+ # Set environment variables including JAVA_HOME
50+ proc_env = {"JAVA_HOME" : self .runtime_dependency_paths .java_home_path }
51+
3352 super ().__init__ (
3453 config ,
3554 logger ,
3655 repository_root_path ,
37- ProcessLaunchInfo (cmd = kotlin_executable_path , cwd = repository_root_path ),
56+ ProcessLaunchInfo (cmd = cmd , env = proc_env , cwd = repository_root_path ),
3857 "kotlin" ,
3958 )
4059
41- def setup_runtime_dependencies (self , logger : MultilspyLogger , config : MultilspyConfig ) -> str :
60+ def setup_runtime_dependencies (self , logger : MultilspyLogger , config : MultilspyConfig ) -> KotlinRuntimeDependencyPaths :
4261 """
4362 Setup runtime dependencies for Kotlin Language Server.
4463 """
@@ -47,39 +66,69 @@ def setup_runtime_dependencies(self, logger: MultilspyLogger, config: MultilspyC
4766 # Verify platform support
4867 assert platform_id .value .startswith ("win-" ) or platform_id .value .startswith ("linux-" ) or platform_id .value .startswith ("osx-" ), "Only Windows, Linux and macOS platforms are supported for Kotlin in multilspy at the moment"
4968
50- # Determine the binary name based on platform
51- binary_name = "kotlin-language-server.bat" if platform_id .value .startswith ("win-" ) else "kotlin-language-server"
52-
5369 # Load dependency information
5470 with open (os .path .join (os .path .dirname (__file__ ), "runtime_dependencies.json" ), "r" ) as f :
5571 d = json .load (f )
5672 del d ["_description" ]
5773
58- dependency = d ["runtimeDependency" ]
59-
60- # Setup paths and download if necessary
61- kotlin_ls_dir = os .path .join (os .path .dirname (__file__ ), "static" )
62- kotlin_bin_path = os .path .join (kotlin_ls_dir , "server" , "bin" )
63- kotlin_executable_path = os .path .join (kotlin_bin_path , binary_name )
74+ kotlin_dependency = d ["runtimeDependency" ]
75+ jdk_dependency = d ["jdk" ][platform_id .value ]
6476
65- if not os .path .exists (kotlin_ls_dir ):
66- os .makedirs (kotlin_ls_dir )
77+ # Setup paths for dependencies
78+ static_dir = os .path .join (os .path .dirname (__file__ ), "static" )
79+ os .makedirs (static_dir , exist_ok = True )
80+
81+ # Setup JDK paths
82+ jdk_dir = os .path .join (static_dir , "jdk" )
83+ os .makedirs (jdk_dir , exist_ok = True )
84+
85+ java_home_path = os .path .join (jdk_dir , jdk_dependency ["java_home_path" ])
86+ java_path = os .path .join (jdk_dir , jdk_dependency ["java_path" ])
87+
88+ # Download and extract JDK if not exists
89+ if not os .path .exists (java_path ):
90+ logger .log (f"Downloading JDK for { platform_id .value } ..." , logging .INFO )
6791 FileUtils .download_and_extract_archive (
68- logger , dependency ["url" ], kotlin_ls_dir , dependency ["archiveType" ]
92+ logger , jdk_dependency ["url" ], jdk_dir , jdk_dependency ["archiveType" ]
6993 )
70-
71- assert os .path .exists (kotlin_executable_path )
94+ # Make Java executable
95+ if not platform_id .value .startswith ("win-" ):
96+ os .chmod (java_path , 0o755 )
97+
98+ assert os .path .exists (java_path ), f"Java executable not found at { java_path } "
7299
73- # Set proper executable permissions (read+execute for everyone)
74- os .chmod ( kotlin_executable_path , 0o755 )
100+ # Setup Kotlin Language Server paths
101+ kotlin_ls_dir = os .path . join ( static_dir , "server" )
75102
76- # Create command that will properly execute the script
103+ # Get platform-specific executable script path
77104 if platform_id .value .startswith ("win-" ):
78- cmd = f'" { kotlin_executable_path } "'
105+ kotlin_script = os . path . join ( kotlin_ls_dir , "bin" , "kotlin-language-server.bat" )
79106 else :
80- cmd = f'/bin/sh "{ kotlin_executable_path } "'
81-
82- return cmd
107+ kotlin_script = os .path .join (kotlin_ls_dir , "bin" , "kotlin-language-server" )
108+
109+ # Download and extract Kotlin Language Server if script doesn't exist
110+ if not os .path .exists (kotlin_script ):
111+ logger .log ("Downloading Kotlin Language Server..." , logging .INFO )
112+ FileUtils .download_and_extract_archive (
113+ logger , kotlin_dependency ["url" ], static_dir , kotlin_dependency ["archiveType" ]
114+ )
115+
116+ # Make script executable on Unix platforms
117+ if os .path .exists (kotlin_script ) and not platform_id .value .startswith ("win-" ):
118+ os .chmod (kotlin_script , stat .S_IRUSR | stat .S_IWUSR | stat .S_IXUSR | stat .S_IRGRP | stat .S_IXGRP | stat .S_IROTH | stat .S_IXOTH )
119+
120+ # Use script file
121+ if os .path .exists (kotlin_script ):
122+ kotlin_executable_path = kotlin_script
123+ logger .log (f"Using Kotlin Language Server script at { kotlin_script } " , logging .INFO )
124+ else :
125+ raise FileNotFoundError (f"Kotlin Language Server script not found at { kotlin_script } " )
126+
127+ return KotlinRuntimeDependencyPaths (
128+ java_path = java_path ,
129+ java_home_path = java_home_path ,
130+ kotlin_executable_path = kotlin_executable_path
131+ )
83132
84133 def _get_initialize_params (self , repository_absolute_path : str ) -> InitializeParams :
85134 """
0 commit comments