mirror of
https://github.com/tiennm99/serena.git
synced 2026-07-14 20:22:36 +00:00
Add language server implementations from multilspy (unmodified)
This commit is contained in:
@@ -202,6 +202,7 @@ pylint.html
|
||||
/agent-ui
|
||||
# dynamic LS installations
|
||||
/src/multilspy/language_servers/*/static
|
||||
/src/solidlsp/language_servers/*/static
|
||||
|
||||
# Cache is in .multilspy
|
||||
**/.multilspy/**
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
"""
|
||||
Provides C/C++ specific instantiation of the LanguageServer class. Contains various configurations and settings specific to C/C++.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import stat
|
||||
import pathlib
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import AsyncIterator
|
||||
|
||||
from multilspy.multilspy_logger import MultilspyLogger
|
||||
from multilspy.language_server import LanguageServer
|
||||
from multilspy.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from multilspy.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from multilspy.multilspy_config import MultilspyConfig
|
||||
from multilspy.multilspy_utils import FileUtils
|
||||
from multilspy.multilspy_utils import PlatformUtils
|
||||
|
||||
|
||||
class ClangdLanguageServer(LanguageServer):
|
||||
"""
|
||||
Provides C/C++ specific instantiation of the LanguageServer class. Contains various configurations and settings specific to C/C++.
|
||||
As the project gets bigger in size, building index will take time. Try running clangd multiple times to ensure index is built properly.
|
||||
Also make sure compile_commands.json is created at root of the source directory. Check clangd test case for example.
|
||||
"""
|
||||
|
||||
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
|
||||
"""
|
||||
Creates a ClangdLanguageServer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
clangd_executable_path = self.setup_runtime_dependencies(logger, config)
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=clangd_executable_path, cwd=repository_root_path),
|
||||
"cpp",
|
||||
)
|
||||
self.server_ready = asyncio.Event()
|
||||
|
||||
def setup_runtime_dependencies(self, logger: MultilspyLogger, config: MultilspyConfig) -> str:
|
||||
"""
|
||||
Setup runtime dependencies for ClangdLanguageServer.
|
||||
"""
|
||||
platform_id = PlatformUtils.get_platform_id()
|
||||
|
||||
with open(os.path.join(os.path.dirname(__file__), "runtime_dependencies.json"), "r") as f:
|
||||
d = json.load(f)
|
||||
del d["_description"]
|
||||
|
||||
assert platform_id.value in [
|
||||
"linux-x64",
|
||||
"win-x64",
|
||||
"osx-arm64",
|
||||
], "Unsupported platform: " + platform_id.value
|
||||
|
||||
runtime_dependencies = d["runtimeDependencies"]
|
||||
runtime_dependencies = [
|
||||
dependency for dependency in runtime_dependencies if dependency["platformId"] == platform_id.value
|
||||
]
|
||||
assert len(runtime_dependencies) == 1
|
||||
# Select dependency matching the current platform
|
||||
dependency = next((dep for dep in runtime_dependencies if dep["platformId"] == platform_id.value), None)
|
||||
if dependency is None:
|
||||
raise RuntimeError(f"No runtime dependency found for platform {platform_id.value}")
|
||||
|
||||
clangd_ls_dir = os.path.join(os.path.dirname(__file__), "static", "clangd")
|
||||
clangd_executable_path = os.path.join(clangd_ls_dir, "clangd_19.1.2", "bin", dependency["binaryName"])
|
||||
if not os.path.exists(clangd_executable_path):
|
||||
clangd_url = dependency["url"]
|
||||
logger.log(f"Clangd executable not found at {clangd_executable_path}. Downloading from {clangd_url}", logging.INFO)
|
||||
os.makedirs(clangd_ls_dir, exist_ok=True)
|
||||
if dependency["archiveType"] == "zip":
|
||||
FileUtils.download_and_extract_archive(
|
||||
logger, clangd_url, clangd_ls_dir, dependency["archiveType"]
|
||||
)
|
||||
else:
|
||||
raise RuntimeError(f"Unsupported archive type: {dependency['archiveType']}")
|
||||
if not os.path.exists(clangd_executable_path):
|
||||
raise FileNotFoundError(
|
||||
f"Clangd executable not found at {clangd_executable_path}.\n"
|
||||
"Make sure you have installed clangd. See https://clangd.llvm.org/installation"
|
||||
)
|
||||
os.chmod(clangd_executable_path, stat.S_IEXEC)
|
||||
|
||||
return clangd_executable_path
|
||||
|
||||
def _get_initialize_params(self, repository_absolute_path: str) -> InitializeParams:
|
||||
"""
|
||||
Returns the initialize params for the clangd Language Server.
|
||||
"""
|
||||
with open(os.path.join(os.path.dirname(__file__), "initialize_params.json"), "r") as f:
|
||||
d = json.load(f)
|
||||
|
||||
del d["_description"]
|
||||
|
||||
d["processId"] = os.getpid()
|
||||
assert d["rootPath"] == "$rootPath"
|
||||
d["rootPath"] = repository_absolute_path
|
||||
|
||||
assert d["rootUri"] == "$rootUri"
|
||||
d["rootUri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["uri"] == "$uri"
|
||||
d["workspaceFolders"][0]["uri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["name"] == "$name"
|
||||
d["workspaceFolders"][0]["name"] = os.path.basename(repository_absolute_path)
|
||||
|
||||
return d
|
||||
|
||||
@asynccontextmanager
|
||||
async def start_server(self) -> AsyncIterator["ClangdLanguageServer"]:
|
||||
"""
|
||||
Starts the Clangd Language Server, waits for the server to be ready and yields the LanguageServer instance.
|
||||
|
||||
Usage:
|
||||
```
|
||||
async with lsp.start_server():
|
||||
# LanguageServer has been initialized and ready to serve requests
|
||||
await lsp.request_definition(...)
|
||||
await lsp.request_references(...)
|
||||
# Shutdown the LanguageServer on exit from scope
|
||||
# LanguageServer has been shutdown
|
||||
"""
|
||||
async def register_capability_handler(params):
|
||||
assert "registrations" in params
|
||||
for registration in params["registrations"]:
|
||||
if registration["method"] == "workspace/executeCommand":
|
||||
self.initialize_searcher_command_available.set()
|
||||
self.resolve_main_method_available.set()
|
||||
return
|
||||
|
||||
async def lang_status_handler(params):
|
||||
# TODO: Should we wait for
|
||||
# server -> client: {'jsonrpc': '2.0', 'method': 'language/status', 'params': {'type': 'ProjectStatus', 'message': 'OK'}}
|
||||
# Before proceeding?
|
||||
if params["type"] == "ServiceReady" and params["message"] == "ServiceReady":
|
||||
self.service_ready_event.set()
|
||||
|
||||
async def execute_client_command_handler(params):
|
||||
return []
|
||||
|
||||
async def do_nothing(params):
|
||||
return
|
||||
|
||||
async def check_experimental_status(params):
|
||||
if params["quiescent"] == True:
|
||||
self.server_ready.set()
|
||||
|
||||
async def window_log_message(msg):
|
||||
self.logger.log(f"LSP: window/logMessage: {msg}", logging.INFO)
|
||||
|
||||
self.server.on_request("client/registerCapability", register_capability_handler)
|
||||
self.server.on_notification("language/status", lang_status_handler)
|
||||
self.server.on_notification("window/logMessage", window_log_message)
|
||||
self.server.on_request("workspace/executeClientCommand", execute_client_command_handler)
|
||||
self.server.on_notification("$/progress", do_nothing)
|
||||
self.server.on_notification("textDocument/publishDiagnostics", do_nothing)
|
||||
self.server.on_notification("language/actionableNotification", do_nothing)
|
||||
self.server.on_notification("experimental/serverStatus", check_experimental_status)
|
||||
|
||||
async with super().start_server():
|
||||
self.logger.log("Starting Clangd server process", logging.INFO)
|
||||
await self.server.start()
|
||||
initialize_params = self._get_initialize_params(self.repository_root_path)
|
||||
|
||||
self.logger.log(
|
||||
"Sending initialize request from LSP client to LSP server and awaiting response",
|
||||
logging.INFO,
|
||||
)
|
||||
init_response = await self.server.send.initialize(initialize_params)
|
||||
assert init_response["capabilities"]["textDocumentSync"]["change"] == 2
|
||||
assert "completionProvider" in init_response["capabilities"]
|
||||
assert init_response["capabilities"]["completionProvider"] == {
|
||||
"triggerCharacters": ['.', '<', '>', ':', '"', '/', '*'],
|
||||
"resolveProvider": False,
|
||||
}
|
||||
|
||||
self.server.notify.initialized({})
|
||||
|
||||
self.completions_available.set()
|
||||
# set ready flag
|
||||
self.server_ready.set()
|
||||
await self.server_ready.wait()
|
||||
|
||||
yield self
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"_description": "The parameters sent by the client when initializing the language server with the \"initialize\" request. More details at https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize",
|
||||
"processId": "os.getpid()",
|
||||
"locale": "en",
|
||||
"rootPath": "$rootPath",
|
||||
"rootUri": "$rootUri",
|
||||
"capabilities": {
|
||||
"textDocument": {
|
||||
"synchronization": {
|
||||
"didSave": true,
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"completion": {
|
||||
"dynamicRegistration": true,
|
||||
"completionItem": {
|
||||
"snippetSupport": true
|
||||
}
|
||||
},
|
||||
"definition": {
|
||||
"dynamicRegistration": true
|
||||
}
|
||||
},
|
||||
"workspace": {
|
||||
"workspaceFolders": true,
|
||||
"didChangeConfiguration": {
|
||||
"dynamicRegistration": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"workspaceFolders": [
|
||||
{
|
||||
"uri": "$uri",
|
||||
"name": "$name"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"_description": "Used to download the runtime dependencies for running Clangd.",
|
||||
"runtimeDependencies": [
|
||||
{
|
||||
"id": "Clangd",
|
||||
"description": "Clangd for Linux (x64)",
|
||||
"url": "https://github.com/clangd/clangd/releases/download/19.1.2/clangd-linux-19.1.2.zip",
|
||||
"platformId": "linux-x64",
|
||||
"archiveType": "zip",
|
||||
"binaryName": "clangd"
|
||||
},
|
||||
{
|
||||
"id": "Clangd",
|
||||
"description": "Clangd for Windows (x64)",
|
||||
"url": "https://github.com/clangd/clangd/releases/download/19.1.2/clangd-windows-19.1.2.zip",
|
||||
"platformId": "windows-x64",
|
||||
"archiveType": "zip",
|
||||
"binaryName": "clangd.exe"
|
||||
},
|
||||
{
|
||||
"id": "Clangd",
|
||||
"description": "Clangd for macOS (Arm64)",
|
||||
"url": "https://github.com/clangd/clangd/releases/download/19.1.2/clangd-mac-19.1.2.zip",
|
||||
"platformId": "osx-arm64",
|
||||
"archiveType": "zip",
|
||||
"binaryName": "clangd"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
from contextlib import asynccontextmanager
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import shutil
|
||||
import stat
|
||||
from typing import AsyncIterator
|
||||
from multilspy.language_server import LanguageServer
|
||||
from multilspy.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
import json
|
||||
from multilspy.multilspy_utils import FileUtils, PlatformUtils
|
||||
|
||||
|
||||
class DartLanguageServer(LanguageServer):
|
||||
"""
|
||||
Provides Dart specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Dart.
|
||||
"""
|
||||
|
||||
def __init__(self, config, logger, repository_root_path):
|
||||
"""
|
||||
Creates a DartServer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
|
||||
executable_path = self.setup_runtime_dependencies(logger)
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=executable_path, cwd=repository_root_path),
|
||||
"dart",
|
||||
)
|
||||
|
||||
def setup_runtime_dependencies(self, logger: "MultilspyLogger") -> str:
|
||||
platform_id = PlatformUtils.get_platform_id()
|
||||
|
||||
with open(os.path.join(os.path.dirname(__file__), "runtime_dependencies.json"), "r") as f:
|
||||
d = json.load(f)
|
||||
del d["_description"]
|
||||
|
||||
runtime_dependencies = d["runtimeDependencies"]
|
||||
runtime_dependencies = [
|
||||
dependency for dependency in runtime_dependencies if dependency["platformId"] == platform_id.value
|
||||
]
|
||||
|
||||
assert len(runtime_dependencies) == 1
|
||||
dependency = runtime_dependencies[0]
|
||||
|
||||
dart_ls_dir = os.path.join(os.path.dirname(__file__), "static", "dart-language-server")
|
||||
dart_executable_path = os.path.join(dart_ls_dir, dependency["binaryName"])
|
||||
|
||||
if not os.path.exists(dart_ls_dir):
|
||||
os.makedirs(dart_ls_dir)
|
||||
FileUtils.download_and_extract_archive(
|
||||
logger, dependency["url"], dart_ls_dir, dependency["archiveType"]
|
||||
)
|
||||
|
||||
|
||||
assert os.path.exists(dart_executable_path)
|
||||
os.chmod(dart_executable_path, stat.S_IEXEC)
|
||||
|
||||
return f"{dart_executable_path} language-server --client-id multilspy.dart --client-version 1.2"
|
||||
|
||||
|
||||
def _get_initialize_params(self, repository_absolute_path: str):
|
||||
"""
|
||||
Returns the initialize params for the Dart Language Server.
|
||||
"""
|
||||
with open(
|
||||
os.path.join(os.path.dirname(__file__), "initialize_params.json"), "r"
|
||||
) as f:
|
||||
d = json.load(f)
|
||||
|
||||
del d["_description"]
|
||||
|
||||
d["processId"] = os.getpid()
|
||||
assert d["rootPath"] == "$rootPath"
|
||||
d["rootPath"] = repository_absolute_path
|
||||
|
||||
assert d["rootUri"] == "$rootUri"
|
||||
d["rootUri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["uri"] == "$uri"
|
||||
d["workspaceFolders"][0]["uri"] = pathlib.Path(
|
||||
repository_absolute_path
|
||||
).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["name"] == "$name"
|
||||
d["workspaceFolders"][0]["name"] = os.path.basename(repository_absolute_path)
|
||||
|
||||
return d
|
||||
|
||||
@asynccontextmanager
|
||||
async def start_server(self) -> AsyncIterator["DartLanguageServer"]:
|
||||
"""
|
||||
Start the language server and yield when the server is ready.
|
||||
"""
|
||||
|
||||
async def execute_client_command_handler(params):
|
||||
return []
|
||||
|
||||
async def do_nothing(params):
|
||||
return
|
||||
|
||||
async def check_experimental_status(params):
|
||||
pass
|
||||
|
||||
async def window_log_message(msg):
|
||||
self.logger.log(f"LSP: window/logMessage: {msg}", logging.INFO)
|
||||
|
||||
self.server.on_request("client/registerCapability", do_nothing)
|
||||
self.server.on_notification("language/status", do_nothing)
|
||||
self.server.on_notification("window/logMessage", window_log_message)
|
||||
self.server.on_request(
|
||||
"workspace/executeClientCommand", execute_client_command_handler
|
||||
)
|
||||
self.server.on_notification("$/progress", do_nothing)
|
||||
self.server.on_notification("textDocument/publishDiagnostics", do_nothing)
|
||||
self.server.on_notification("language/actionableNotification", do_nothing)
|
||||
self.server.on_notification(
|
||||
"experimental/serverStatus", check_experimental_status
|
||||
)
|
||||
|
||||
async with super().start_server():
|
||||
self.logger.log(
|
||||
"Starting dart-language-server server process", logging.INFO
|
||||
)
|
||||
await self.server.start()
|
||||
initialize_params = self._get_initialize_params(self.repository_root_path)
|
||||
self.logger.log(
|
||||
"Sending initialize request to dart-language-server",
|
||||
logging.DEBUG,
|
||||
)
|
||||
init_response = await self.server.send_request(
|
||||
"initialize", initialize_params
|
||||
)
|
||||
self.logger.log(
|
||||
f"Received initialize response from dart-language-server: {init_response}",
|
||||
logging.INFO,
|
||||
)
|
||||
|
||||
self.server.notify.initialized({})
|
||||
|
||||
yield self
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"_description": "This file contains the initialization parameters for the Dart Language Server.",
|
||||
"processId": "$processId",
|
||||
"rootPath": "$rootPath",
|
||||
"rootUri": "$rootUri",
|
||||
"capabilities": {},
|
||||
"initializationOptions": {
|
||||
"onlyAnalyzeProjectsWithOpenFiles": false,
|
||||
"suggestFromUnimportedLibraries": true,
|
||||
"closingLabels": false,
|
||||
"outline": false,
|
||||
"flutterOutline": false,
|
||||
"allowOpenUri": false
|
||||
},
|
||||
"trace": "verbose",
|
||||
"workspaceFolders": [
|
||||
{
|
||||
"uri": "$uri",
|
||||
"name": "$name"
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"_description": "Used to download the runtime dependencies for running Dart Language Server, downloaded from https://dart.dev/get-dart/archive",
|
||||
"runtimeDependencies": [
|
||||
{
|
||||
"id": "DartLanguageServer",
|
||||
"description": "Dart Language Server for Linux (x64)",
|
||||
"url": "https://storage.googleapis.com/dart-archive/channels/stable/release/3.7.1/sdk/dartsdk-linux-x64-release.zip",
|
||||
"platformId": "linux-x64",
|
||||
"archiveType": "zip",
|
||||
"binaryName": "dart-sdk/bin/dart"
|
||||
},
|
||||
{
|
||||
"id": "DartLanguageServer",
|
||||
"description": "Dart Language Server for Windows (x64)",
|
||||
"url": "https://storage.googleapis.com/dart-archive/channels/stable/release/3.7.1/sdk/dartsdk-windows-x64-release.zip",
|
||||
"platformId": "win-x64",
|
||||
"archiveType": "zip",
|
||||
"binaryName": "dart-sdk/bin/dart.exe"
|
||||
},
|
||||
{
|
||||
"id": "DartLanguageServer",
|
||||
"description": "Dart Language Server for Windows (arm64)",
|
||||
"url": "https://storage.googleapis.com/dart-archive/channels/stable/release/3.7.1/sdk/dartsdk-windows-arm64-release.zip",
|
||||
"platformId": "win-arm64",
|
||||
"archiveType": "zip",
|
||||
"binaryName": "dart-sdk/bin/dart.exe"
|
||||
},
|
||||
{
|
||||
"id": "DartLanguageServer",
|
||||
"description": "Dart Language Server for macOS (x64)",
|
||||
"url": "https://storage.googleapis.com/dart-archive/channels/stable/release/3.7.1/sdk/dartsdk-macos-x64-release.zip",
|
||||
"platformId": "osx-x64",
|
||||
"archiveType": "zip",
|
||||
"binaryName": "dart-sdk/bin/dart"
|
||||
},
|
||||
{
|
||||
"id": "DartLanguageServer",
|
||||
"description": "Dart Language Server for macOS (arm64)",
|
||||
"url": "https://storage.googleapis.com/dart-archive/channels/stable/release/3.7.1/sdk/dartsdk-macos-arm64-release.zip",
|
||||
"platformId": "osx-arm64",
|
||||
"archiveType": "zip",
|
||||
"binaryName": "dart-sdk/bin/dart"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,422 @@
|
||||
"""
|
||||
Provides Java specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Java.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import dataclasses
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import shutil
|
||||
import stat
|
||||
import uuid
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import AsyncIterator
|
||||
|
||||
from overrides import override
|
||||
|
||||
from multilspy.multilspy_logger import MultilspyLogger
|
||||
from multilspy.language_server import LanguageServer
|
||||
from multilspy.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from multilspy.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from multilspy.multilspy_config import MultilspyConfig
|
||||
from multilspy.multilspy_settings import MultilspySettings
|
||||
from multilspy.multilspy_utils import FileUtils
|
||||
from multilspy.multilspy_utils import PlatformUtils
|
||||
from pathlib import PurePath
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class RuntimeDependencyPaths:
|
||||
"""
|
||||
Stores the paths to the runtime dependencies of EclipseJDTLS
|
||||
"""
|
||||
|
||||
gradle_path: str
|
||||
lombok_jar_path: str
|
||||
jre_path: str
|
||||
jre_home_path: str
|
||||
jdtls_launcher_jar_path: str
|
||||
jdtls_readonly_config_path: str
|
||||
intellicode_jar_path: str
|
||||
intellisense_members_path: str
|
||||
|
||||
|
||||
class EclipseJDTLS(LanguageServer):
|
||||
"""
|
||||
The EclipseJDTLS class provides a Java specific implementation of the LanguageServer class
|
||||
"""
|
||||
|
||||
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
|
||||
"""
|
||||
Creates a new EclipseJDTLS instance initializing the language server settings appropriately.
|
||||
This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
|
||||
runtime_dependency_paths = self.setupRuntimeDependencies(logger, config)
|
||||
self.runtime_dependency_paths = runtime_dependency_paths
|
||||
|
||||
# ws_dir is the workspace directory for the EclipseJDTLS server
|
||||
ws_dir = str(
|
||||
PurePath(
|
||||
MultilspySettings.get_language_server_directory(),
|
||||
"EclipseJDTLS",
|
||||
"workspaces",
|
||||
uuid.uuid4().hex,
|
||||
)
|
||||
)
|
||||
|
||||
# shared_cache_location is the global cache used by Eclipse JDTLS across all workspaces
|
||||
shared_cache_location = str(
|
||||
PurePath(MultilspySettings.get_global_cache_directory(), "lsp", "EclipseJDTLS", "sharedIndex")
|
||||
)
|
||||
|
||||
jre_path = self.runtime_dependency_paths.jre_path
|
||||
lombok_jar_path = self.runtime_dependency_paths.lombok_jar_path
|
||||
|
||||
jdtls_launcher_jar = self.runtime_dependency_paths.jdtls_launcher_jar_path
|
||||
|
||||
os.makedirs(ws_dir, exist_ok=True)
|
||||
|
||||
data_dir = str(PurePath(ws_dir, "data_dir"))
|
||||
jdtls_config_path = str(PurePath(ws_dir, "config_path"))
|
||||
|
||||
jdtls_readonly_config_path = self.runtime_dependency_paths.jdtls_readonly_config_path
|
||||
|
||||
if not os.path.exists(jdtls_config_path):
|
||||
shutil.copytree(jdtls_readonly_config_path, jdtls_config_path)
|
||||
|
||||
for static_path in [
|
||||
jre_path,
|
||||
lombok_jar_path,
|
||||
jdtls_launcher_jar,
|
||||
jdtls_config_path,
|
||||
jdtls_readonly_config_path,
|
||||
]:
|
||||
assert os.path.exists(static_path), static_path
|
||||
|
||||
# TODO: Add "self.runtime_dependency_paths.jre_home_path"/bin to $PATH as well
|
||||
proc_env = {"syntaxserver": "false", "JAVA_HOME": self.runtime_dependency_paths.jre_home_path}
|
||||
proc_cwd = repository_root_path
|
||||
cmd = " ".join(
|
||||
[
|
||||
jre_path,
|
||||
"--add-modules=ALL-SYSTEM",
|
||||
"--add-opens",
|
||||
"java.base/java.util=ALL-UNNAMED",
|
||||
"--add-opens",
|
||||
"java.base/java.lang=ALL-UNNAMED",
|
||||
"--add-opens",
|
||||
"java.base/sun.nio.fs=ALL-UNNAMED",
|
||||
"-Declipse.application=org.eclipse.jdt.ls.core.id1",
|
||||
"-Dosgi.bundles.defaultStartLevel=4",
|
||||
"-Declipse.product=org.eclipse.jdt.ls.core.product",
|
||||
"-Djava.import.generatesMetadataFilesAtProjectRoot=false",
|
||||
"-Dfile.encoding=utf8",
|
||||
"-noverify",
|
||||
"-XX:+UseParallelGC",
|
||||
"-XX:GCTimeRatio=4",
|
||||
"-XX:AdaptiveSizePolicyWeight=90",
|
||||
"-Dsun.zip.disableMemoryMapping=true",
|
||||
"-Djava.lsp.joinOnCompletion=true",
|
||||
"-Xmx3G",
|
||||
"-Xms100m",
|
||||
"-Xlog:disable",
|
||||
"-Dlog.level=ALL",
|
||||
f'"-javaagent:{lombok_jar_path}"',
|
||||
f'"-Djdt.core.sharedIndexLocation={shared_cache_location}"',
|
||||
"-jar",
|
||||
f'"{jdtls_launcher_jar}"',
|
||||
"-configuration",
|
||||
f'"{jdtls_config_path}"',
|
||||
"-data",
|
||||
f'"{data_dir}"',
|
||||
]
|
||||
)
|
||||
|
||||
self.service_ready_event = asyncio.Event()
|
||||
self.intellicode_enable_command_available = asyncio.Event()
|
||||
self.initialize_searcher_command_available = asyncio.Event()
|
||||
|
||||
super().__init__(config, logger, repository_root_path, ProcessLaunchInfo(cmd, proc_env, proc_cwd), "java")
|
||||
|
||||
@override
|
||||
def is_ignored_dirname(self, dirname: str) -> bool:
|
||||
# Ignore common Java build directories from different build tools:
|
||||
# - Maven: target
|
||||
# - Gradle: build, .gradle
|
||||
# - Eclipse: bin, .settings
|
||||
# - IntelliJ IDEA: out, .idea
|
||||
# - General: classes, dist, lib
|
||||
return super().is_ignored_dirname(dirname) or dirname in [
|
||||
"target", # Maven
|
||||
"build", # Gradle
|
||||
"bin", # Eclipse
|
||||
"out", # IntelliJ IDEA
|
||||
"classes", # General
|
||||
"dist", # General
|
||||
"lib" # General
|
||||
]
|
||||
|
||||
def setupRuntimeDependencies(self, logger: MultilspyLogger, config: MultilspyConfig) -> RuntimeDependencyPaths:
|
||||
"""
|
||||
Setup runtime dependencies for EclipseJDTLS.
|
||||
"""
|
||||
platformId = PlatformUtils.get_platform_id()
|
||||
|
||||
with open(str(PurePath(os.path.dirname(__file__), "runtime_dependencies.json")), "r", encoding="utf-8") as f:
|
||||
runtimeDependencies = json.load(f)
|
||||
del runtimeDependencies["_description"]
|
||||
|
||||
os.makedirs(str(PurePath(os.path.abspath(os.path.dirname(__file__)), "static")), exist_ok=True)
|
||||
|
||||
# assert platformId.value in [
|
||||
# "linux-x64",
|
||||
# "win-x64",
|
||||
# ], "Only linux-x64 platform is supported for in multilspy at the moment"
|
||||
|
||||
gradle_path = str(
|
||||
PurePath(
|
||||
os.path.abspath(os.path.dirname(__file__)),
|
||||
"static/gradle-7.3.3",
|
||||
)
|
||||
)
|
||||
|
||||
if not os.path.exists(gradle_path):
|
||||
FileUtils.download_and_extract_archive(
|
||||
logger,
|
||||
runtimeDependencies["gradle"]["platform-agnostic"]["url"],
|
||||
str(PurePath(gradle_path).parent),
|
||||
runtimeDependencies["gradle"]["platform-agnostic"]["archiveType"],
|
||||
)
|
||||
|
||||
assert os.path.exists(gradle_path)
|
||||
|
||||
dependency = runtimeDependencies["vscode-java"][platformId.value]
|
||||
vscode_java_path = str(
|
||||
PurePath(os.path.abspath(os.path.dirname(__file__)), "static", dependency["relative_extraction_path"])
|
||||
)
|
||||
os.makedirs(vscode_java_path, exist_ok=True)
|
||||
jre_home_path = str(PurePath(vscode_java_path, dependency["jre_home_path"]))
|
||||
jre_path = str(PurePath(vscode_java_path, dependency["jre_path"]))
|
||||
lombok_jar_path = str(PurePath(vscode_java_path, dependency["lombok_jar_path"]))
|
||||
jdtls_launcher_jar_path = str(PurePath(vscode_java_path, dependency["jdtls_launcher_jar_path"]))
|
||||
jdtls_readonly_config_path = str(PurePath(vscode_java_path, dependency["jdtls_readonly_config_path"]))
|
||||
if not all(
|
||||
[
|
||||
os.path.exists(vscode_java_path),
|
||||
os.path.exists(jre_home_path),
|
||||
os.path.exists(jre_path),
|
||||
os.path.exists(lombok_jar_path),
|
||||
os.path.exists(jdtls_launcher_jar_path),
|
||||
os.path.exists(jdtls_readonly_config_path),
|
||||
]
|
||||
):
|
||||
FileUtils.download_and_extract_archive(
|
||||
logger, dependency["url"], vscode_java_path, dependency["archiveType"]
|
||||
)
|
||||
|
||||
os.chmod(jre_path, stat.S_IEXEC)
|
||||
|
||||
assert os.path.exists(vscode_java_path)
|
||||
assert os.path.exists(jre_home_path)
|
||||
assert os.path.exists(jre_path)
|
||||
assert os.path.exists(lombok_jar_path)
|
||||
assert os.path.exists(jdtls_launcher_jar_path)
|
||||
assert os.path.exists(jdtls_readonly_config_path)
|
||||
|
||||
dependency = runtimeDependencies["intellicode"]["platform-agnostic"]
|
||||
intellicode_directory_path = str(
|
||||
PurePath(os.path.abspath(os.path.dirname(__file__)), "static", dependency["relative_extraction_path"])
|
||||
)
|
||||
os.makedirs(intellicode_directory_path, exist_ok=True)
|
||||
intellicode_jar_path = str(PurePath(intellicode_directory_path, dependency["intellicode_jar_path"]))
|
||||
intellisense_members_path = str(PurePath(intellicode_directory_path, dependency["intellisense_members_path"]))
|
||||
if not all(
|
||||
[
|
||||
os.path.exists(intellicode_directory_path),
|
||||
os.path.exists(intellicode_jar_path),
|
||||
os.path.exists(intellisense_members_path),
|
||||
]
|
||||
):
|
||||
FileUtils.download_and_extract_archive(
|
||||
logger, dependency["url"], intellicode_directory_path, dependency["archiveType"]
|
||||
)
|
||||
|
||||
assert os.path.exists(intellicode_directory_path)
|
||||
assert os.path.exists(intellicode_jar_path)
|
||||
assert os.path.exists(intellisense_members_path)
|
||||
|
||||
return RuntimeDependencyPaths(
|
||||
gradle_path=gradle_path,
|
||||
lombok_jar_path=lombok_jar_path,
|
||||
jre_path=jre_path,
|
||||
jre_home_path=jre_home_path,
|
||||
jdtls_launcher_jar_path=jdtls_launcher_jar_path,
|
||||
jdtls_readonly_config_path=jdtls_readonly_config_path,
|
||||
intellicode_jar_path=intellicode_jar_path,
|
||||
intellisense_members_path=intellisense_members_path,
|
||||
)
|
||||
|
||||
def _get_initialize_params(self, repository_absolute_path: str) -> InitializeParams:
|
||||
"""
|
||||
Returns the initialize parameters for the EclipseJDTLS server.
|
||||
"""
|
||||
# Look into https://github.com/eclipse/eclipse.jdt.ls/blob/master/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java to understand all the options available
|
||||
with open(str(PurePath(os.path.dirname(__file__), "initialize_params.json")), "r", encoding="utf-8") as f:
|
||||
d: InitializeParams = json.load(f)
|
||||
|
||||
del d["_description"]
|
||||
|
||||
if not os.path.isabs(repository_absolute_path):
|
||||
repository_absolute_path = os.path.abspath(repository_absolute_path)
|
||||
|
||||
assert d["processId"] == "os.getpid()"
|
||||
d["processId"] = os.getpid()
|
||||
|
||||
assert d["rootPath"] == "repository_absolute_path"
|
||||
d["rootPath"] = repository_absolute_path
|
||||
|
||||
assert d["rootUri"] == "pathlib.Path(repository_absolute_path).as_uri()"
|
||||
d["rootUri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["initializationOptions"]["workspaceFolders"] == "[pathlib.Path(repository_absolute_path).as_uri()]"
|
||||
d["initializationOptions"]["workspaceFolders"] = [pathlib.Path(repository_absolute_path).as_uri()]
|
||||
|
||||
assert (
|
||||
d["workspaceFolders"]
|
||||
== '[\n {\n "uri": pathlib.Path(repository_absolute_path).as_uri(),\n "name": os.path.basename(repository_absolute_path),\n }\n ]'
|
||||
)
|
||||
d["workspaceFolders"] = [
|
||||
{
|
||||
"uri": pathlib.Path(repository_absolute_path).as_uri(),
|
||||
"name": os.path.basename(repository_absolute_path),
|
||||
}
|
||||
]
|
||||
|
||||
assert d["initializationOptions"]["bundles"] == ["intellicode-core.jar"]
|
||||
bundles = [self.runtime_dependency_paths.intellicode_jar_path]
|
||||
d["initializationOptions"]["bundles"] = bundles
|
||||
|
||||
assert d["initializationOptions"]["settings"]["java"]["configuration"]["runtimes"] == [
|
||||
{"name": "JavaSE-21", "path": "static/vscode-java/extension/jre/21.0.7-linux-x86_64", "default": True}
|
||||
]
|
||||
d["initializationOptions"]["settings"]["java"]["configuration"]["runtimes"] = [
|
||||
{"name": "JavaSE-21", "path": self.runtime_dependency_paths.jre_home_path, "default": True}
|
||||
]
|
||||
|
||||
for runtime in d["initializationOptions"]["settings"]["java"]["configuration"]["runtimes"]:
|
||||
assert "name" in runtime
|
||||
assert "path" in runtime
|
||||
assert os.path.exists(
|
||||
runtime["path"]
|
||||
), f"Runtime required for eclipse_jdtls at path {runtime['path']} does not exist"
|
||||
|
||||
assert d["initializationOptions"]["settings"]["java"]["import"]["gradle"]["home"] == "abs(static/gradle-7.3.3)"
|
||||
d["initializationOptions"]["settings"]["java"]["import"]["gradle"][
|
||||
"home"
|
||||
] = self.runtime_dependency_paths.gradle_path
|
||||
|
||||
d["initializationOptions"]["settings"]["java"]["import"]["gradle"]["java"][
|
||||
"home"
|
||||
] = self.runtime_dependency_paths.jre_path
|
||||
|
||||
return d
|
||||
|
||||
@asynccontextmanager
|
||||
async def start_server(self) -> AsyncIterator["EclipseJDTLS"]:
|
||||
"""
|
||||
Starts the Eclipse JDTLS Language Server, waits for the server to be ready and yields the LanguageServer instance.
|
||||
|
||||
Usage:
|
||||
```
|
||||
async with lsp.start_server():
|
||||
# LanguageServer has been initialized and ready to serve requests
|
||||
await lsp.request_definition(...)
|
||||
await lsp.request_references(...)
|
||||
# Shutdown the LanguageServer on exit from scope
|
||||
# LanguageServer has been shutdown
|
||||
```
|
||||
"""
|
||||
|
||||
async def register_capability_handler(params):
|
||||
assert "registrations" in params
|
||||
for registration in params["registrations"]:
|
||||
if registration["method"] == "textDocument/completion":
|
||||
assert registration["registerOptions"]["resolveProvider"] == True
|
||||
assert registration["registerOptions"]["triggerCharacters"] == [
|
||||
".",
|
||||
"@",
|
||||
"#",
|
||||
"*",
|
||||
" ",
|
||||
]
|
||||
self.completions_available.set()
|
||||
if registration["method"] == "workspace/executeCommand":
|
||||
if "java.intellicode.enable" in registration["registerOptions"]["commands"]:
|
||||
self.intellicode_enable_command_available.set()
|
||||
return
|
||||
|
||||
async def lang_status_handler(params):
|
||||
# TODO: Should we wait for
|
||||
# server -> client: {'jsonrpc': '2.0', 'method': 'language/status', 'params': {'type': 'ProjectStatus', 'message': 'OK'}}
|
||||
# Before proceeding?
|
||||
if params["type"] == "ServiceReady" and params["message"] == "ServiceReady":
|
||||
self.service_ready_event.set()
|
||||
|
||||
async def execute_client_command_handler(params):
|
||||
assert params["command"] == "_java.reloadBundles.command"
|
||||
assert params["arguments"] == []
|
||||
return []
|
||||
|
||||
async def window_log_message(msg):
|
||||
self.logger.log(f"LSP: window/logMessage: {msg}", logging.INFO)
|
||||
|
||||
async def do_nothing(params):
|
||||
return
|
||||
|
||||
self.server.on_request("client/registerCapability", register_capability_handler)
|
||||
self.server.on_notification("language/status", lang_status_handler)
|
||||
self.server.on_notification("window/logMessage", window_log_message)
|
||||
self.server.on_request("workspace/executeClientCommand", execute_client_command_handler)
|
||||
self.server.on_notification("$/progress", do_nothing)
|
||||
self.server.on_notification("textDocument/publishDiagnostics", do_nothing)
|
||||
self.server.on_notification("language/actionableNotification", do_nothing)
|
||||
|
||||
async with super().start_server():
|
||||
self.logger.log("Starting EclipseJDTLS server process", logging.INFO)
|
||||
await self.server.start()
|
||||
initialize_params = self._get_initialize_params(self.repository_root_path)
|
||||
|
||||
self.logger.log(
|
||||
"Sending initialize request from LSP client to LSP server and awaiting response",
|
||||
logging.INFO,
|
||||
)
|
||||
init_response = await self.server.send.initialize(initialize_params)
|
||||
assert init_response["capabilities"]["textDocumentSync"]["change"] == 2
|
||||
assert "completionProvider" not in init_response["capabilities"]
|
||||
assert "executeCommandProvider" not in init_response["capabilities"]
|
||||
|
||||
self.server.notify.initialized({})
|
||||
|
||||
self.server.notify.workspace_did_change_configuration(
|
||||
{"settings": initialize_params["initializationOptions"]["settings"]}
|
||||
)
|
||||
|
||||
await self.intellicode_enable_command_available.wait()
|
||||
|
||||
java_intellisense_members_path = self.runtime_dependency_paths.intellisense_members_path
|
||||
assert os.path.exists(java_intellisense_members_path)
|
||||
intellicode_enable_result = await self.server.send.execute_command(
|
||||
{
|
||||
"command": "java.intellicode.enable",
|
||||
"arguments": [True, java_intellisense_members_path],
|
||||
}
|
||||
)
|
||||
assert intellicode_enable_result
|
||||
|
||||
# TODO: Add comments about why we wait here, and how this can be optimized
|
||||
await self.service_ready_event.wait()
|
||||
|
||||
yield self
|
||||
@@ -0,0 +1,849 @@
|
||||
{
|
||||
"_description": "The parameters sent by the client when initializing the language server with the \"initialize\" request. More details at https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize",
|
||||
"processId": "os.getpid()",
|
||||
"clientInfo": {
|
||||
"name": "Visual Studio Code - Insiders",
|
||||
"version": "1.77.0-insider"
|
||||
},
|
||||
"locale": "en",
|
||||
"rootPath": "repository_absolute_path",
|
||||
"rootUri": "pathlib.Path(repository_absolute_path).as_uri()",
|
||||
"capabilities": {
|
||||
"workspace": {
|
||||
"applyEdit": true,
|
||||
"workspaceEdit": {
|
||||
"documentChanges": true,
|
||||
"resourceOperations": [
|
||||
"create",
|
||||
"rename",
|
||||
"delete"
|
||||
],
|
||||
"failureHandling": "textOnlyTransactional",
|
||||
"normalizesLineEndings": true,
|
||||
"changeAnnotationSupport": {
|
||||
"groupsOnLabel": true
|
||||
}
|
||||
},
|
||||
"didChangeConfiguration": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"didChangeWatchedFiles": {
|
||||
"dynamicRegistration": true,
|
||||
"relativePatternSupport": true
|
||||
},
|
||||
"symbol": {
|
||||
"dynamicRegistration": true,
|
||||
"symbolKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26
|
||||
]
|
||||
},
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"location.range"
|
||||
]
|
||||
}
|
||||
},
|
||||
"codeLens": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"executeCommand": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"configuration": true,
|
||||
"workspaceFolders": true,
|
||||
"semanticTokens": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"fileOperations": {
|
||||
"dynamicRegistration": true,
|
||||
"didCreate": true,
|
||||
"didRename": true,
|
||||
"didDelete": true,
|
||||
"willCreate": true,
|
||||
"willRename": true,
|
||||
"willDelete": true
|
||||
},
|
||||
"inlineValue": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"inlayHint": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"diagnostics": {
|
||||
"refreshSupport": true
|
||||
}
|
||||
},
|
||||
"textDocument": {
|
||||
"publishDiagnostics": {
|
||||
"relatedInformation": true,
|
||||
"versionSupport": false,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2
|
||||
]
|
||||
},
|
||||
"codeDescriptionSupport": true,
|
||||
"dataSupport": true
|
||||
},
|
||||
"synchronization": {
|
||||
"dynamicRegistration": true,
|
||||
"willSave": true,
|
||||
"willSaveWaitUntil": true,
|
||||
"didSave": true
|
||||
},
|
||||
"completion": {
|
||||
"dynamicRegistration": true,
|
||||
"contextSupport": true,
|
||||
"completionItem": {
|
||||
"snippetSupport": false,
|
||||
"commitCharactersSupport": true,
|
||||
"documentationFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
],
|
||||
"deprecatedSupport": true,
|
||||
"preselectSupport": true,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"insertReplaceSupport": false,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"documentation",
|
||||
"detail",
|
||||
"additionalTextEdits"
|
||||
]
|
||||
},
|
||||
"insertTextModeSupport": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2
|
||||
]
|
||||
},
|
||||
"labelDetailsSupport": true
|
||||
},
|
||||
"insertTextMode": 2,
|
||||
"completionItemKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25
|
||||
]
|
||||
},
|
||||
"completionList": {
|
||||
"itemDefaults": [
|
||||
"commitCharacters",
|
||||
"editRange",
|
||||
"insertTextFormat",
|
||||
"insertTextMode"
|
||||
]
|
||||
}
|
||||
},
|
||||
"hover": {
|
||||
"dynamicRegistration": true,
|
||||
"contentFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
]
|
||||
},
|
||||
"signatureHelp": {
|
||||
"dynamicRegistration": true,
|
||||
"signatureInformation": {
|
||||
"documentationFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
],
|
||||
"parameterInformation": {
|
||||
"labelOffsetSupport": true
|
||||
},
|
||||
"activeParameterSupport": true
|
||||
},
|
||||
"contextSupport": true
|
||||
},
|
||||
"definition": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"references": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"documentHighlight": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"documentSymbol": {
|
||||
"dynamicRegistration": true,
|
||||
"symbolKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26
|
||||
]
|
||||
},
|
||||
"hierarchicalDocumentSymbolSupport": true,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"labelSupport": true
|
||||
},
|
||||
"codeAction": {
|
||||
"dynamicRegistration": true,
|
||||
"isPreferredSupport": true,
|
||||
"disabledSupport": true,
|
||||
"dataSupport": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"edit"
|
||||
]
|
||||
},
|
||||
"codeActionLiteralSupport": {
|
||||
"codeActionKind": {
|
||||
"valueSet": [
|
||||
"",
|
||||
"quickfix",
|
||||
"refactor",
|
||||
"refactor.extract",
|
||||
"refactor.inline",
|
||||
"refactor.rewrite",
|
||||
"source",
|
||||
"source.organizeImports"
|
||||
]
|
||||
}
|
||||
},
|
||||
"honorsChangeAnnotations": false
|
||||
},
|
||||
"codeLens": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"formatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"rangeFormatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"onTypeFormatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"rename": {
|
||||
"dynamicRegistration": true,
|
||||
"prepareSupport": true,
|
||||
"prepareSupportDefaultBehavior": 1,
|
||||
"honorsChangeAnnotations": true
|
||||
},
|
||||
"documentLink": {
|
||||
"dynamicRegistration": true,
|
||||
"tooltipSupport": true
|
||||
},
|
||||
"typeDefinition": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"implementation": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"colorProvider": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"foldingRange": {
|
||||
"dynamicRegistration": true,
|
||||
"rangeLimit": 5000,
|
||||
"lineFoldingOnly": true,
|
||||
"foldingRangeKind": {
|
||||
"valueSet": [
|
||||
"comment",
|
||||
"imports",
|
||||
"region"
|
||||
]
|
||||
},
|
||||
"foldingRange": {
|
||||
"collapsedText": false
|
||||
}
|
||||
},
|
||||
"declaration": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"selectionRange": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"callHierarchy": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"semanticTokens": {
|
||||
"dynamicRegistration": true,
|
||||
"tokenTypes": [
|
||||
"namespace",
|
||||
"type",
|
||||
"class",
|
||||
"enum",
|
||||
"interface",
|
||||
"struct",
|
||||
"typeParameter",
|
||||
"parameter",
|
||||
"variable",
|
||||
"property",
|
||||
"enumMember",
|
||||
"event",
|
||||
"function",
|
||||
"method",
|
||||
"macro",
|
||||
"keyword",
|
||||
"modifier",
|
||||
"comment",
|
||||
"string",
|
||||
"number",
|
||||
"regexp",
|
||||
"operator",
|
||||
"decorator"
|
||||
],
|
||||
"tokenModifiers": [
|
||||
"declaration",
|
||||
"definition",
|
||||
"readonly",
|
||||
"static",
|
||||
"deprecated",
|
||||
"abstract",
|
||||
"async",
|
||||
"modification",
|
||||
"documentation",
|
||||
"defaultLibrary"
|
||||
],
|
||||
"formats": [
|
||||
"relative"
|
||||
],
|
||||
"requests": {
|
||||
"range": true,
|
||||
"full": {
|
||||
"delta": true
|
||||
}
|
||||
},
|
||||
"multilineTokenSupport": false,
|
||||
"overlappingTokenSupport": false,
|
||||
"serverCancelSupport": true,
|
||||
"augmentsSyntaxTokens": true
|
||||
},
|
||||
"linkedEditingRange": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"typeHierarchy": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"inlineValue": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"inlayHint": {
|
||||
"dynamicRegistration": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"tooltip",
|
||||
"textEdits",
|
||||
"label.tooltip",
|
||||
"label.location",
|
||||
"label.command"
|
||||
]
|
||||
}
|
||||
},
|
||||
"diagnostic": {
|
||||
"dynamicRegistration": true,
|
||||
"relatedDocumentSupport": false
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
"showMessage": {
|
||||
"messageActionItem": {
|
||||
"additionalPropertiesSupport": true
|
||||
}
|
||||
},
|
||||
"showDocument": {
|
||||
"support": true
|
||||
},
|
||||
"workDoneProgress": true
|
||||
},
|
||||
"general": {
|
||||
"staleRequestSupport": {
|
||||
"cancel": true,
|
||||
"retryOnContentModified": [
|
||||
"textDocument/semanticTokens/full",
|
||||
"textDocument/semanticTokens/range",
|
||||
"textDocument/semanticTokens/full/delta"
|
||||
]
|
||||
},
|
||||
"regularExpressions": {
|
||||
"engine": "ECMAScript",
|
||||
"version": "ES2020"
|
||||
},
|
||||
"markdown": {
|
||||
"parser": "marked",
|
||||
"version": "1.1.0"
|
||||
},
|
||||
"positionEncodings": [
|
||||
"utf-16"
|
||||
]
|
||||
},
|
||||
"notebookDocument": {
|
||||
"synchronization": {
|
||||
"dynamicRegistration": true,
|
||||
"executionSummarySupport": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"initializationOptions": {
|
||||
"bundles": [
|
||||
"intellicode-core.jar"
|
||||
],
|
||||
"workspaceFolders": "[pathlib.Path(repository_absolute_path).as_uri()]",
|
||||
"settings": {
|
||||
"java": {
|
||||
"home": null,
|
||||
"jdt": {
|
||||
"ls": {
|
||||
"java": {
|
||||
"home": null
|
||||
},
|
||||
"vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx1G -Xms100m -Xlog:disable",
|
||||
"lombokSupport": {
|
||||
"enabled": true
|
||||
},
|
||||
"protobufSupport": {
|
||||
"enabled": true
|
||||
},
|
||||
"androidSupport": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
"incompleteClasspath": {
|
||||
"severity": "error"
|
||||
}
|
||||
},
|
||||
"configuration": {
|
||||
"checkProjectSettingsExclusions": false,
|
||||
"updateBuildConfiguration": "interactive",
|
||||
"maven": {
|
||||
"userSettings": null,
|
||||
"globalSettings": null,
|
||||
"notCoveredPluginExecutionSeverity": "warning",
|
||||
"defaultMojoExecutionAction": "ignore"
|
||||
},
|
||||
"workspaceCacheLimit": 90,
|
||||
"runtimes": [
|
||||
{
|
||||
"name": "JavaSE-21",
|
||||
"path": "static/vscode-java/extension/jre/21.0.7-linux-x86_64",
|
||||
"default": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"trace": {
|
||||
"server": "verbose"
|
||||
},
|
||||
"import": {
|
||||
"maven": {
|
||||
"enabled": true,
|
||||
"offline": {
|
||||
"enabled": false
|
||||
},
|
||||
"disableTestClasspathFlag": false
|
||||
},
|
||||
"gradle": {
|
||||
"enabled": true,
|
||||
"wrapper": {
|
||||
"enabled": true
|
||||
},
|
||||
"version": null,
|
||||
"home": "abs(static/gradle-7.3.3)",
|
||||
"java": {
|
||||
"home": "abs(static/launch_jres/21.0.7-linux-x86_64)"
|
||||
},
|
||||
"offline": {
|
||||
"enabled": false
|
||||
},
|
||||
"arguments": null,
|
||||
"jvmArguments": null,
|
||||
"user": {
|
||||
"home": null
|
||||
},
|
||||
"annotationProcessing": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"exclusions": [
|
||||
"**/node_modules/**",
|
||||
"**/.metadata/**",
|
||||
"**/archetype-resources/**",
|
||||
"**/META-INF/maven/**"
|
||||
],
|
||||
"generatesMetadataFilesAtProjectRoot": false
|
||||
},
|
||||
"maven": {
|
||||
"downloadSources": true,
|
||||
"updateSnapshots": true
|
||||
},
|
||||
"eclipse": {
|
||||
"downloadSources": true
|
||||
},
|
||||
"referencesCodeLens": {
|
||||
"enabled": true
|
||||
},
|
||||
"signatureHelp": {
|
||||
"enabled": true,
|
||||
"description": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"implementationsCodeLens": {
|
||||
"enabled": true
|
||||
},
|
||||
"format": {
|
||||
"enabled": true,
|
||||
"settings": {
|
||||
"url": null,
|
||||
"profile": null
|
||||
},
|
||||
"comments": {
|
||||
"enabled": true
|
||||
},
|
||||
"onType": {
|
||||
"enabled": true
|
||||
},
|
||||
"insertSpaces": true,
|
||||
"tabSize": 4
|
||||
},
|
||||
"saveActions": {
|
||||
"organizeImports": false
|
||||
},
|
||||
"project": {
|
||||
"referencedLibraries": [
|
||||
"lib/**/*.jar"
|
||||
],
|
||||
"importOnFirstTimeStartup": "automatic",
|
||||
"importHint": true,
|
||||
"resourceFilters": [
|
||||
"node_modules",
|
||||
"\\.git"
|
||||
],
|
||||
"encoding": "ignore",
|
||||
"exportJar": {
|
||||
"targetPath": "${workspaceFolder}/${workspaceFolderBasename}.jar"
|
||||
}
|
||||
},
|
||||
"contentProvider": {
|
||||
"preferred": null
|
||||
},
|
||||
"autobuild": {
|
||||
"enabled": true
|
||||
},
|
||||
"maxConcurrentBuilds": 1,
|
||||
"recommendations": {
|
||||
"dependency": {
|
||||
"analytics": {
|
||||
"show": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"completion": {
|
||||
"maxResults": 0,
|
||||
"enabled": true,
|
||||
"guessMethodArguments": true,
|
||||
"favoriteStaticMembers": [
|
||||
"org.junit.Assert.*",
|
||||
"org.junit.Assume.*",
|
||||
"org.junit.jupiter.api.Assertions.*",
|
||||
"org.junit.jupiter.api.Assumptions.*",
|
||||
"org.junit.jupiter.api.DynamicContainer.*",
|
||||
"org.junit.jupiter.api.DynamicTest.*",
|
||||
"org.mockito.Mockito.*",
|
||||
"org.mockito.ArgumentMatchers.*",
|
||||
"org.mockito.Answers.*"
|
||||
],
|
||||
"filteredTypes": [
|
||||
"java.awt.*",
|
||||
"com.sun.*",
|
||||
"sun.*",
|
||||
"jdk.*",
|
||||
"org.graalvm.*",
|
||||
"io.micrometer.shaded.*"
|
||||
],
|
||||
"importOrder": [
|
||||
"#",
|
||||
"java",
|
||||
"javax",
|
||||
"org",
|
||||
"com",
|
||||
""
|
||||
],
|
||||
"postfix": {
|
||||
"enabled": false
|
||||
},
|
||||
"matchCase": "off"
|
||||
},
|
||||
"foldingRange": {
|
||||
"enabled": true
|
||||
},
|
||||
"progressReports": {
|
||||
"enabled": false
|
||||
},
|
||||
"codeGeneration": {
|
||||
"hashCodeEquals": {
|
||||
"useJava7Objects": false,
|
||||
"useInstanceof": false
|
||||
},
|
||||
"useBlocks": false,
|
||||
"generateComments": false,
|
||||
"toString": {
|
||||
"template": "${object.className} [${member.name()}=${member.value}, ${otherMembers}]",
|
||||
"codeStyle": "STRING_CONCATENATION",
|
||||
"skipNullValues": false,
|
||||
"listArrayContents": true,
|
||||
"limitElements": 0
|
||||
},
|
||||
"insertionLocation": "afterCursor"
|
||||
},
|
||||
"selectionRange": {
|
||||
"enabled": true
|
||||
},
|
||||
"showBuildStatusOnStart": {
|
||||
"enabled": "notification"
|
||||
},
|
||||
"server": {
|
||||
"launchMode": "Standard"
|
||||
},
|
||||
"sources": {
|
||||
"organizeImports": {
|
||||
"starThreshold": 99,
|
||||
"staticStarThreshold": 99
|
||||
}
|
||||
},
|
||||
"imports": {
|
||||
"gradle": {
|
||||
"wrapper": {
|
||||
"checksums": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"templates": {
|
||||
"fileHeader": [],
|
||||
"typeComment": []
|
||||
},
|
||||
"references": {
|
||||
"includeAccessors": true,
|
||||
"includeDecompiledSources": true
|
||||
},
|
||||
"typeHierarchy": {
|
||||
"lazyLoad": false
|
||||
},
|
||||
"settings": {
|
||||
"url": null
|
||||
},
|
||||
"symbols": {
|
||||
"includeSourceMethodDeclarations": false
|
||||
},
|
||||
"quickfix": {
|
||||
"showAt": "line"
|
||||
},
|
||||
"inlayHints": {
|
||||
"parameterNames": {
|
||||
"enabled": "literals",
|
||||
"exclusions": []
|
||||
}
|
||||
},
|
||||
"codeAction": {
|
||||
"sortMembers": {
|
||||
"avoidVolatileChanges": true
|
||||
}
|
||||
},
|
||||
"compile": {
|
||||
"nullAnalysis": {
|
||||
"nonnull": [
|
||||
"javax.annotation.Nonnull",
|
||||
"org.eclipse.jdt.annotation.NonNull",
|
||||
"org.springframework.lang.NonNull"
|
||||
],
|
||||
"nullable": [
|
||||
"javax.annotation.Nullable",
|
||||
"org.eclipse.jdt.annotation.Nullable",
|
||||
"org.springframework.lang.Nullable"
|
||||
],
|
||||
"mode": "automatic"
|
||||
}
|
||||
},
|
||||
"cleanup": {
|
||||
"actionsOnSave": []
|
||||
},
|
||||
"sharedIndexes": {
|
||||
"enabled": "auto",
|
||||
"location": ""
|
||||
},
|
||||
"refactoring": {
|
||||
"extract": {
|
||||
"interface": {
|
||||
"replace": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"logLevel": "verbose",
|
||||
"settings": {
|
||||
"showHex": false,
|
||||
"showStaticVariables": false,
|
||||
"showQualifiedNames": false,
|
||||
"showLogicalStructure": true,
|
||||
"showToString": true,
|
||||
"maxStringLength": 0,
|
||||
"numericPrecision": 0,
|
||||
"hotCodeReplace": "manual",
|
||||
"enableRunDebugCodeLens": true,
|
||||
"forceBuildBeforeLaunch": true,
|
||||
"onBuildFailureProceed": false,
|
||||
"console": "integratedTerminal",
|
||||
"exceptionBreakpoint": {
|
||||
"skipClasses": []
|
||||
},
|
||||
"stepping": {
|
||||
"skipClasses": [],
|
||||
"skipSynthetics": false,
|
||||
"skipStaticInitializers": false,
|
||||
"skipConstructors": false
|
||||
},
|
||||
"jdwp": {
|
||||
"limitOfVariablesPerJdwpRequest": 100,
|
||||
"requestTimeout": 3000,
|
||||
"async": "auto"
|
||||
},
|
||||
"vmArgs": ""
|
||||
}
|
||||
},
|
||||
"silentNotification": false,
|
||||
"dependency": {
|
||||
"showMembers": false,
|
||||
"syncWithFolderExplorer": true,
|
||||
"autoRefresh": true,
|
||||
"refreshDelay": 2000,
|
||||
"packagePresentation": "flat"
|
||||
},
|
||||
"help": {
|
||||
"firstView": "auto",
|
||||
"showReleaseNotes": true,
|
||||
"collectErrorLog": false
|
||||
},
|
||||
"test": {
|
||||
"defaultConfig": "",
|
||||
"config": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"extendedClientCapabilities": {
|
||||
"progressReportProvider": false,
|
||||
"classFileContentsSupport": true,
|
||||
"overrideMethodsPromptSupport": true,
|
||||
"hashCodeEqualsPromptSupport": true,
|
||||
"advancedOrganizeImportsSupport": true,
|
||||
"generateToStringPromptSupport": true,
|
||||
"advancedGenerateAccessorsSupport": true,
|
||||
"generateConstructorsPromptSupport": true,
|
||||
"generateDelegateMethodsPromptSupport": true,
|
||||
"advancedExtractRefactoringSupport": true,
|
||||
"inferSelectionSupport": [
|
||||
"extractMethod",
|
||||
"extractVariable",
|
||||
"extractField"
|
||||
],
|
||||
"moveRefactoringSupport": true,
|
||||
"clientHoverProvider": true,
|
||||
"clientDocumentSymbolProvider": true,
|
||||
"gradleChecksumWrapperPromptSupport": true,
|
||||
"resolveAdditionalTextEditsSupport": true,
|
||||
"advancedIntroduceParameterRefactoringSupport": true,
|
||||
"actionableRuntimeNotificationSupport": true,
|
||||
"shouldLanguageServerExitOnShutdown": true,
|
||||
"onCompletionItemSelectedCommand": "editor.action.triggerParameterHints",
|
||||
"extractInterfaceSupport": true,
|
||||
"advancedUpgradeGradleSupport": true
|
||||
},
|
||||
"triggerFiles": []
|
||||
},
|
||||
"trace": "verbose",
|
||||
"workspaceFolders": "[\n {\n \"uri\": pathlib.Path(repository_absolute_path).as_uri(),\n \"name\": os.path.basename(repository_absolute_path),\n }\n ]"
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"_description": "This file lists the runtime dependencies for the Java Language Server",
|
||||
"gradle": {
|
||||
"platform-agnostic": {
|
||||
"url": "https://services.gradle.org/distributions/gradle-7.3.3-bin.zip",
|
||||
"archiveType": "zip",
|
||||
"relative_extraction_path": "."
|
||||
}
|
||||
},
|
||||
"vscode-java": {
|
||||
"darwin-arm64": {
|
||||
"url": "https://github.com/redhat-developer/vscode-java/releases/download/v1.42.0/java-darwin-arm64-1.42.0-561.vsix",
|
||||
"archiveType": "zip",
|
||||
"relative_extraction_path": "vscode-java"
|
||||
},
|
||||
"osx-arm64": {
|
||||
"url": "https://github.com/redhat-developer/vscode-java/releases/download/v1.42.0/java-darwin-arm64-1.42.0-561.vsix",
|
||||
"archiveType": "zip",
|
||||
"relative_extraction_path": "vscode-java",
|
||||
"jre_home_path": "extension/jre/21.0.7-macosx-aarch64",
|
||||
"jre_path": "extension/jre/21.0.7-macosx-aarch64/bin/java",
|
||||
"lombok_jar_path": "extension/lombok/lombok-1.18.36.jar",
|
||||
"jdtls_launcher_jar_path": "extension/server/plugins/org.eclipse.equinox.launcher_1.7.0.v20250424-1814.jar",
|
||||
"jdtls_readonly_config_path": "extension/server/config_mac_arm"
|
||||
},
|
||||
"osx-x64": {
|
||||
"url": "https://github.com/redhat-developer/vscode-java/releases/download/v1.42.0/java-darwin-x64-1.42.0-561.vsix",
|
||||
"archiveType": "zip",
|
||||
"relative_extraction_path": "vscode-java",
|
||||
"jre_home_path": "extension/jre/21.0.7-macosx-x86_64",
|
||||
"jre_path": "extension/jre/21.0.7-macosx-x86_64/bin/java",
|
||||
"lombok_jar_path": "extension/lombok/lombok-1.18.36.jar",
|
||||
"jdtls_launcher_jar_path": "extension/server/plugins/org.eclipse.equinox.launcher_1.7.0.v20250424-1814.jar",
|
||||
"jdtls_readonly_config_path": "extension/server/config_mac"
|
||||
},
|
||||
"linux-arm64": {
|
||||
"url": "https://github.com/redhat-developer/vscode-java/releases/download/v1.42.0/java-linux-arm64-1.42.0-561.vsix",
|
||||
"archiveType": "zip",
|
||||
"relative_extraction_path": "vscode-java"
|
||||
},
|
||||
"linux-x64": {
|
||||
"url": "https://github.com/redhat-developer/vscode-java/releases/download/v1.42.0/java-linux-x64-1.42.0-561.vsix",
|
||||
"archiveType": "zip",
|
||||
"relative_extraction_path": "vscode-java",
|
||||
"jre_home_path": "extension/jre/21.0.7-linux-x86_64",
|
||||
"jre_path": "extension/jre/21.0.7-linux-x86_64/bin/java",
|
||||
"lombok_jar_path": "extension/lombok/lombok-1.18.36.jar",
|
||||
"jdtls_launcher_jar_path": "extension/server/plugins/org.eclipse.equinox.launcher_1.7.0.v20250424-1814.jar",
|
||||
"jdtls_readonly_config_path": "extension/server/config_linux"
|
||||
},
|
||||
"win-x64": {
|
||||
"url": "https://github.com/redhat-developer/vscode-java/releases/download/v1.42.0/java-win32-x64-1.42.0-561.vsix",
|
||||
"archiveType": "zip",
|
||||
"relative_extraction_path": "vscode-java",
|
||||
"jre_home_path": "extension/jre/21.0.7-win32-x86_64",
|
||||
"jre_path": "extension/jre/21.0.7-win32-x86_64/bin/java.exe",
|
||||
"lombok_jar_path": "extension/lombok/lombok-1.18.36.jar",
|
||||
"jdtls_launcher_jar_path": "extension/server/plugins/org.eclipse.equinox.launcher_1.7.0.v20250424-1814.jar",
|
||||
"jdtls_readonly_config_path": "extension/server/config_win"
|
||||
}
|
||||
},
|
||||
"intellicode": {
|
||||
"platform-agnostic": {
|
||||
"url": "https://VisualStudioExptTeam.gallery.vsassets.io/_apis/public/gallery/publisher/VisualStudioExptTeam/extension/vscodeintellicode/1.2.30/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage",
|
||||
"alternate_url": "https://marketplace.visualstudio.com/_apis/public/gallery/publishers/VisualStudioExptTeam/vsextensions/vscodeintellicode/1.2.30/vspackage",
|
||||
"archiveType": "zip",
|
||||
"relative_extraction_path": "intellicode",
|
||||
"intellicode_jar_path": "extension/dist/com.microsoft.jdtls.intellicode.core-0.7.0.jar",
|
||||
"intellisense_members_path": "extension/dist/bundledModels/java_intellisense-members"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import subprocess
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import AsyncIterator, List
|
||||
|
||||
from overrides import override
|
||||
|
||||
from multilspy import multilspy_types
|
||||
from multilspy.lsp_protocol_handler import lsp_types
|
||||
from multilspy.multilspy_exceptions import MultilspyException
|
||||
from multilspy.multilspy_logger import MultilspyLogger
|
||||
from multilspy.language_server import LanguageServer
|
||||
from multilspy.lsp_protocol_handler.server import Error, ProcessLaunchInfo
|
||||
from multilspy.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from multilspy.multilspy_config import MultilspyConfig
|
||||
|
||||
|
||||
class Gopls(LanguageServer):
|
||||
"""
|
||||
Provides Go specific instantiation of the LanguageServer class using gopls.
|
||||
"""
|
||||
|
||||
@override
|
||||
def is_ignored_dirname(self, dirname: str) -> bool:
|
||||
# For Go projects, we should ignore:
|
||||
# - vendor: third-party dependencies vendored into the project
|
||||
# - node_modules: if the project has JavaScript components
|
||||
# - dist/build: common output directories
|
||||
return super().is_ignored_dirname(dirname) or dirname in ["vendor", "node_modules", "dist", "build"]
|
||||
|
||||
@staticmethod
|
||||
def _get_go_version():
|
||||
"""Get the installed Go version or None if not found."""
|
||||
try:
|
||||
result = subprocess.run(['go', 'version'], capture_output=True, text=True)
|
||||
if result.returncode == 0:
|
||||
return result.stdout.strip()
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _get_gopls_version():
|
||||
"""Get the installed gopls version or None if not found."""
|
||||
try:
|
||||
result = subprocess.run(['gopls', 'version'], capture_output=True, text=True)
|
||||
if result.returncode == 0:
|
||||
return result.stdout.strip()
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def setup_runtime_dependency(cls):
|
||||
"""
|
||||
Check if required Go runtime dependencies are available.
|
||||
Raises RuntimeError with helpful message if dependencies are missing.
|
||||
"""
|
||||
go_version = cls._get_go_version()
|
||||
if not go_version:
|
||||
raise RuntimeError("Go is not installed. Please install Go from https://golang.org/doc/install and make sure it is added to your PATH.")
|
||||
|
||||
gopls_version = cls._get_gopls_version()
|
||||
if not gopls_version:
|
||||
raise RuntimeError(
|
||||
"Found a Go version but gopls is not installed.\n"
|
||||
"Please install gopls as described in https://pkg.go.dev/golang.org/x/tools/gopls#section-readme\n\n"
|
||||
"After installation, make sure it is added to your PATH (it might be installed in a different location than Go)."
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
|
||||
self.setup_runtime_dependency()
|
||||
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd="gopls", cwd=repository_root_path),
|
||||
"go",
|
||||
)
|
||||
self.server_ready = asyncio.Event()
|
||||
self.request_id = 0
|
||||
|
||||
def _get_initialize_params(self, repository_absolute_path: str) -> InitializeParams:
|
||||
"""
|
||||
Returns the initialize params for the TypeScript Language Server.
|
||||
"""
|
||||
with open(os.path.join(os.path.dirname(__file__), "initialize_params.json"), "r", encoding="utf-8") as f:
|
||||
d = json.load(f)
|
||||
|
||||
del d["_description"]
|
||||
|
||||
d["processId"] = os.getpid()
|
||||
assert d["rootPath"] == "$rootPath"
|
||||
d["rootPath"] = repository_absolute_path
|
||||
|
||||
assert d["rootUri"] == "$rootUri"
|
||||
d["rootUri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["uri"] == "$uri"
|
||||
d["workspaceFolders"][0]["uri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["name"] == "$name"
|
||||
d["workspaceFolders"][0]["name"] = os.path.basename(repository_absolute_path)
|
||||
|
||||
return d
|
||||
|
||||
@asynccontextmanager
|
||||
async def start_server(self) -> AsyncIterator["Gopls"]:
|
||||
"""Start gopls server process"""
|
||||
async def register_capability_handler(params):
|
||||
return
|
||||
|
||||
async def window_log_message(msg):
|
||||
self.logger.log(f"LSP: window/logMessage: {msg}", logging.INFO)
|
||||
|
||||
async def do_nothing(params):
|
||||
return
|
||||
|
||||
self.server.on_request("client/registerCapability", register_capability_handler)
|
||||
self.server.on_notification("window/logMessage", window_log_message)
|
||||
self.server.on_notification("$/progress", do_nothing)
|
||||
self.server.on_notification("textDocument/publishDiagnostics", do_nothing)
|
||||
|
||||
async with super().start_server():
|
||||
self.logger.log("Starting gopls server process", logging.INFO)
|
||||
await self.server.start()
|
||||
initialize_params = self._get_initialize_params(self.repository_root_path)
|
||||
|
||||
self.logger.log(
|
||||
"Sending initialize request from LSP client to LSP server and awaiting response",
|
||||
logging.INFO,
|
||||
)
|
||||
init_response = await self.server.send.initialize(initialize_params)
|
||||
|
||||
# Verify server capabilities
|
||||
assert "textDocumentSync" in init_response["capabilities"]
|
||||
assert "completionProvider" in init_response["capabilities"]
|
||||
assert "definitionProvider" in init_response["capabilities"]
|
||||
|
||||
self.server.notify.initialized({})
|
||||
self.completions_available.set()
|
||||
|
||||
# gopls server is typically ready immediately after initialization
|
||||
self.server_ready.set()
|
||||
await self.server_ready.wait()
|
||||
|
||||
yield self
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"_description": "The parameters sent by the client when initializing the language server with the \"initialize\" request. More details at https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize",
|
||||
"processId": "os.getpid()",
|
||||
"locale": "en",
|
||||
"rootPath": "$rootPath",
|
||||
"rootUri": "$rootUri",
|
||||
"capabilities": {
|
||||
"textDocument": {
|
||||
"synchronization": {
|
||||
"didSave": true,
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"completion": {
|
||||
"dynamicRegistration": true,
|
||||
"completionItem": {
|
||||
"snippetSupport": true
|
||||
}
|
||||
},
|
||||
"definition": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"documentSymbol": {
|
||||
"dynamicRegistration": true,
|
||||
"hierarchicalDocumentSymbolSupport": true,
|
||||
"symbolKind": {
|
||||
"valueSet": [
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"workspace": {
|
||||
"workspaceFolders": true,
|
||||
"didChangeConfiguration": {
|
||||
"dynamicRegistration": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"workspaceFolders": [
|
||||
{
|
||||
"uri": "$uri",
|
||||
"name": "$name"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"_description": "The parameters sent by the client when initializing the language server with the \"initialize\" request. More details at https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize",
|
||||
"processId": "os.getpid()",
|
||||
"locale": "en",
|
||||
"rootPath": "$rootPath",
|
||||
"rootUri": "$rootUri",
|
||||
"capabilities": {
|
||||
"textDocument": {
|
||||
"synchronization": {
|
||||
"didSave": true,
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"completion": {
|
||||
"dynamicRegistration": true,
|
||||
"completionItem": {
|
||||
"snippetSupport": true
|
||||
}
|
||||
},
|
||||
"definition": {
|
||||
"dynamicRegistration": true
|
||||
}
|
||||
},
|
||||
"workspace": {
|
||||
"workspaceFolders": true,
|
||||
"didChangeConfiguration": {
|
||||
"dynamicRegistration": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"workspaceFolders": [
|
||||
{
|
||||
"uri": "$uri",
|
||||
"name": "$name"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
"""
|
||||
Provides PHP specific instantiation of the LanguageServer class using Intelephense.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import shutil
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import pathlib
|
||||
from contextlib import asynccontextmanager
|
||||
from time import sleep
|
||||
from typing import AsyncIterator
|
||||
|
||||
from overrides import override
|
||||
|
||||
from multilspy.multilspy_logger import MultilspyLogger
|
||||
from multilspy.language_server import LanguageServer
|
||||
from multilspy.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from multilspy.lsp_protocol_handler.lsp_types import DefinitionParams, InitializeParams
|
||||
from multilspy.multilspy_config import MultilspyConfig
|
||||
from multilspy.multilspy_utils import PlatformUtils, PlatformId
|
||||
|
||||
class Intelephense(LanguageServer):
|
||||
"""
|
||||
Provides PHP specific instantiation of the LanguageServer class using Intelephense.
|
||||
"""
|
||||
|
||||
@override
|
||||
def is_ignored_dirname(self, dirname: str) -> bool:
|
||||
# For PHP projects, we should ignore:
|
||||
# - vendor: third-party dependencies managed by Composer
|
||||
# - node_modules: if the project has JavaScript components
|
||||
# - cache: commonly used for caching
|
||||
return super().is_ignored_dirname(dirname) or dirname in ["node_modules", "vendor", "cache"]
|
||||
|
||||
def setup_runtime_dependencies(self, logger: MultilspyLogger, config: MultilspyConfig) -> str:
|
||||
"""
|
||||
Setup runtime dependencies for Intelephense.
|
||||
"""
|
||||
platform_id = PlatformUtils.get_platform_id()
|
||||
|
||||
valid_platforms = [
|
||||
PlatformId.LINUX_x64,
|
||||
PlatformId.LINUX_arm64,
|
||||
PlatformId.OSX,
|
||||
PlatformId.OSX_x64,
|
||||
PlatformId.OSX_arm64,
|
||||
PlatformId.WIN_x64,
|
||||
PlatformId.WIN_arm64,
|
||||
]
|
||||
assert platform_id in valid_platforms, f"Platform {platform_id} is not supported for multilspy PHP at the moment"
|
||||
|
||||
with open(os.path.join(os.path.dirname(__file__), "runtime_dependencies.json"), "r", encoding="utf-8") as f:
|
||||
d = json.load(f)
|
||||
del d["_description"]
|
||||
|
||||
runtime_dependencies = d.get("runtimeDependencies", [])
|
||||
intelephense_ls_dir = os.path.join(os.path.dirname(__file__), "static", "php-lsp")
|
||||
|
||||
# Verify both node and npm are installed
|
||||
is_node_installed = shutil.which('node') is not None
|
||||
assert is_node_installed, "node is not installed or isn't in PATH. Please install NodeJS and try again."
|
||||
is_npm_installed = shutil.which('npm') is not None
|
||||
assert is_npm_installed, "npm is not installed or isn't in PATH. Please install npm and try again."
|
||||
|
||||
# Install intelephense if not already installed
|
||||
if not os.path.exists(intelephense_ls_dir):
|
||||
os.makedirs(intelephense_ls_dir, exist_ok=True)
|
||||
for dependency in runtime_dependencies:
|
||||
# Windows doesn't support the 'user' parameter and doesn't have pwd module
|
||||
if PlatformUtils.get_platform_id().value.startswith("win"):
|
||||
subprocess.run(
|
||||
dependency["command"],
|
||||
shell=True,
|
||||
check=True,
|
||||
cwd=intelephense_ls_dir,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL
|
||||
)
|
||||
else:
|
||||
# On Unix-like systems, run as non-root user
|
||||
import pwd
|
||||
user = pwd.getpwuid(os.getuid()).pw_name
|
||||
subprocess.run(
|
||||
dependency["command"],
|
||||
shell=True,
|
||||
check=True,
|
||||
user=user,
|
||||
cwd=intelephense_ls_dir,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL
|
||||
)
|
||||
|
||||
intelephense_executable_path = os.path.join(intelephense_ls_dir, "node_modules", ".bin", "intelephense")
|
||||
assert os.path.exists(intelephense_executable_path), "intelephense executable not found. Please install intelephense and try again."
|
||||
|
||||
return f"{intelephense_executable_path} --stdio"
|
||||
|
||||
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
|
||||
# Setup runtime dependencies before initializing
|
||||
intelephense_cmd = self.setup_runtime_dependencies(logger, config)
|
||||
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=intelephense_cmd, cwd=repository_root_path),
|
||||
"php"
|
||||
)
|
||||
self.server_ready = asyncio.Event()
|
||||
self.request_id = 0
|
||||
|
||||
def _get_initialize_params(self, repository_absolute_path: str) -> InitializeParams:
|
||||
"""
|
||||
Returns the initialize params for the TypeScript Language Server.
|
||||
"""
|
||||
with open(os.path.join(os.path.dirname(__file__), "initialize_params.json"), "r", encoding="utf-8") as f:
|
||||
d = json.load(f)
|
||||
|
||||
del d["_description"]
|
||||
|
||||
d["processId"] = os.getpid()
|
||||
assert d["rootPath"] == "$rootPath"
|
||||
d["rootPath"] = repository_absolute_path
|
||||
|
||||
assert d["rootUri"] == "$rootUri"
|
||||
d["rootUri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["uri"] == "$uri"
|
||||
d["workspaceFolders"][0]["uri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["name"] == "$name"
|
||||
d["workspaceFolders"][0]["name"] = os.path.basename(repository_absolute_path)
|
||||
|
||||
return d
|
||||
|
||||
@asynccontextmanager
|
||||
async def start_server(self) -> AsyncIterator["Intelephense"]:
|
||||
"""Start Intelephense server process"""
|
||||
async def register_capability_handler(params):
|
||||
return
|
||||
|
||||
async def window_log_message(msg):
|
||||
self.logger.log(f"LSP: window/logMessage: {msg}", logging.INFO)
|
||||
|
||||
async def do_nothing(params):
|
||||
return
|
||||
|
||||
self.server.on_request("client/registerCapability", register_capability_handler)
|
||||
self.server.on_notification("window/logMessage", window_log_message)
|
||||
self.server.on_notification("$/progress", do_nothing)
|
||||
self.server.on_notification("textDocument/publishDiagnostics", do_nothing)
|
||||
|
||||
async with super().start_server():
|
||||
self.logger.log("Starting Intelephense server process", logging.INFO)
|
||||
await self.server.start()
|
||||
initialize_params = self._get_initialize_params(self.repository_root_path)
|
||||
|
||||
self.logger.log(
|
||||
"Sending initialize request from LSP client to LSP server and awaiting response",
|
||||
logging.INFO,
|
||||
)
|
||||
init_response = await self.server.send.initialize(initialize_params)
|
||||
self.logger.log(
|
||||
"After sent initialize params",
|
||||
logging.INFO,
|
||||
)
|
||||
|
||||
# Verify server capabilities
|
||||
assert "textDocumentSync" in init_response["capabilities"]
|
||||
assert "completionProvider" in init_response["capabilities"]
|
||||
assert "definitionProvider" in init_response["capabilities"]
|
||||
|
||||
self.server.notify.initialized({})
|
||||
self.completions_available.set()
|
||||
|
||||
# Intelephense server is typically ready immediately after initialization
|
||||
self.server_ready.set()
|
||||
await self.server_ready.wait()
|
||||
|
||||
yield self
|
||||
|
||||
@override
|
||||
# For some reason, the LS may need longer to process this, so we just retry
|
||||
async def _send_references_request(self, relative_file_path: str, line: int, column: int):
|
||||
# TODO: The LS doesn't return references contained in other files if it doesn't sleep. This is
|
||||
# despite the LS having processed requests already. I don't know what causes this, but sleeping
|
||||
# one second helps. It may be that sleeping only once is enough but that's hard to reliably test.
|
||||
# May be related to the time it takes to read the files or something like that.
|
||||
# The sleeping doesn't seem to be needed on all systems
|
||||
sleep(1)
|
||||
return await super()._send_references_request(relative_file_path, line, column)
|
||||
|
||||
@override
|
||||
async def _send_definition_request(self, definition_params: DefinitionParams):
|
||||
# TODO: same as above, also only a problem if the definition is in another file
|
||||
sleep(1)
|
||||
return await super()._send_definition_request(definition_params)
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"_description": "Used to download the runtime dependencies for running intelephense. Obtained from https://www.npmjs.com/package/intelephense",
|
||||
"runtimeDependencies": [
|
||||
{
|
||||
"id": "intelephense",
|
||||
"description": "Intelephense package for Linux, OSX, and Windows. Both x64 and arm64 are supported.",
|
||||
"command": "npm install --prefix ./ intelephense@1.14.4"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,905 @@
|
||||
{
|
||||
"_description": "The parameters sent by the client when initializing the language server with the \"initialize\" request. More details at https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize",
|
||||
"processId": "os.getpid()",
|
||||
"clientInfo": {
|
||||
"name": "Visual Studio Code - Insiders",
|
||||
"version": "1.81.0-insider"
|
||||
},
|
||||
"locale": "en",
|
||||
"rootPath": "$rootPath",
|
||||
"rootUri": "$rootUri",
|
||||
"capabilities": {
|
||||
"workspace": {
|
||||
"applyEdit": true,
|
||||
"workspaceEdit": {
|
||||
"documentChanges": true,
|
||||
"resourceOperations": [
|
||||
"create",
|
||||
"rename",
|
||||
"delete"
|
||||
],
|
||||
"failureHandling": "textOnlyTransactional",
|
||||
"normalizesLineEndings": true,
|
||||
"changeAnnotationSupport": {
|
||||
"groupsOnLabel": true
|
||||
}
|
||||
},
|
||||
"configuration": true,
|
||||
"didChangeWatchedFiles": {
|
||||
"dynamicRegistration": true,
|
||||
"relativePatternSupport": true
|
||||
},
|
||||
"symbol": {
|
||||
"dynamicRegistration": true,
|
||||
"symbolKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26
|
||||
]
|
||||
},
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"location.range"
|
||||
]
|
||||
}
|
||||
},
|
||||
"codeLens": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"executeCommand": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"didChangeConfiguration": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"workspaceFolders": true,
|
||||
"semanticTokens": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"fileOperations": {
|
||||
"dynamicRegistration": true,
|
||||
"didCreate": true,
|
||||
"didRename": true,
|
||||
"didDelete": true,
|
||||
"willCreate": true,
|
||||
"willRename": true,
|
||||
"willDelete": true
|
||||
},
|
||||
"inlineValue": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"inlayHint": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"diagnostics": {
|
||||
"refreshSupport": true
|
||||
}
|
||||
},
|
||||
"textDocument": {
|
||||
"publishDiagnostics": {
|
||||
"relatedInformation": true,
|
||||
"versionSupport": false,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2
|
||||
]
|
||||
},
|
||||
"codeDescriptionSupport": true,
|
||||
"dataSupport": true
|
||||
},
|
||||
"synchronization": {
|
||||
"dynamicRegistration": true,
|
||||
"willSave": true,
|
||||
"willSaveWaitUntil": true,
|
||||
"didSave": true
|
||||
},
|
||||
"completion": {
|
||||
"dynamicRegistration": true,
|
||||
"contextSupport": true,
|
||||
"completionItem": {
|
||||
"snippetSupport": true,
|
||||
"commitCharactersSupport": true,
|
||||
"documentationFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
],
|
||||
"deprecatedSupport": true,
|
||||
"preselectSupport": true,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"insertReplaceSupport": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"documentation",
|
||||
"detail",
|
||||
"additionalTextEdits"
|
||||
]
|
||||
},
|
||||
"insertTextModeSupport": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2
|
||||
]
|
||||
},
|
||||
"labelDetailsSupport": true
|
||||
},
|
||||
"insertTextMode": 2,
|
||||
"completionItemKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25
|
||||
]
|
||||
},
|
||||
"completionList": {
|
||||
"itemDefaults": [
|
||||
"commitCharacters",
|
||||
"editRange",
|
||||
"insertTextFormat",
|
||||
"insertTextMode"
|
||||
]
|
||||
}
|
||||
},
|
||||
"hover": {
|
||||
"dynamicRegistration": true,
|
||||
"contentFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
]
|
||||
},
|
||||
"signatureHelp": {
|
||||
"dynamicRegistration": true,
|
||||
"signatureInformation": {
|
||||
"documentationFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
],
|
||||
"parameterInformation": {
|
||||
"labelOffsetSupport": true
|
||||
},
|
||||
"activeParameterSupport": true
|
||||
},
|
||||
"contextSupport": true
|
||||
},
|
||||
"definition": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"references": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"documentHighlight": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"documentSymbol": {
|
||||
"dynamicRegistration": true,
|
||||
"symbolKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26
|
||||
]
|
||||
},
|
||||
"hierarchicalDocumentSymbolSupport": true,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"labelSupport": true
|
||||
},
|
||||
"codeAction": {
|
||||
"dynamicRegistration": true,
|
||||
"isPreferredSupport": true,
|
||||
"disabledSupport": true,
|
||||
"dataSupport": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"edit"
|
||||
]
|
||||
},
|
||||
"codeActionLiteralSupport": {
|
||||
"codeActionKind": {
|
||||
"valueSet": [
|
||||
"",
|
||||
"quickfix",
|
||||
"refactor",
|
||||
"refactor.extract",
|
||||
"refactor.inline",
|
||||
"refactor.rewrite",
|
||||
"source",
|
||||
"source.organizeImports"
|
||||
]
|
||||
}
|
||||
},
|
||||
"honorsChangeAnnotations": false
|
||||
},
|
||||
"codeLens": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"formatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"rangeFormatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"onTypeFormatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"rename": {
|
||||
"dynamicRegistration": true,
|
||||
"prepareSupport": true,
|
||||
"prepareSupportDefaultBehavior": 1,
|
||||
"honorsChangeAnnotations": true
|
||||
},
|
||||
"documentLink": {
|
||||
"dynamicRegistration": true,
|
||||
"tooltipSupport": true
|
||||
},
|
||||
"typeDefinition": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"implementation": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"colorProvider": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"foldingRange": {
|
||||
"dynamicRegistration": true,
|
||||
"rangeLimit": 5000,
|
||||
"lineFoldingOnly": true,
|
||||
"foldingRangeKind": {
|
||||
"valueSet": [
|
||||
"comment",
|
||||
"imports",
|
||||
"region"
|
||||
]
|
||||
},
|
||||
"foldingRange": {
|
||||
"collapsedText": false
|
||||
}
|
||||
},
|
||||
"declaration": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"selectionRange": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"callHierarchy": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"semanticTokens": {
|
||||
"dynamicRegistration": true,
|
||||
"tokenTypes": [
|
||||
"namespace",
|
||||
"type",
|
||||
"class",
|
||||
"enum",
|
||||
"interface",
|
||||
"struct",
|
||||
"typeParameter",
|
||||
"parameter",
|
||||
"variable",
|
||||
"property",
|
||||
"enumMember",
|
||||
"event",
|
||||
"function",
|
||||
"method",
|
||||
"macro",
|
||||
"keyword",
|
||||
"modifier",
|
||||
"comment",
|
||||
"string",
|
||||
"number",
|
||||
"regexp",
|
||||
"operator",
|
||||
"decorator"
|
||||
],
|
||||
"tokenModifiers": [
|
||||
"declaration",
|
||||
"definition",
|
||||
"readonly",
|
||||
"static",
|
||||
"deprecated",
|
||||
"abstract",
|
||||
"async",
|
||||
"modification",
|
||||
"documentation",
|
||||
"defaultLibrary"
|
||||
],
|
||||
"formats": [
|
||||
"relative"
|
||||
],
|
||||
"requests": {
|
||||
"range": true,
|
||||
"full": {
|
||||
"delta": true
|
||||
}
|
||||
},
|
||||
"multilineTokenSupport": false,
|
||||
"overlappingTokenSupport": false,
|
||||
"serverCancelSupport": true,
|
||||
"augmentsSyntaxTokens": false
|
||||
},
|
||||
"linkedEditingRange": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"typeHierarchy": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"inlineValue": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"inlayHint": {
|
||||
"dynamicRegistration": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"tooltip",
|
||||
"textEdits",
|
||||
"label.tooltip",
|
||||
"label.location",
|
||||
"label.command"
|
||||
]
|
||||
}
|
||||
},
|
||||
"diagnostic": {
|
||||
"dynamicRegistration": true,
|
||||
"relatedDocumentSupport": false
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
"showMessage": {
|
||||
"messageActionItem": {
|
||||
"additionalPropertiesSupport": true
|
||||
}
|
||||
},
|
||||
"showDocument": {
|
||||
"support": true
|
||||
},
|
||||
"workDoneProgress": true
|
||||
},
|
||||
"general": {
|
||||
"staleRequestSupport": {
|
||||
"cancel": true,
|
||||
"retryOnContentModified": [
|
||||
"textDocument/semanticTokens/full",
|
||||
"textDocument/semanticTokens/range",
|
||||
"textDocument/semanticTokens/full/delta"
|
||||
]
|
||||
},
|
||||
"regularExpressions": {
|
||||
"engine": "ECMAScript",
|
||||
"version": "ES2020"
|
||||
},
|
||||
"markdown": {
|
||||
"parser": "marked",
|
||||
"version": "1.1.0",
|
||||
"allowedTags": [
|
||||
"ul",
|
||||
"li",
|
||||
"p",
|
||||
"code",
|
||||
"blockquote",
|
||||
"ol",
|
||||
"h1",
|
||||
"h2",
|
||||
"h3",
|
||||
"h4",
|
||||
"h5",
|
||||
"h6",
|
||||
"hr",
|
||||
"em",
|
||||
"pre",
|
||||
"table",
|
||||
"thead",
|
||||
"tbody",
|
||||
"tr",
|
||||
"th",
|
||||
"td",
|
||||
"div",
|
||||
"del",
|
||||
"a",
|
||||
"strong",
|
||||
"br",
|
||||
"img",
|
||||
"span"
|
||||
]
|
||||
},
|
||||
"positionEncodings": [
|
||||
"utf-16"
|
||||
]
|
||||
},
|
||||
"notebookDocument": {
|
||||
"synchronization": {
|
||||
"dynamicRegistration": true,
|
||||
"executionSummarySupport": true
|
||||
}
|
||||
},
|
||||
"experimental": {
|
||||
"snippetTextEdit": true,
|
||||
"codeActionGroup": true,
|
||||
"hoverActions": true,
|
||||
"serverStatusNotification": true,
|
||||
"colorDiagnosticOutput": true,
|
||||
"openServerLogs": true,
|
||||
"commands": {
|
||||
"commands": [
|
||||
"rust-analyzer.runSingle",
|
||||
"rust-analyzer.debugSingle",
|
||||
"rust-analyzer.showReferences",
|
||||
"rust-analyzer.gotoLocation",
|
||||
"editor.action.triggerParameterHints"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"initializationOptions": {
|
||||
"cargoRunner": null,
|
||||
"runnables": {
|
||||
"extraEnv": null,
|
||||
"problemMatcher": [
|
||||
"$rustc"
|
||||
],
|
||||
"command": null,
|
||||
"extraArgs": []
|
||||
},
|
||||
"server": {
|
||||
"path": null,
|
||||
"extraEnv": null
|
||||
},
|
||||
"trace": {
|
||||
"server": "verbose",
|
||||
"extension": true
|
||||
},
|
||||
"debug": {
|
||||
"engine": "auto",
|
||||
"sourceFileMap": {
|
||||
"/rustc/<id>": "${env:USERPROFILE}/.rustup/toolchains/<toolchain-id>/lib/rustlib/src/rust"
|
||||
},
|
||||
"openDebugPane": false,
|
||||
"engineSettings": {}
|
||||
},
|
||||
"restartServerOnConfigChange": false,
|
||||
"typing": {
|
||||
"continueCommentsOnNewline": true,
|
||||
"autoClosingAngleBrackets": {
|
||||
"enable": false
|
||||
}
|
||||
},
|
||||
"diagnostics": {
|
||||
"previewRustcOutput": false,
|
||||
"useRustcErrorCode": false,
|
||||
"disabled": [],
|
||||
"enable": true,
|
||||
"experimental": {
|
||||
"enable": false
|
||||
},
|
||||
"remapPrefix": {},
|
||||
"warningsAsHint": [],
|
||||
"warningsAsInfo": []
|
||||
},
|
||||
"discoverProjectCommand": null,
|
||||
"showUnlinkedFileNotification": true,
|
||||
"showDependenciesExplorer": true,
|
||||
"assist": {
|
||||
"emitMustUse": false,
|
||||
"expressionFillDefault": "todo"
|
||||
},
|
||||
"cachePriming": {
|
||||
"enable": true,
|
||||
"numThreads": 0
|
||||
},
|
||||
"cargo": {
|
||||
"autoreload": true,
|
||||
"buildScripts": {
|
||||
"enable": true,
|
||||
"invocationLocation": "workspace",
|
||||
"invocationStrategy": "per_workspace",
|
||||
"overrideCommand": null,
|
||||
"useRustcWrapper": true
|
||||
},
|
||||
"cfgs": {},
|
||||
"extraArgs": [],
|
||||
"extraEnv": {},
|
||||
"features": [],
|
||||
"noDefaultFeatures": false,
|
||||
"sysroot": "discover",
|
||||
"sysrootSrc": null,
|
||||
"target": null,
|
||||
"unsetTest": [
|
||||
"core"
|
||||
]
|
||||
},
|
||||
"checkOnSave": true,
|
||||
"check": {
|
||||
"allTargets": true,
|
||||
"command": "check",
|
||||
"extraArgs": [],
|
||||
"extraEnv": {},
|
||||
"features": null,
|
||||
"invocationLocation": "workspace",
|
||||
"invocationStrategy": "per_workspace",
|
||||
"noDefaultFeatures": null,
|
||||
"overrideCommand": null,
|
||||
"targets": null
|
||||
},
|
||||
"completion": {
|
||||
"autoimport": {
|
||||
"enable": true
|
||||
},
|
||||
"autoself": {
|
||||
"enable": true
|
||||
},
|
||||
"callable": {
|
||||
"snippets": "fill_arguments"
|
||||
},
|
||||
"limit": null,
|
||||
"postfix": {
|
||||
"enable": true
|
||||
},
|
||||
"privateEditable": {
|
||||
"enable": false
|
||||
},
|
||||
"snippets": {
|
||||
"custom": {
|
||||
"Arc::new": {
|
||||
"postfix": "arc",
|
||||
"body": "Arc::new(${receiver})",
|
||||
"requires": "std::sync::Arc",
|
||||
"description": "Put the expression into an `Arc`",
|
||||
"scope": "expr"
|
||||
},
|
||||
"Rc::new": {
|
||||
"postfix": "rc",
|
||||
"body": "Rc::new(${receiver})",
|
||||
"requires": "std::rc::Rc",
|
||||
"description": "Put the expression into an `Rc`",
|
||||
"scope": "expr"
|
||||
},
|
||||
"Box::pin": {
|
||||
"postfix": "pinbox",
|
||||
"body": "Box::pin(${receiver})",
|
||||
"requires": "std::boxed::Box",
|
||||
"description": "Put the expression into a pinned `Box`",
|
||||
"scope": "expr"
|
||||
},
|
||||
"Ok": {
|
||||
"postfix": "ok",
|
||||
"body": "Ok(${receiver})",
|
||||
"description": "Wrap the expression in a `Result::Ok`",
|
||||
"scope": "expr"
|
||||
},
|
||||
"Err": {
|
||||
"postfix": "err",
|
||||
"body": "Err(${receiver})",
|
||||
"description": "Wrap the expression in a `Result::Err`",
|
||||
"scope": "expr"
|
||||
},
|
||||
"Some": {
|
||||
"postfix": "some",
|
||||
"body": "Some(${receiver})",
|
||||
"description": "Wrap the expression in an `Option::Some`",
|
||||
"scope": "expr"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"excludeDirs": [],
|
||||
"watcher": "client"
|
||||
},
|
||||
"highlightRelated": {
|
||||
"breakPoints": {
|
||||
"enable": true
|
||||
},
|
||||
"closureCaptures": {
|
||||
"enable": true
|
||||
},
|
||||
"exitPoints": {
|
||||
"enable": true
|
||||
},
|
||||
"references": {
|
||||
"enable": true
|
||||
},
|
||||
"yieldPoints": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"hover": {
|
||||
"actions": {
|
||||
"debug": {
|
||||
"enable": true
|
||||
},
|
||||
"enable": true,
|
||||
"gotoTypeDef": {
|
||||
"enable": true
|
||||
},
|
||||
"implementations": {
|
||||
"enable": true
|
||||
},
|
||||
"references": {
|
||||
"enable": false
|
||||
},
|
||||
"run": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"documentation": {
|
||||
"enable": true,
|
||||
"keywords": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"enable": true
|
||||
},
|
||||
"memoryLayout": {
|
||||
"alignment": "hexadecimal",
|
||||
"enable": true,
|
||||
"niches": false,
|
||||
"offset": "hexadecimal",
|
||||
"size": "both"
|
||||
}
|
||||
},
|
||||
"imports": {
|
||||
"granularity": {
|
||||
"enforce": false,
|
||||
"group": "crate"
|
||||
},
|
||||
"group": {
|
||||
"enable": true
|
||||
},
|
||||
"merge": {
|
||||
"glob": true
|
||||
},
|
||||
"prefer": {
|
||||
"no": {
|
||||
"std": false
|
||||
}
|
||||
},
|
||||
"prefix": "plain"
|
||||
},
|
||||
"inlayHints": {
|
||||
"bindingModeHints": {
|
||||
"enable": false
|
||||
},
|
||||
"chainingHints": {
|
||||
"enable": true
|
||||
},
|
||||
"closingBraceHints": {
|
||||
"enable": true,
|
||||
"minLines": 25
|
||||
},
|
||||
"closureCaptureHints": {
|
||||
"enable": false
|
||||
},
|
||||
"closureReturnTypeHints": {
|
||||
"enable": "never"
|
||||
},
|
||||
"closureStyle": "impl_fn",
|
||||
"discriminantHints": {
|
||||
"enable": "never"
|
||||
},
|
||||
"expressionAdjustmentHints": {
|
||||
"enable": "never",
|
||||
"hideOutsideUnsafe": false,
|
||||
"mode": "prefix"
|
||||
},
|
||||
"lifetimeElisionHints": {
|
||||
"enable": "never",
|
||||
"useParameterNames": false
|
||||
},
|
||||
"maxLength": 25,
|
||||
"parameterHints": {
|
||||
"enable": true
|
||||
},
|
||||
"reborrowHints": {
|
||||
"enable": "never"
|
||||
},
|
||||
"renderColons": true,
|
||||
"typeHints": {
|
||||
"enable": true,
|
||||
"hideClosureInitialization": false,
|
||||
"hideNamedConstructor": false
|
||||
}
|
||||
},
|
||||
"interpret": {
|
||||
"tests": false
|
||||
},
|
||||
"joinLines": {
|
||||
"joinAssignments": true,
|
||||
"joinElseIf": true,
|
||||
"removeTrailingComma": true,
|
||||
"unwrapTrivialBlock": true
|
||||
},
|
||||
"lens": {
|
||||
"debug": {
|
||||
"enable": true
|
||||
},
|
||||
"enable": true,
|
||||
"forceCustomCommands": true,
|
||||
"implementations": {
|
||||
"enable": true
|
||||
},
|
||||
"location": "above_name",
|
||||
"references": {
|
||||
"adt": {
|
||||
"enable": false
|
||||
},
|
||||
"enumVariant": {
|
||||
"enable": false
|
||||
},
|
||||
"method": {
|
||||
"enable": false
|
||||
},
|
||||
"trait": {
|
||||
"enable": false
|
||||
}
|
||||
},
|
||||
"run": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"linkedProjects": [],
|
||||
"lru": {
|
||||
"capacity": null,
|
||||
"query": {
|
||||
"capacities": {}
|
||||
}
|
||||
},
|
||||
"notifications": {
|
||||
"cargoTomlNotFound": true
|
||||
},
|
||||
"numThreads": null,
|
||||
"procMacro": {
|
||||
"attributes": {
|
||||
"enable": true
|
||||
},
|
||||
"enable": true,
|
||||
"ignored": {},
|
||||
"server": null
|
||||
},
|
||||
"references": {
|
||||
"excludeImports": false
|
||||
},
|
||||
"rustc": {
|
||||
"source": null
|
||||
},
|
||||
"rustfmt": {
|
||||
"extraArgs": [],
|
||||
"overrideCommand": null,
|
||||
"rangeFormatting": {
|
||||
"enable": false
|
||||
}
|
||||
},
|
||||
"semanticHighlighting": {
|
||||
"doc": {
|
||||
"comment": {
|
||||
"inject": {
|
||||
"enable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"nonStandardTokens": true,
|
||||
"operator": {
|
||||
"enable": true,
|
||||
"specialization": {
|
||||
"enable": false
|
||||
}
|
||||
},
|
||||
"punctuation": {
|
||||
"enable": false,
|
||||
"separate": {
|
||||
"macro": {
|
||||
"bang": false
|
||||
}
|
||||
},
|
||||
"specialization": {
|
||||
"enable": false
|
||||
}
|
||||
},
|
||||
"strings": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"signatureInfo": {
|
||||
"detail": "full",
|
||||
"documentation": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"workspace": {
|
||||
"symbols": {
|
||||
"maxSymbols": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"trace": "verbose",
|
||||
"workspaceFolders": [
|
||||
{
|
||||
"uri": "$uri",
|
||||
"name": "$name"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
"""
|
||||
Provides Python specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Python.
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import AsyncIterator, Tuple
|
||||
|
||||
from overrides import override
|
||||
|
||||
from multilspy.multilspy_logger import MultilspyLogger
|
||||
from multilspy.language_server import LanguageServer
|
||||
from multilspy.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from multilspy.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from multilspy.multilspy_config import MultilspyConfig
|
||||
|
||||
|
||||
class JediServer(LanguageServer):
|
||||
"""
|
||||
Provides Python specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Python.
|
||||
"""
|
||||
|
||||
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
|
||||
"""
|
||||
Creates a JediServer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd="jedi-language-server", cwd=repository_root_path),
|
||||
"python",
|
||||
)
|
||||
|
||||
@override
|
||||
def is_ignored_dirname(self, dirname: str) -> bool:
|
||||
return super().is_ignored_dirname(dirname) or dirname in ["venv", "__pycache__"]
|
||||
|
||||
def _get_initialize_params(self, repository_absolute_path: str) -> InitializeParams:
|
||||
"""
|
||||
Returns the initialize params for the Jedi Language Server.
|
||||
"""
|
||||
with open(os.path.join(os.path.dirname(__file__), "initialize_params.json"), "r", encoding="utf-8") as f:
|
||||
d = json.load(f)
|
||||
|
||||
del d["_description"]
|
||||
|
||||
d["processId"] = os.getpid()
|
||||
assert d["rootPath"] == "$rootPath"
|
||||
d["rootPath"] = repository_absolute_path
|
||||
|
||||
assert d["rootUri"] == "$rootUri"
|
||||
d["rootUri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["uri"] == "$uri"
|
||||
d["workspaceFolders"][0]["uri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["name"] == "$name"
|
||||
d["workspaceFolders"][0]["name"] = os.path.basename(repository_absolute_path)
|
||||
|
||||
return d
|
||||
|
||||
@asynccontextmanager
|
||||
async def start_server(self) -> AsyncIterator["JediServer"]:
|
||||
"""
|
||||
Starts the JEDI Language Server, waits for the server to be ready and yields the LanguageServer instance.
|
||||
|
||||
Usage:
|
||||
```
|
||||
async with lsp.start_server():
|
||||
# LanguageServer has been initialized and ready to serve requests
|
||||
await lsp.request_definition(...)
|
||||
await lsp.request_references(...)
|
||||
# Shutdown the LanguageServer on exit from scope
|
||||
# LanguageServer has been shutdown
|
||||
```
|
||||
"""
|
||||
|
||||
async def execute_client_command_handler(params):
|
||||
return []
|
||||
|
||||
async def do_nothing(params):
|
||||
return
|
||||
|
||||
async def check_experimental_status(params):
|
||||
if params["quiescent"] == True:
|
||||
self.completions_available.set()
|
||||
|
||||
async def window_log_message(msg):
|
||||
self.logger.log(f"LSP: window/logMessage: {msg}", logging.INFO)
|
||||
|
||||
self.server.on_request("client/registerCapability", do_nothing)
|
||||
self.server.on_notification("language/status", do_nothing)
|
||||
self.server.on_notification("window/logMessage", window_log_message)
|
||||
self.server.on_request("workspace/executeClientCommand", execute_client_command_handler)
|
||||
self.server.on_notification("$/progress", do_nothing)
|
||||
self.server.on_notification("textDocument/publishDiagnostics", do_nothing)
|
||||
self.server.on_notification("language/actionableNotification", do_nothing)
|
||||
self.server.on_notification("experimental/serverStatus", check_experimental_status)
|
||||
|
||||
async with super().start_server():
|
||||
self.logger.log("Starting jedi-language-server server process", logging.INFO)
|
||||
await self.server.start()
|
||||
initialize_params = self._get_initialize_params(self.repository_root_path)
|
||||
|
||||
self.logger.log(
|
||||
"Sending initialize request from LSP client to LSP server and awaiting response",
|
||||
logging.INFO,
|
||||
)
|
||||
init_response = await self.server.send.initialize(initialize_params)
|
||||
assert init_response["capabilities"]["textDocumentSync"]["change"] == 2
|
||||
assert "completionProvider" in init_response["capabilities"]
|
||||
assert init_response["capabilities"]["completionProvider"] == {
|
||||
"triggerCharacters": [".", "'", '"'],
|
||||
"resolveProvider": True,
|
||||
}
|
||||
|
||||
self.server.notify.initialized({})
|
||||
|
||||
yield self
|
||||
@@ -0,0 +1,521 @@
|
||||
{
|
||||
"_description": "The parameters sent by the client when initializing the language server with the \"initialize\" request. More details at https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize",
|
||||
"processId": "os.getpid()",
|
||||
"clientInfo": {
|
||||
"name": "Multilspy Kotlin Client",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"locale": "en",
|
||||
"rootPath": "repository_absolute_path",
|
||||
"rootUri": "pathlib.Path(repository_absolute_path).as_uri()",
|
||||
"capabilities": {
|
||||
"workspace": {
|
||||
"applyEdit": true,
|
||||
"workspaceEdit": {
|
||||
"documentChanges": true,
|
||||
"resourceOperations": [
|
||||
"create",
|
||||
"rename",
|
||||
"delete"
|
||||
],
|
||||
"failureHandling": "textOnlyTransactional",
|
||||
"normalizesLineEndings": true,
|
||||
"changeAnnotationSupport": {
|
||||
"groupsOnLabel": true
|
||||
}
|
||||
},
|
||||
"didChangeConfiguration": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"didChangeWatchedFiles": {
|
||||
"dynamicRegistration": true,
|
||||
"relativePatternSupport": true
|
||||
},
|
||||
"symbol": {
|
||||
"dynamicRegistration": true,
|
||||
"symbolKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26
|
||||
]
|
||||
},
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"location.range"
|
||||
]
|
||||
}
|
||||
},
|
||||
"codeLens": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"executeCommand": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"configuration": true,
|
||||
"workspaceFolders": true,
|
||||
"semanticTokens": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"fileOperations": {
|
||||
"dynamicRegistration": true,
|
||||
"didCreate": true,
|
||||
"didRename": true,
|
||||
"didDelete": true,
|
||||
"willCreate": true,
|
||||
"willRename": true,
|
||||
"willDelete": true
|
||||
},
|
||||
"inlineValue": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"inlayHint": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"diagnostics": {
|
||||
"refreshSupport": true
|
||||
}
|
||||
},
|
||||
"textDocument": {
|
||||
"publishDiagnostics": {
|
||||
"relatedInformation": true,
|
||||
"versionSupport": false,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2
|
||||
]
|
||||
},
|
||||
"codeDescriptionSupport": true,
|
||||
"dataSupport": true
|
||||
},
|
||||
"synchronization": {
|
||||
"dynamicRegistration": true,
|
||||
"willSave": true,
|
||||
"willSaveWaitUntil": true,
|
||||
"didSave": true
|
||||
},
|
||||
"completion": {
|
||||
"dynamicRegistration": true,
|
||||
"contextSupport": true,
|
||||
"completionItem": {
|
||||
"snippetSupport": false,
|
||||
"commitCharactersSupport": true,
|
||||
"documentationFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
],
|
||||
"deprecatedSupport": true,
|
||||
"preselectSupport": true,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"insertReplaceSupport": false,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"documentation",
|
||||
"detail",
|
||||
"additionalTextEdits"
|
||||
]
|
||||
},
|
||||
"insertTextModeSupport": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2
|
||||
]
|
||||
},
|
||||
"labelDetailsSupport": true
|
||||
},
|
||||
"insertTextMode": 2,
|
||||
"completionItemKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25
|
||||
]
|
||||
},
|
||||
"completionList": {
|
||||
"itemDefaults": [
|
||||
"commitCharacters",
|
||||
"editRange",
|
||||
"insertTextFormat",
|
||||
"insertTextMode"
|
||||
]
|
||||
}
|
||||
},
|
||||
"hover": {
|
||||
"dynamicRegistration": true,
|
||||
"contentFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
]
|
||||
},
|
||||
"signatureHelp": {
|
||||
"dynamicRegistration": true,
|
||||
"signatureInformation": {
|
||||
"documentationFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
],
|
||||
"parameterInformation": {
|
||||
"labelOffsetSupport": true
|
||||
},
|
||||
"activeParameterSupport": true
|
||||
},
|
||||
"contextSupport": true
|
||||
},
|
||||
"definition": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"references": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"documentHighlight": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"documentSymbol": {
|
||||
"dynamicRegistration": true,
|
||||
"symbolKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26
|
||||
]
|
||||
},
|
||||
"hierarchicalDocumentSymbolSupport": true,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"labelSupport": true
|
||||
},
|
||||
"codeAction": {
|
||||
"dynamicRegistration": true,
|
||||
"isPreferredSupport": true,
|
||||
"disabledSupport": true,
|
||||
"dataSupport": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"edit"
|
||||
]
|
||||
},
|
||||
"codeActionLiteralSupport": {
|
||||
"codeActionKind": {
|
||||
"valueSet": [
|
||||
"",
|
||||
"quickfix",
|
||||
"refactor",
|
||||
"refactor.extract",
|
||||
"refactor.inline",
|
||||
"refactor.rewrite",
|
||||
"source",
|
||||
"source.organizeImports"
|
||||
]
|
||||
}
|
||||
},
|
||||
"honorsChangeAnnotations": false
|
||||
},
|
||||
"codeLens": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"formatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"rangeFormatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"onTypeFormatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"rename": {
|
||||
"dynamicRegistration": true,
|
||||
"prepareSupport": true,
|
||||
"prepareSupportDefaultBehavior": 1,
|
||||
"honorsChangeAnnotations": true
|
||||
},
|
||||
"documentLink": {
|
||||
"dynamicRegistration": true,
|
||||
"tooltipSupport": true
|
||||
},
|
||||
"typeDefinition": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"implementation": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"colorProvider": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"foldingRange": {
|
||||
"dynamicRegistration": true,
|
||||
"rangeLimit": 5000,
|
||||
"lineFoldingOnly": true,
|
||||
"foldingRangeKind": {
|
||||
"valueSet": [
|
||||
"comment",
|
||||
"imports",
|
||||
"region"
|
||||
]
|
||||
},
|
||||
"foldingRange": {
|
||||
"collapsedText": false
|
||||
}
|
||||
},
|
||||
"declaration": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"selectionRange": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"callHierarchy": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"semanticTokens": {
|
||||
"dynamicRegistration": true,
|
||||
"tokenTypes": [
|
||||
"namespace",
|
||||
"type",
|
||||
"class",
|
||||
"enum",
|
||||
"interface",
|
||||
"struct",
|
||||
"typeParameter",
|
||||
"parameter",
|
||||
"variable",
|
||||
"property",
|
||||
"enumMember",
|
||||
"event",
|
||||
"function",
|
||||
"method",
|
||||
"macro",
|
||||
"keyword",
|
||||
"modifier",
|
||||
"comment",
|
||||
"string",
|
||||
"number",
|
||||
"regexp",
|
||||
"operator",
|
||||
"decorator"
|
||||
],
|
||||
"tokenModifiers": [
|
||||
"declaration",
|
||||
"definition",
|
||||
"readonly",
|
||||
"static",
|
||||
"deprecated",
|
||||
"abstract",
|
||||
"async",
|
||||
"modification",
|
||||
"documentation",
|
||||
"defaultLibrary"
|
||||
],
|
||||
"formats": [
|
||||
"relative"
|
||||
],
|
||||
"requests": {
|
||||
"range": true,
|
||||
"full": {
|
||||
"delta": true
|
||||
}
|
||||
},
|
||||
"multilineTokenSupport": false,
|
||||
"overlappingTokenSupport": false,
|
||||
"serverCancelSupport": true,
|
||||
"augmentsSyntaxTokens": true
|
||||
},
|
||||
"linkedEditingRange": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"typeHierarchy": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"inlineValue": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"inlayHint": {
|
||||
"dynamicRegistration": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"tooltip",
|
||||
"textEdits",
|
||||
"label.tooltip",
|
||||
"label.location",
|
||||
"label.command"
|
||||
]
|
||||
}
|
||||
},
|
||||
"diagnostic": {
|
||||
"dynamicRegistration": true,
|
||||
"relatedDocumentSupport": false
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
"showMessage": {
|
||||
"messageActionItem": {
|
||||
"additionalPropertiesSupport": true
|
||||
}
|
||||
},
|
||||
"showDocument": {
|
||||
"support": true
|
||||
},
|
||||
"workDoneProgress": true
|
||||
},
|
||||
"general": {
|
||||
"staleRequestSupport": {
|
||||
"cancel": true,
|
||||
"retryOnContentModified": [
|
||||
"textDocument/semanticTokens/full",
|
||||
"textDocument/semanticTokens/range",
|
||||
"textDocument/semanticTokens/full/delta"
|
||||
]
|
||||
},
|
||||
"regularExpressions": {
|
||||
"engine": "ECMAScript",
|
||||
"version": "ES2020"
|
||||
},
|
||||
"markdown": {
|
||||
"parser": "marked",
|
||||
"version": "1.1.0"
|
||||
},
|
||||
"positionEncodings": [
|
||||
"utf-16"
|
||||
]
|
||||
},
|
||||
"notebookDocument": {
|
||||
"synchronization": {
|
||||
"dynamicRegistration": true,
|
||||
"executionSummarySupport": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"initializationOptions": {
|
||||
"workspaceFolders": "[pathlib.Path(repository_absolute_path).as_uri()]",
|
||||
"storagePath": null,
|
||||
"codegen": {
|
||||
"enabled": false
|
||||
},
|
||||
"compiler": {
|
||||
"jvm": {
|
||||
"target": "default"
|
||||
}
|
||||
},
|
||||
"completion": {
|
||||
"snippets": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"diagnostics": {
|
||||
"enabled": true,
|
||||
"level": 4,
|
||||
"debounceTime": 250
|
||||
},
|
||||
"scripts": {
|
||||
"enabled": true,
|
||||
"buildScriptsEnabled": true
|
||||
},
|
||||
"indexing": {
|
||||
"enabled": true
|
||||
},
|
||||
"externalSources": {
|
||||
"useKlsScheme": false,
|
||||
"autoConvertToKotlin": false
|
||||
},
|
||||
"inlayHints": {
|
||||
"typeHints": false,
|
||||
"parameterHints": false,
|
||||
"chainedHints": false
|
||||
},
|
||||
"formatting": {
|
||||
"formatter": "ktfmt",
|
||||
"ktfmt": {
|
||||
"style": "google",
|
||||
"indent": 4,
|
||||
"maxWidth": 100,
|
||||
"continuationIndent": 8,
|
||||
"removeUnusedImports": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"trace": "verbose",
|
||||
"workspaceFolders": "[\n {\n \"uri\": pathlib.Path(repository_absolute_path).as_uri(),\n \"name\": os.path.basename(repository_absolute_path),\n }\n ]"
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
"""
|
||||
Provides Kotlin specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Kotlin.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import dataclasses
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import stat
|
||||
import pathlib
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import AsyncIterator
|
||||
|
||||
from multilspy.multilspy_logger import MultilspyLogger
|
||||
from multilspy.language_server import LanguageServer
|
||||
from multilspy.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from multilspy.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from multilspy.multilspy_config import MultilspyConfig
|
||||
from multilspy.multilspy_utils import FileUtils
|
||||
from multilspy.multilspy_utils import PlatformUtils
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class KotlinRuntimeDependencyPaths:
|
||||
"""
|
||||
Stores the paths to the runtime dependencies of Kotlin Language Server
|
||||
"""
|
||||
java_path: str
|
||||
java_home_path: str
|
||||
kotlin_executable_path: str
|
||||
|
||||
|
||||
class KotlinLanguageServer(LanguageServer):
|
||||
"""
|
||||
Provides Kotlin specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Kotlin.
|
||||
"""
|
||||
|
||||
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
|
||||
"""
|
||||
Creates a Kotlin Language Server instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
runtime_dependency_paths = self.setup_runtime_dependencies(logger, config)
|
||||
self.runtime_dependency_paths = runtime_dependency_paths
|
||||
|
||||
# Create command to execute the Kotlin Language Server script
|
||||
cmd = f'"{self.runtime_dependency_paths.kotlin_executable_path}"'
|
||||
|
||||
# Set environment variables including JAVA_HOME
|
||||
proc_env = {"JAVA_HOME": self.runtime_dependency_paths.java_home_path}
|
||||
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=cmd, env=proc_env, cwd=repository_root_path),
|
||||
"kotlin",
|
||||
)
|
||||
|
||||
def setup_runtime_dependencies(self, logger: MultilspyLogger, config: MultilspyConfig) -> KotlinRuntimeDependencyPaths:
|
||||
"""
|
||||
Setup runtime dependencies for Kotlin Language Server.
|
||||
"""
|
||||
platform_id = PlatformUtils.get_platform_id()
|
||||
|
||||
# Verify platform support
|
||||
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"
|
||||
|
||||
# Load dependency information
|
||||
with open(os.path.join(os.path.dirname(__file__), "runtime_dependencies.json"), "r", encoding="utf-8") as f:
|
||||
d = json.load(f)
|
||||
del d["_description"]
|
||||
|
||||
kotlin_dependency = d["runtimeDependency"]
|
||||
java_dependency = d["java"][platform_id.value]
|
||||
|
||||
# Setup paths for dependencies
|
||||
static_dir = os.path.join(os.path.dirname(__file__), "static")
|
||||
os.makedirs(static_dir, exist_ok=True)
|
||||
|
||||
# Setup Java paths
|
||||
java_dir = os.path.join(static_dir, "java")
|
||||
os.makedirs(java_dir, exist_ok=True)
|
||||
|
||||
java_home_path = os.path.join(java_dir, java_dependency["java_home_path"])
|
||||
java_path = os.path.join(java_dir, java_dependency["java_path"])
|
||||
|
||||
# Download and extract Java if not exists
|
||||
if not os.path.exists(java_path):
|
||||
logger.log(f"Downloading Java for {platform_id.value}...", logging.INFO)
|
||||
FileUtils.download_and_extract_archive(
|
||||
logger, java_dependency["url"], java_dir, java_dependency["archiveType"]
|
||||
)
|
||||
# Make Java executable
|
||||
if not platform_id.value.startswith("win-"):
|
||||
os.chmod(java_path, 0o755)
|
||||
|
||||
assert os.path.exists(java_path), f"Java executable not found at {java_path}"
|
||||
|
||||
# Setup Kotlin Language Server paths
|
||||
kotlin_ls_dir = os.path.join(static_dir, "server")
|
||||
|
||||
# Get platform-specific executable script path
|
||||
if platform_id.value.startswith("win-"):
|
||||
kotlin_script = os.path.join(kotlin_ls_dir, "bin", "kotlin-language-server.bat")
|
||||
else:
|
||||
kotlin_script = os.path.join(kotlin_ls_dir, "bin", "kotlin-language-server")
|
||||
|
||||
# Download and extract Kotlin Language Server if script doesn't exist
|
||||
if not os.path.exists(kotlin_script):
|
||||
logger.log("Downloading Kotlin Language Server...", logging.INFO)
|
||||
FileUtils.download_and_extract_archive(
|
||||
logger, kotlin_dependency["url"], static_dir, kotlin_dependency["archiveType"]
|
||||
)
|
||||
|
||||
# Make script executable on Unix platforms
|
||||
if os.path.exists(kotlin_script) and not platform_id.value.startswith("win-"):
|
||||
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)
|
||||
|
||||
# Use script file
|
||||
if os.path.exists(kotlin_script):
|
||||
kotlin_executable_path = kotlin_script
|
||||
logger.log(f"Using Kotlin Language Server script at {kotlin_script}", logging.INFO)
|
||||
else:
|
||||
raise FileNotFoundError(f"Kotlin Language Server script not found at {kotlin_script}")
|
||||
|
||||
return KotlinRuntimeDependencyPaths(
|
||||
java_path=java_path,
|
||||
java_home_path=java_home_path,
|
||||
kotlin_executable_path=kotlin_executable_path
|
||||
)
|
||||
|
||||
def _get_initialize_params(self, repository_absolute_path: str) -> InitializeParams:
|
||||
"""
|
||||
Returns the initialize params for the Kotlin Language Server.
|
||||
"""
|
||||
with open(str(pathlib.PurePath(os.path.dirname(__file__), "initialize_params.json")), "r", encoding="utf-8") as f:
|
||||
d: InitializeParams = json.load(f)
|
||||
|
||||
del d["_description"]
|
||||
|
||||
if not os.path.isabs(repository_absolute_path):
|
||||
repository_absolute_path = os.path.abspath(repository_absolute_path)
|
||||
|
||||
assert d["processId"] == "os.getpid()"
|
||||
d["processId"] = os.getpid()
|
||||
|
||||
assert d["rootPath"] == "repository_absolute_path"
|
||||
d["rootPath"] = repository_absolute_path
|
||||
|
||||
assert d["rootUri"] == "pathlib.Path(repository_absolute_path).as_uri()"
|
||||
d["rootUri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["initializationOptions"]["workspaceFolders"] == "[pathlib.Path(repository_absolute_path).as_uri()]"
|
||||
d["initializationOptions"]["workspaceFolders"] = [pathlib.Path(repository_absolute_path).as_uri()]
|
||||
|
||||
assert (
|
||||
d["workspaceFolders"]
|
||||
== '[\n {\n "uri": pathlib.Path(repository_absolute_path).as_uri(),\n "name": os.path.basename(repository_absolute_path),\n }\n ]'
|
||||
)
|
||||
d["workspaceFolders"] = [
|
||||
{
|
||||
"uri": pathlib.Path(repository_absolute_path).as_uri(),
|
||||
"name": os.path.basename(repository_absolute_path),
|
||||
}
|
||||
]
|
||||
|
||||
return d
|
||||
|
||||
@asynccontextmanager
|
||||
async def start_server(self) -> AsyncIterator["KotlinLanguageServer"]:
|
||||
"""
|
||||
Starts the Kotlin Language Server, waits for the server to be ready and yields the LanguageServer instance.
|
||||
|
||||
Usage:
|
||||
```
|
||||
async with lsp.start_server():
|
||||
# LanguageServer has been initialized and ready to serve requests
|
||||
await lsp.request_definition(...)
|
||||
await lsp.request_references(...)
|
||||
# Shutdown the LanguageServer on exit from scope
|
||||
# LanguageServer has been shutdown
|
||||
```
|
||||
"""
|
||||
async def execute_client_command_handler(params):
|
||||
return []
|
||||
|
||||
async def do_nothing(params):
|
||||
return
|
||||
|
||||
async def window_log_message(msg):
|
||||
self.logger.log(f"LSP: window/logMessage: {msg}", logging.INFO)
|
||||
|
||||
self.server.on_request("client/registerCapability", do_nothing)
|
||||
self.server.on_notification("language/status", do_nothing)
|
||||
self.server.on_notification("window/logMessage", window_log_message)
|
||||
self.server.on_request("workspace/executeClientCommand", execute_client_command_handler)
|
||||
self.server.on_notification("$/progress", do_nothing)
|
||||
self.server.on_notification("textDocument/publishDiagnostics", do_nothing)
|
||||
self.server.on_notification("language/actionableNotification", do_nothing)
|
||||
|
||||
async with super().start_server():
|
||||
self.logger.log("Starting Kotlin server process", logging.INFO)
|
||||
await self.server.start()
|
||||
initialize_params = self._get_initialize_params(self.repository_root_path)
|
||||
|
||||
self.logger.log(
|
||||
"Sending initialize request from LSP client to LSP server and awaiting response",
|
||||
logging.INFO,
|
||||
)
|
||||
init_response = await self.server.send.initialize(initialize_params)
|
||||
|
||||
capabilities = init_response["capabilities"]
|
||||
assert "textDocumentSync" in capabilities, "Server must support textDocumentSync"
|
||||
assert "hoverProvider" in capabilities, "Server must support hover"
|
||||
assert "completionProvider" in capabilities, "Server must support code completion"
|
||||
assert "signatureHelpProvider" in capabilities, "Server must support signature help"
|
||||
assert "definitionProvider" in capabilities, "Server must support go to definition"
|
||||
assert "referencesProvider" in capabilities, "Server must support find references"
|
||||
assert "documentSymbolProvider" in capabilities, "Server must support document symbols"
|
||||
assert "workspaceSymbolProvider" in capabilities, "Server must support workspace symbols"
|
||||
assert "semanticTokensProvider" in capabilities, "Server must support semantic tokens"
|
||||
|
||||
self.server.notify.initialized({})
|
||||
self.completions_available.set()
|
||||
|
||||
yield self
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"_description": "Used to download the runtime dependencies for Kotlin Language Server from https://github.com/fwcd/kotlin-language-server",
|
||||
"runtimeDependency": {
|
||||
"id": "KotlinLsp",
|
||||
"description": "Kotlin Language Server",
|
||||
"url": "https://github.com/fwcd/kotlin-language-server/releases/download/1.3.13/server.zip",
|
||||
"archiveType": "zip"
|
||||
},
|
||||
"java": {
|
||||
"win-x64": {
|
||||
"url": "https://github.com/redhat-developer/vscode-java/releases/download/v1.42.0/java-win32-x64-1.42.0-561.vsix",
|
||||
"archiveType": "zip",
|
||||
"java_home_path": "extension/jre/21.0.7-win32-x86_64",
|
||||
"java_path": "extension/jre/21.0.7-win32-x86_64/bin/java.exe"
|
||||
},
|
||||
"linux-x64": {
|
||||
"url": "https://github.com/redhat-developer/vscode-java/releases/download/v1.42.0/java-linux-x64-1.42.0-561.vsix",
|
||||
"archiveType": "zip",
|
||||
"java_home_path": "extension/jre/21.0.7-linux-x86_64",
|
||||
"java_path": "extension/jre/21.0.7-linux-x86_64/bin/java"
|
||||
},
|
||||
"linux-arm64": {
|
||||
"url": "https://github.com/redhat-developer/vscode-java/releases/download/v1.42.0/java-linux-arm64-1.42.0-561.vsix",
|
||||
"archiveType": "zip",
|
||||
"java_home_path": "extension/jre/21.0.7-linux-aarch64",
|
||||
"java_path": "extension/jre/21.0.7-linux-aarch64/bin/java"
|
||||
},
|
||||
"osx-x64": {
|
||||
"url": "https://github.com/redhat-developer/vscode-java/releases/download/v1.42.0/java-darwin-x64-1.42.0-561.vsix",
|
||||
"archiveType": "zip",
|
||||
"java_home_path": "extension/jre/21.0.7-macosx-x86_64",
|
||||
"java_path": "extension/jre/21.0.7-macosx-x86_64/bin/java"
|
||||
},
|
||||
"osx-arm64": {
|
||||
"url": "https://github.com/redhat-developer/vscode-java/releases/download/v1.42.0/java-darwin-arm64-1.42.0-561.vsix",
|
||||
"archiveType": "zip",
|
||||
"java_home_path": "extension/jre/21.0.7-macosx-aarch64",
|
||||
"java_path": "extension/jre/21.0.7-macosx-aarch64/bin/java"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,631 @@
|
||||
{
|
||||
"_description": "The parameters sent by the client when initializing the language server with the \"initialize\" request. More details at https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize",
|
||||
"processId": "os.getpid()",
|
||||
"clientInfo": {
|
||||
"name": "Visual Studio Code - Insiders",
|
||||
"version": "1.82.0-insider"
|
||||
},
|
||||
"locale": "en",
|
||||
"rootPath": "$rootPath",
|
||||
"rootUri": "$rootUri",
|
||||
"capabilities": {
|
||||
"workspace": {
|
||||
"applyEdit": true,
|
||||
"workspaceEdit": {
|
||||
"documentChanges": true,
|
||||
"resourceOperations": [
|
||||
"create",
|
||||
"rename",
|
||||
"delete"
|
||||
],
|
||||
"failureHandling": "textOnlyTransactional",
|
||||
"normalizesLineEndings": true,
|
||||
"changeAnnotationSupport": {
|
||||
"groupsOnLabel": true
|
||||
}
|
||||
},
|
||||
"configuration": false,
|
||||
"didChangeWatchedFiles": {
|
||||
"dynamicRegistration": true,
|
||||
"relativePatternSupport": true
|
||||
},
|
||||
"symbol": {
|
||||
"dynamicRegistration": true,
|
||||
"symbolKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26
|
||||
]
|
||||
},
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"location.range"
|
||||
]
|
||||
}
|
||||
},
|
||||
"codeLens": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"executeCommand": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"didChangeConfiguration": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"workspaceFolders": true,
|
||||
"semanticTokens": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"fileOperations": {
|
||||
"dynamicRegistration": true,
|
||||
"didCreate": true,
|
||||
"didRename": true,
|
||||
"didDelete": true,
|
||||
"willCreate": true,
|
||||
"willRename": true,
|
||||
"willDelete": true
|
||||
},
|
||||
"inlineValue": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"inlayHint": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"diagnostics": {
|
||||
"refreshSupport": true
|
||||
}
|
||||
},
|
||||
"textDocument": {
|
||||
"publishDiagnostics": {
|
||||
"relatedInformation": true,
|
||||
"versionSupport": false,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2
|
||||
]
|
||||
},
|
||||
"codeDescriptionSupport": true,
|
||||
"dataSupport": true
|
||||
},
|
||||
"synchronization": {
|
||||
"dynamicRegistration": true,
|
||||
"willSave": true,
|
||||
"willSaveWaitUntil": true,
|
||||
"didSave": true
|
||||
},
|
||||
"completion": {
|
||||
"dynamicRegistration": true,
|
||||
"contextSupport": true,
|
||||
"completionItem": {
|
||||
"snippetSupport": true,
|
||||
"commitCharactersSupport": true,
|
||||
"documentationFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
],
|
||||
"deprecatedSupport": true,
|
||||
"preselectSupport": true,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"insertReplaceSupport": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"documentation",
|
||||
"detail",
|
||||
"additionalTextEdits"
|
||||
]
|
||||
},
|
||||
"insertTextModeSupport": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2
|
||||
]
|
||||
},
|
||||
"labelDetailsSupport": true
|
||||
},
|
||||
"insertTextMode": 2,
|
||||
"completionItemKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25
|
||||
]
|
||||
},
|
||||
"completionList": {
|
||||
"itemDefaults": [
|
||||
"commitCharacters",
|
||||
"editRange",
|
||||
"insertTextFormat",
|
||||
"insertTextMode"
|
||||
]
|
||||
}
|
||||
},
|
||||
"hover": {
|
||||
"dynamicRegistration": true,
|
||||
"contentFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
]
|
||||
},
|
||||
"signatureHelp": {
|
||||
"dynamicRegistration": true,
|
||||
"signatureInformation": {
|
||||
"documentationFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
],
|
||||
"parameterInformation": {
|
||||
"labelOffsetSupport": true
|
||||
},
|
||||
"activeParameterSupport": true
|
||||
},
|
||||
"contextSupport": true
|
||||
},
|
||||
"definition": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"references": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"documentHighlight": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"documentSymbol": {
|
||||
"dynamicRegistration": true,
|
||||
"symbolKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26
|
||||
]
|
||||
},
|
||||
"hierarchicalDocumentSymbolSupport": true,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"labelSupport": true
|
||||
},
|
||||
"codeAction": {
|
||||
"dynamicRegistration": true,
|
||||
"isPreferredSupport": true,
|
||||
"disabledSupport": true,
|
||||
"dataSupport": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"edit"
|
||||
]
|
||||
},
|
||||
"codeActionLiteralSupport": {
|
||||
"codeActionKind": {
|
||||
"valueSet": [
|
||||
"",
|
||||
"quickfix",
|
||||
"refactor",
|
||||
"refactor.extract",
|
||||
"refactor.inline",
|
||||
"refactor.rewrite",
|
||||
"source",
|
||||
"source.organizeImports"
|
||||
]
|
||||
}
|
||||
},
|
||||
"honorsChangeAnnotations": false
|
||||
},
|
||||
"codeLens": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"formatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"rangeFormatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"onTypeFormatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"rename": {
|
||||
"dynamicRegistration": true,
|
||||
"prepareSupport": true,
|
||||
"prepareSupportDefaultBehavior": 1,
|
||||
"honorsChangeAnnotations": true
|
||||
},
|
||||
"documentLink": {
|
||||
"dynamicRegistration": true,
|
||||
"tooltipSupport": true
|
||||
},
|
||||
"typeDefinition": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"implementation": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"colorProvider": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"foldingRange": {
|
||||
"dynamicRegistration": true,
|
||||
"rangeLimit": 5000,
|
||||
"lineFoldingOnly": true,
|
||||
"foldingRangeKind": {
|
||||
"valueSet": [
|
||||
"comment",
|
||||
"imports",
|
||||
"region"
|
||||
]
|
||||
},
|
||||
"foldingRange": {
|
||||
"collapsedText": false
|
||||
}
|
||||
},
|
||||
"declaration": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"selectionRange": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"callHierarchy": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"semanticTokens": {
|
||||
"dynamicRegistration": true,
|
||||
"tokenTypes": [
|
||||
"namespace",
|
||||
"type",
|
||||
"class",
|
||||
"enum",
|
||||
"interface",
|
||||
"struct",
|
||||
"typeParameter",
|
||||
"parameter",
|
||||
"variable",
|
||||
"property",
|
||||
"enumMember",
|
||||
"event",
|
||||
"function",
|
||||
"method",
|
||||
"macro",
|
||||
"keyword",
|
||||
"modifier",
|
||||
"comment",
|
||||
"string",
|
||||
"number",
|
||||
"regexp",
|
||||
"operator",
|
||||
"decorator"
|
||||
],
|
||||
"tokenModifiers": [
|
||||
"declaration",
|
||||
"definition",
|
||||
"readonly",
|
||||
"static",
|
||||
"deprecated",
|
||||
"abstract",
|
||||
"async",
|
||||
"modification",
|
||||
"documentation",
|
||||
"defaultLibrary"
|
||||
],
|
||||
"formats": [
|
||||
"relative"
|
||||
],
|
||||
"requests": {
|
||||
"range": true,
|
||||
"full": {
|
||||
"delta": true
|
||||
}
|
||||
},
|
||||
"multilineTokenSupport": false,
|
||||
"overlappingTokenSupport": false,
|
||||
"serverCancelSupport": true,
|
||||
"augmentsSyntaxTokens": false
|
||||
},
|
||||
"linkedEditingRange": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"typeHierarchy": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"inlineValue": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"inlayHint": {
|
||||
"dynamicRegistration": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"tooltip",
|
||||
"textEdits",
|
||||
"label.tooltip",
|
||||
"label.location",
|
||||
"label.command"
|
||||
]
|
||||
}
|
||||
},
|
||||
"diagnostic": {
|
||||
"dynamicRegistration": true,
|
||||
"relatedDocumentSupport": false
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
"showMessage": {
|
||||
"messageActionItem": {
|
||||
"additionalPropertiesSupport": true
|
||||
}
|
||||
},
|
||||
"showDocument": {
|
||||
"support": true
|
||||
},
|
||||
"workDoneProgress": true
|
||||
},
|
||||
"general": {
|
||||
"staleRequestSupport": {
|
||||
"cancel": true,
|
||||
"retryOnContentModified": [
|
||||
"textDocument/semanticTokens/full",
|
||||
"textDocument/semanticTokens/range",
|
||||
"textDocument/semanticTokens/full/delta"
|
||||
]
|
||||
},
|
||||
"regularExpressions": {
|
||||
"engine": "ECMAScript",
|
||||
"version": "ES2020"
|
||||
},
|
||||
"markdown": {
|
||||
"parser": "marked",
|
||||
"version": "1.1.0",
|
||||
"allowedTags": [
|
||||
"ul",
|
||||
"li",
|
||||
"p",
|
||||
"code",
|
||||
"blockquote",
|
||||
"ol",
|
||||
"h1",
|
||||
"h2",
|
||||
"h3",
|
||||
"h4",
|
||||
"h5",
|
||||
"h6",
|
||||
"hr",
|
||||
"em",
|
||||
"pre",
|
||||
"table",
|
||||
"thead",
|
||||
"tbody",
|
||||
"tr",
|
||||
"th",
|
||||
"td",
|
||||
"div",
|
||||
"del",
|
||||
"a",
|
||||
"strong",
|
||||
"br",
|
||||
"img",
|
||||
"span"
|
||||
]
|
||||
},
|
||||
"positionEncodings": [
|
||||
"utf-16"
|
||||
]
|
||||
},
|
||||
"notebookDocument": {
|
||||
"synchronization": {
|
||||
"dynamicRegistration": true,
|
||||
"executionSummarySupport": true
|
||||
}
|
||||
},
|
||||
"experimental": {
|
||||
"snippetTextEdit": true,
|
||||
"codeActionGroup": true,
|
||||
"hoverActions": true,
|
||||
"serverStatusNotification": true,
|
||||
"colorDiagnosticOutput": true,
|
||||
"openServerLogs": true,
|
||||
"commands": {
|
||||
"commands": [
|
||||
"editor.action.triggerParameterHints"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"initializationOptions": {
|
||||
"RoslynExtensionsOptions": {
|
||||
"EnableDecompilationSupport": false,
|
||||
"EnableAnalyzersSupport": true,
|
||||
"EnableImportCompletion": true,
|
||||
"EnableAsyncCompletion": false,
|
||||
"DocumentAnalysisTimeoutMs": 30000,
|
||||
"DiagnosticWorkersThreadCount": 18,
|
||||
"AnalyzeOpenDocumentsOnly": true,
|
||||
"InlayHintsOptions": {
|
||||
"EnableForParameters": false,
|
||||
"ForLiteralParameters": false,
|
||||
"ForIndexerParameters": false,
|
||||
"ForObjectCreationParameters": false,
|
||||
"ForOtherParameters": false,
|
||||
"SuppressForParametersThatDifferOnlyBySuffix": false,
|
||||
"SuppressForParametersThatMatchMethodIntent": false,
|
||||
"SuppressForParametersThatMatchArgumentName": false,
|
||||
"EnableForTypes": false,
|
||||
"ForImplicitVariableTypes": false,
|
||||
"ForLambdaParameterTypes": false,
|
||||
"ForImplicitObjectCreation": false
|
||||
},
|
||||
"LocationPaths": null
|
||||
},
|
||||
"FormattingOptions": {
|
||||
"OrganizeImports": false,
|
||||
"EnableEditorConfigSupport": true,
|
||||
"NewLine": "\n",
|
||||
"UseTabs": false,
|
||||
"TabSize": 4,
|
||||
"IndentationSize": 4,
|
||||
"SpacingAfterMethodDeclarationName": false,
|
||||
"SeparateImportDirectiveGroups": false,
|
||||
"SpaceWithinMethodDeclarationParenthesis": false,
|
||||
"SpaceBetweenEmptyMethodDeclarationParentheses": false,
|
||||
"SpaceAfterMethodCallName": false,
|
||||
"SpaceWithinMethodCallParentheses": false,
|
||||
"SpaceBetweenEmptyMethodCallParentheses": false,
|
||||
"SpaceAfterControlFlowStatementKeyword": true,
|
||||
"SpaceWithinExpressionParentheses": false,
|
||||
"SpaceWithinCastParentheses": false,
|
||||
"SpaceWithinOtherParentheses": false,
|
||||
"SpaceAfterCast": false,
|
||||
"SpaceBeforeOpenSquareBracket": false,
|
||||
"SpaceBetweenEmptySquareBrackets": false,
|
||||
"SpaceWithinSquareBrackets": false,
|
||||
"SpaceAfterColonInBaseTypeDeclaration": true,
|
||||
"SpaceAfterComma": true,
|
||||
"SpaceAfterDot": false,
|
||||
"SpaceAfterSemicolonsInForStatement": true,
|
||||
"SpaceBeforeColonInBaseTypeDeclaration": true,
|
||||
"SpaceBeforeComma": false,
|
||||
"SpaceBeforeDot": false,
|
||||
"SpaceBeforeSemicolonsInForStatement": false,
|
||||
"SpacingAroundBinaryOperator": "single",
|
||||
"IndentBraces": false,
|
||||
"IndentBlock": true,
|
||||
"IndentSwitchSection": true,
|
||||
"IndentSwitchCaseSection": true,
|
||||
"IndentSwitchCaseSectionWhenBlock": true,
|
||||
"LabelPositioning": "oneLess",
|
||||
"WrappingPreserveSingleLine": true,
|
||||
"WrappingKeepStatementsOnSingleLine": true,
|
||||
"NewLinesForBracesInTypes": true,
|
||||
"NewLinesForBracesInMethods": true,
|
||||
"NewLinesForBracesInProperties": true,
|
||||
"NewLinesForBracesInAccessors": true,
|
||||
"NewLinesForBracesInAnonymousMethods": true,
|
||||
"NewLinesForBracesInControlBlocks": true,
|
||||
"NewLinesForBracesInAnonymousTypes": true,
|
||||
"NewLinesForBracesInObjectCollectionArrayInitializers": true,
|
||||
"NewLinesForBracesInLambdaExpressionBody": true,
|
||||
"NewLineForElse": true,
|
||||
"NewLineForCatch": true,
|
||||
"NewLineForFinally": true,
|
||||
"NewLineForMembersInObjectInit": true,
|
||||
"NewLineForMembersInAnonymousTypes": true,
|
||||
"NewLineForClausesInQuery": true
|
||||
},
|
||||
"FileOptions": {
|
||||
"SystemExcludeSearchPatterns": [
|
||||
"**/node_modules/**/*",
|
||||
"**/bin/**/*",
|
||||
"**/obj/**/*",
|
||||
"**/.git/**/*",
|
||||
"**/.git",
|
||||
"**/.svn",
|
||||
"**/.hg",
|
||||
"**/CVS",
|
||||
"**/.DS_Store",
|
||||
"**/Thumbs.db"
|
||||
],
|
||||
"ExcludeSearchPatterns": []
|
||||
},
|
||||
"RenameOptions": {
|
||||
"RenameOverloads": false,
|
||||
"RenameInStrings": false,
|
||||
"RenameInComments": false
|
||||
},
|
||||
"ImplementTypeOptions": {
|
||||
"InsertionBehavior": 0,
|
||||
"PropertyGenerationBehavior": 0
|
||||
},
|
||||
"DotNetCliOptions": {
|
||||
"LocationPaths": null
|
||||
},
|
||||
"Plugins": {
|
||||
"LocationPaths": null
|
||||
}
|
||||
},
|
||||
"trace": "verbose",
|
||||
"workspaceFolders": [
|
||||
{
|
||||
"uri": "$uri",
|
||||
"name": "$name"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,406 @@
|
||||
"""
|
||||
Provides C# specific instantiation of the LanguageServer class. Contains various configurations and settings specific to C#.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import stat
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import AsyncIterator, Iterable
|
||||
|
||||
from overrides import override
|
||||
|
||||
from multilspy.multilspy_logger import MultilspyLogger
|
||||
from multilspy.language_server import LanguageServer
|
||||
from multilspy.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from multilspy.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from multilspy.multilspy_config import MultilspyConfig
|
||||
from multilspy.multilspy_exceptions import MultilspyException
|
||||
from multilspy.multilspy_utils import FileUtils, PlatformUtils, PlatformId, DotnetVersion
|
||||
|
||||
|
||||
def breadth_first_file_scan(root) -> Iterable[str]:
|
||||
"""
|
||||
This function was obtained from https://stackoverflow.com/questions/49654234/is-there-a-breadth-first-search-option-available-in-os-walk-or-equivalent-py
|
||||
It traverses the directory tree in breadth first order.
|
||||
"""
|
||||
dirs = [root]
|
||||
# while we has dirs to scan
|
||||
while len(dirs):
|
||||
next_dirs = []
|
||||
for parent in dirs:
|
||||
# scan each dir
|
||||
for f in os.listdir(parent):
|
||||
# if there is a dir, then save for next ittr
|
||||
# if it is a file then yield it (we'll return later)
|
||||
ff = os.path.join(parent, f)
|
||||
if os.path.isdir(ff):
|
||||
next_dirs.append(ff)
|
||||
else:
|
||||
yield ff
|
||||
|
||||
# once we've done all the current dirs then
|
||||
# we set up the next itter as the child dirs
|
||||
# from the current itter.
|
||||
dirs = next_dirs
|
||||
|
||||
|
||||
def find_least_depth_sln_file(root_dir) -> str | None:
|
||||
for filename in breadth_first_file_scan(root_dir):
|
||||
if filename.endswith(".sln"):
|
||||
return filename
|
||||
return None
|
||||
|
||||
|
||||
class OmniSharp(LanguageServer):
|
||||
"""
|
||||
Provides C# specific instantiation of the LanguageServer class. Contains various configurations and settings specific to C#.
|
||||
"""
|
||||
|
||||
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
|
||||
"""
|
||||
Creates an OmniSharp instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
omnisharp_executable_path, dll_path = self.setupRuntimeDependencies(logger, config)
|
||||
|
||||
slnfilename = find_least_depth_sln_file(repository_root_path)
|
||||
if slnfilename is None:
|
||||
logger.log("No *.sln file found in repository", logging.ERROR)
|
||||
raise MultilspyException("No SLN file found in repository")
|
||||
|
||||
cmd = " ".join(
|
||||
[
|
||||
omnisharp_executable_path,
|
||||
"-lsp",
|
||||
"--encoding",
|
||||
"ascii",
|
||||
"-z",
|
||||
"-s",
|
||||
f'"{slnfilename}"',
|
||||
"--hostPID",
|
||||
str(os.getpid()),
|
||||
"DotNet:enablePackageRestore=false",
|
||||
"--loglevel",
|
||||
"trace",
|
||||
"--plugin",
|
||||
dll_path,
|
||||
"FileOptions:SystemExcludeSearchPatterns:0=**/.git",
|
||||
"FileOptions:SystemExcludeSearchPatterns:1=**/.svn",
|
||||
"FileOptions:SystemExcludeSearchPatterns:2=**/.hg",
|
||||
"FileOptions:SystemExcludeSearchPatterns:3=**/CVS",
|
||||
"FileOptions:SystemExcludeSearchPatterns:4=**/.DS_Store",
|
||||
"FileOptions:SystemExcludeSearchPatterns:5=**/Thumbs.db",
|
||||
"RoslynExtensionsOptions:EnableAnalyzersSupport=true",
|
||||
"FormattingOptions:EnableEditorConfigSupport=true",
|
||||
"RoslynExtensionsOptions:EnableImportCompletion=true",
|
||||
"Sdk:IncludePrereleases=true",
|
||||
"RoslynExtensionsOptions:AnalyzeOpenDocumentsOnly=true",
|
||||
"formattingOptions:useTabs=false",
|
||||
"formattingOptions:tabSize=4",
|
||||
"formattingOptions:indentationSize=4",
|
||||
]
|
||||
)
|
||||
super().__init__(
|
||||
config, logger, repository_root_path, ProcessLaunchInfo(cmd=cmd, cwd=repository_root_path), "csharp"
|
||||
)
|
||||
|
||||
self.definition_available = asyncio.Event()
|
||||
self.references_available = asyncio.Event()
|
||||
|
||||
@override
|
||||
def is_ignored_dirname(self, dirname: str) -> bool:
|
||||
return super().is_ignored_dirname(dirname) or dirname in ["bin", "obj"]
|
||||
|
||||
def _get_initialize_params(self, repository_absolute_path: str) -> InitializeParams:
|
||||
"""
|
||||
Returns the initialize params for the Omnisharp Language Server.
|
||||
"""
|
||||
with open(os.path.join(os.path.dirname(__file__), "initialize_params.json"), "r", encoding="utf-8") as f:
|
||||
d = json.load(f)
|
||||
|
||||
del d["_description"]
|
||||
|
||||
d["processId"] = os.getpid()
|
||||
assert d["rootPath"] == "$rootPath"
|
||||
d["rootPath"] = repository_absolute_path
|
||||
|
||||
assert d["rootUri"] == "$rootUri"
|
||||
d["rootUri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["uri"] == "$uri"
|
||||
d["workspaceFolders"][0]["uri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["name"] == "$name"
|
||||
d["workspaceFolders"][0]["name"] = os.path.basename(repository_absolute_path)
|
||||
|
||||
return d
|
||||
|
||||
def setupRuntimeDependencies(self, logger: MultilspyLogger, config: MultilspyConfig) -> tuple[str, str]:
|
||||
"""
|
||||
Setup runtime dependencies for OmniSharp.
|
||||
"""
|
||||
platform_id = PlatformUtils.get_platform_id()
|
||||
dotnet_version = PlatformUtils.get_dotnet_version()
|
||||
|
||||
with open(os.path.join(os.path.dirname(__file__), "runtime_dependencies.json"), "r", encoding="utf-8") as f:
|
||||
d = json.load(f)
|
||||
del d["_description"]
|
||||
|
||||
assert platform_id in [
|
||||
PlatformId.LINUX_x64,
|
||||
PlatformId.WIN_x64,
|
||||
], "Only linux-x64 and win-x64 platform is supported for in multilspy at the moment"
|
||||
assert dotnet_version in [
|
||||
DotnetVersion.V6,
|
||||
DotnetVersion.V7,
|
||||
DotnetVersion.V8
|
||||
], "Only dotnet version 6 and 7 are supported in multilspy at the moment"
|
||||
|
||||
# TODO: Do away with this assumption
|
||||
# Currently, runtime binaries are not available for .Net 7 and .Net 8. Hence, we assume .Net 6 runtime binaries to be compatible with .Net 7, .Net 8
|
||||
if dotnet_version in [DotnetVersion.V7, DotnetVersion.V8]:
|
||||
dotnet_version = DotnetVersion.V6
|
||||
|
||||
runtime_dependencies = d["runtimeDependencies"]
|
||||
runtime_dependencies = [
|
||||
dependency for dependency in runtime_dependencies if dependency["platformId"] == platform_id.value
|
||||
]
|
||||
runtime_dependencies = [
|
||||
dependency
|
||||
for dependency in runtime_dependencies
|
||||
if not ("dotnet_version" in dependency) or dependency["dotnet_version"] == dotnet_version.value
|
||||
]
|
||||
assert len(runtime_dependencies) == 2
|
||||
runtime_dependencies = {
|
||||
runtime_dependencies[0]["id"]: runtime_dependencies[0],
|
||||
runtime_dependencies[1]["id"]: runtime_dependencies[1],
|
||||
}
|
||||
|
||||
assert "OmniSharp" in runtime_dependencies
|
||||
assert "RazorOmnisharp" in runtime_dependencies
|
||||
|
||||
omnisharp_ls_dir = os.path.join(os.path.dirname(__file__), "static", "OmniSharp")
|
||||
if not os.path.exists(omnisharp_ls_dir):
|
||||
os.makedirs(omnisharp_ls_dir)
|
||||
FileUtils.download_and_extract_archive(
|
||||
logger, runtime_dependencies["OmniSharp"]["url"], omnisharp_ls_dir, "zip"
|
||||
)
|
||||
omnisharp_executable_path = os.path.join(omnisharp_ls_dir, runtime_dependencies["OmniSharp"]["binaryName"])
|
||||
assert os.path.exists(omnisharp_executable_path)
|
||||
os.chmod(omnisharp_executable_path, stat.S_IEXEC)
|
||||
|
||||
razor_omnisharp_ls_dir = os.path.join(os.path.dirname(__file__), "static", "RazorOmnisharp")
|
||||
if not os.path.exists(razor_omnisharp_ls_dir):
|
||||
os.makedirs(razor_omnisharp_ls_dir)
|
||||
FileUtils.download_and_extract_archive(
|
||||
logger, runtime_dependencies["RazorOmnisharp"]["url"], razor_omnisharp_ls_dir, "zip"
|
||||
)
|
||||
razor_omnisharp_dll_path = os.path.join(
|
||||
razor_omnisharp_ls_dir, runtime_dependencies["RazorOmnisharp"]["dll_path"]
|
||||
)
|
||||
assert os.path.exists(razor_omnisharp_dll_path)
|
||||
|
||||
return omnisharp_executable_path, razor_omnisharp_dll_path
|
||||
|
||||
@asynccontextmanager
|
||||
async def start_server(self) -> AsyncIterator["OmniSharp"]:
|
||||
"""
|
||||
Starts the Omnisharp Language Server, waits for the server to be ready and yields the LanguageServer instance.
|
||||
|
||||
Usage:
|
||||
```
|
||||
async with lsp.start_server():
|
||||
# LanguageServer has been initialized and ready to serve requests
|
||||
await lsp.request_definition(...)
|
||||
await lsp.request_references(...)
|
||||
# Shutdown the LanguageServer on exit from scope
|
||||
# LanguageServer has been shutdown
|
||||
"""
|
||||
|
||||
async def register_capability_handler(params):
|
||||
assert "registrations" in params
|
||||
for registration in params["registrations"]:
|
||||
if registration["method"] == "textDocument/definition":
|
||||
self.definition_available.set()
|
||||
if registration["method"] == "textDocument/references":
|
||||
self.references_available.set()
|
||||
if registration["method"] == "textDocument/completion":
|
||||
self.completions_available.set()
|
||||
|
||||
async def lang_status_handler(params):
|
||||
# TODO: Should we wait for
|
||||
# server -> client: {'jsonrpc': '2.0', 'method': 'language/status', 'params': {'type': 'ProjectStatus', 'message': 'OK'}}
|
||||
# Before proceeding?
|
||||
# if params["type"] == "ServiceReady" and params["message"] == "ServiceReady":
|
||||
# self.service_ready_event.set()
|
||||
pass
|
||||
|
||||
async def execute_client_command_handler(params):
|
||||
return []
|
||||
|
||||
async def do_nothing(params):
|
||||
return
|
||||
|
||||
async def check_experimental_status(params):
|
||||
if params["quiescent"] == True:
|
||||
self.server_ready.set()
|
||||
|
||||
async def window_log_message(msg):
|
||||
self.logger.log(f"LSP: window/logMessage: {msg}", logging.INFO)
|
||||
|
||||
async def workspace_configuration_handler(params):
|
||||
# TODO: We do not know the appropriate way to handle this request. Should ideally contact the OmniSharp dev team
|
||||
return [
|
||||
{
|
||||
"RoslynExtensionsOptions": {
|
||||
"EnableDecompilationSupport": False,
|
||||
"EnableAnalyzersSupport": True,
|
||||
"EnableImportCompletion": True,
|
||||
"EnableAsyncCompletion": False,
|
||||
"DocumentAnalysisTimeoutMs": 30000,
|
||||
"DiagnosticWorkersThreadCount": 18,
|
||||
"AnalyzeOpenDocumentsOnly": True,
|
||||
"InlayHintsOptions": {
|
||||
"EnableForParameters": False,
|
||||
"ForLiteralParameters": False,
|
||||
"ForIndexerParameters": False,
|
||||
"ForObjectCreationParameters": False,
|
||||
"ForOtherParameters": False,
|
||||
"SuppressForParametersThatDifferOnlyBySuffix": False,
|
||||
"SuppressForParametersThatMatchMethodIntent": False,
|
||||
"SuppressForParametersThatMatchArgumentName": False,
|
||||
"EnableForTypes": False,
|
||||
"ForImplicitVariableTypes": False,
|
||||
"ForLambdaParameterTypes": False,
|
||||
"ForImplicitObjectCreation": False,
|
||||
},
|
||||
"LocationPaths": None,
|
||||
},
|
||||
"FormattingOptions": {
|
||||
"OrganizeImports": False,
|
||||
"EnableEditorConfigSupport": True,
|
||||
"NewLine": "\n",
|
||||
"UseTabs": False,
|
||||
"TabSize": 4,
|
||||
"IndentationSize": 4,
|
||||
"SpacingAfterMethodDeclarationName": False,
|
||||
"SeparateImportDirectiveGroups": False,
|
||||
"SpaceWithinMethodDeclarationParenthesis": False,
|
||||
"SpaceBetweenEmptyMethodDeclarationParentheses": False,
|
||||
"SpaceAfterMethodCallName": False,
|
||||
"SpaceWithinMethodCallParentheses": False,
|
||||
"SpaceBetweenEmptyMethodCallParentheses": False,
|
||||
"SpaceAfterControlFlowStatementKeyword": True,
|
||||
"SpaceWithinExpressionParentheses": False,
|
||||
"SpaceWithinCastParentheses": False,
|
||||
"SpaceWithinOtherParentheses": False,
|
||||
"SpaceAfterCast": False,
|
||||
"SpaceBeforeOpenSquareBracket": False,
|
||||
"SpaceBetweenEmptySquareBrackets": False,
|
||||
"SpaceWithinSquareBrackets": False,
|
||||
"SpaceAfterColonInBaseTypeDeclaration": True,
|
||||
"SpaceAfterComma": True,
|
||||
"SpaceAfterDot": False,
|
||||
"SpaceAfterSemicolonsInForStatement": True,
|
||||
"SpaceBeforeColonInBaseTypeDeclaration": True,
|
||||
"SpaceBeforeComma": False,
|
||||
"SpaceBeforeDot": False,
|
||||
"SpaceBeforeSemicolonsInForStatement": False,
|
||||
"SpacingAroundBinaryOperator": "single",
|
||||
"IndentBraces": False,
|
||||
"IndentBlock": True,
|
||||
"IndentSwitchSection": True,
|
||||
"IndentSwitchCaseSection": True,
|
||||
"IndentSwitchCaseSectionWhenBlock": True,
|
||||
"LabelPositioning": "oneLess",
|
||||
"WrappingPreserveSingleLine": True,
|
||||
"WrappingKeepStatementsOnSingleLine": True,
|
||||
"NewLinesForBracesInTypes": True,
|
||||
"NewLinesForBracesInMethods": True,
|
||||
"NewLinesForBracesInProperties": True,
|
||||
"NewLinesForBracesInAccessors": True,
|
||||
"NewLinesForBracesInAnonymousMethods": True,
|
||||
"NewLinesForBracesInControlBlocks": True,
|
||||
"NewLinesForBracesInAnonymousTypes": True,
|
||||
"NewLinesForBracesInObjectCollectionArrayInitializers": True,
|
||||
"NewLinesForBracesInLambdaExpressionBody": True,
|
||||
"NewLineForElse": True,
|
||||
"NewLineForCatch": True,
|
||||
"NewLineForFinally": True,
|
||||
"NewLineForMembersInObjectInit": True,
|
||||
"NewLineForMembersInAnonymousTypes": True,
|
||||
"NewLineForClausesInQuery": True,
|
||||
},
|
||||
"FileOptions": {
|
||||
"SystemExcludeSearchPatterns": [
|
||||
"**/node_modules/**/*",
|
||||
"**/bin/**/*",
|
||||
"**/obj/**/*",
|
||||
"**/.git/**/*",
|
||||
"**/.git",
|
||||
"**/.svn",
|
||||
"**/.hg",
|
||||
"**/CVS",
|
||||
"**/.DS_Store",
|
||||
"**/Thumbs.db",
|
||||
],
|
||||
"ExcludeSearchPatterns": [],
|
||||
},
|
||||
"RenameOptions": {
|
||||
"RenameOverloads": False,
|
||||
"RenameInStrings": False,
|
||||
"RenameInComments": False,
|
||||
},
|
||||
"ImplementTypeOptions": {
|
||||
"InsertionBehavior": 0,
|
||||
"PropertyGenerationBehavior": 0,
|
||||
},
|
||||
"DotNetCliOptions": {"LocationPaths": None},
|
||||
"Plugins": {"LocationPaths": None},
|
||||
}
|
||||
]
|
||||
|
||||
self.server.on_request("client/registerCapability", register_capability_handler)
|
||||
self.server.on_notification("language/status", lang_status_handler)
|
||||
self.server.on_notification("window/logMessage", window_log_message)
|
||||
self.server.on_request("workspace/executeClientCommand", execute_client_command_handler)
|
||||
self.server.on_notification("$/progress", do_nothing)
|
||||
self.server.on_notification("textDocument/publishDiagnostics", do_nothing)
|
||||
self.server.on_notification("language/actionableNotification", do_nothing)
|
||||
self.server.on_notification("experimental/serverStatus", check_experimental_status)
|
||||
self.server.on_request("workspace/configuration", workspace_configuration_handler)
|
||||
|
||||
async with super().start_server():
|
||||
self.logger.log("Starting OmniSharp server process", logging.INFO)
|
||||
await self.server.start()
|
||||
initialize_params = self._get_initialize_params(self.repository_root_path)
|
||||
|
||||
self.logger.log(
|
||||
"Sending initialize request from LSP client to LSP server and awaiting response",
|
||||
logging.INFO,
|
||||
)
|
||||
init_response = await self.server.send.initialize(initialize_params)
|
||||
self.server.notify.initialized({})
|
||||
with open(os.path.join(os.path.dirname(__file__), "workspace_did_change_configuration.json"), "r", encoding="utf-8") as f:
|
||||
self.server.notify.workspace_did_change_configuration({
|
||||
"settings": json.load(f)
|
||||
})
|
||||
assert "capabilities" in init_response
|
||||
if (
|
||||
"definitionProvider" in init_response["capabilities"]
|
||||
and init_response["capabilities"]["definitionProvider"]
|
||||
):
|
||||
self.definition_available.set()
|
||||
if (
|
||||
"referencesProvider" in init_response["capabilities"]
|
||||
and init_response["capabilities"]["referencesProvider"]
|
||||
):
|
||||
self.references_available.set()
|
||||
|
||||
await self.definition_available.wait()
|
||||
await self.references_available.wait()
|
||||
|
||||
yield self
|
||||
@@ -0,0 +1,441 @@
|
||||
{
|
||||
"_description": "Used to download the runtime dependencies for running OmniSharp. Obtained from https://github.com/dotnet/vscode-csharp/blob/main/package.json",
|
||||
"runtimeDependencies": [
|
||||
{
|
||||
"id": "OmniSharp",
|
||||
"description": "OmniSharp for Windows (.NET 4 / x86)",
|
||||
"url": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.10/omnisharp-win-x86-1.39.10.zip",
|
||||
"installPath": ".omnisharp/1.39.10",
|
||||
"platforms": [
|
||||
"win32"
|
||||
],
|
||||
"architectures": [
|
||||
"x86"
|
||||
],
|
||||
"installTestPath": "./.omnisharp/1.39.10/OmniSharp.exe",
|
||||
"platformId": "win-x86",
|
||||
"isFramework": true,
|
||||
"integrity": "C81CE2099AD494EF63F9D88FAA70D55A68CF175810F944526FF94AAC7A5109F9",
|
||||
"dotnet_version": "4",
|
||||
"binaryName": "OmniSharp.exe"
|
||||
},
|
||||
{
|
||||
"id": "OmniSharp",
|
||||
"description": "OmniSharp for Windows (.NET 6 / x86)",
|
||||
"url": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.10/omnisharp-win-x86-net6.0-1.39.10.zip",
|
||||
"installPath": ".omnisharp/1.39.10-net6.0",
|
||||
"platforms": [
|
||||
"win32"
|
||||
],
|
||||
"architectures": [
|
||||
"x86"
|
||||
],
|
||||
"installTestPath": "./.omnisharp/1.39.10-net6.0/OmniSharp.dll",
|
||||
"platformId": "win-x86",
|
||||
"isFramework": false,
|
||||
"integrity": "B7E62415CFC3DAC2154AC636C5BF0FB4B2C9BBF11B5A1FBF72381DDDED59791E",
|
||||
"dotnet_version": "6",
|
||||
"binaryName": "OmniSharp.exe"
|
||||
},
|
||||
{
|
||||
"id": "OmniSharp",
|
||||
"description": "OmniSharp for Windows (.NET 4 / x64)",
|
||||
"url": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.10/omnisharp-win-x64-1.39.10.zip",
|
||||
"installPath": ".omnisharp/1.39.10",
|
||||
"platforms": [
|
||||
"win32"
|
||||
],
|
||||
"architectures": [
|
||||
"x86_64"
|
||||
],
|
||||
"installTestPath": "./.omnisharp/1.39.10/OmniSharp.exe",
|
||||
"platformId": "win-x64",
|
||||
"isFramework": true,
|
||||
"integrity": "BE0ED10AACEA17E14B78BD0D887DE5935D4ECA3712192A701F3F2100CA3C8B6E",
|
||||
"dotnet_version": "4",
|
||||
"binaryName": "OmniSharp.exe"
|
||||
},
|
||||
{
|
||||
"id": "OmniSharp",
|
||||
"description": "OmniSharp for Windows (.NET 6 / x64)",
|
||||
"url": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.10/omnisharp-win-x64-net6.0-1.39.10.zip",
|
||||
"installPath": ".omnisharp/1.39.10-net6.0",
|
||||
"platforms": [
|
||||
"win32"
|
||||
],
|
||||
"architectures": [
|
||||
"x86_64"
|
||||
],
|
||||
"installTestPath": "./.omnisharp/1.39.10-net6.0/OmniSharp.dll",
|
||||
"platformId": "win-x64",
|
||||
"isFramework": false,
|
||||
"integrity": "A73327395E7EF92C1D8E307055463DA412662C03F077ECC743462FD2760BB537",
|
||||
"dotnet_version": "6",
|
||||
"binaryName": "OmniSharp.exe"
|
||||
},
|
||||
{
|
||||
"id": "OmniSharp",
|
||||
"description": "OmniSharp for Windows (.NET 4 / arm64)",
|
||||
"url": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.10/omnisharp-win-arm64-1.39.10.zip",
|
||||
"installPath": ".omnisharp/1.39.10",
|
||||
"platforms": [
|
||||
"win32"
|
||||
],
|
||||
"architectures": [
|
||||
"arm64"
|
||||
],
|
||||
"installTestPath": "./.omnisharp/1.39.10/OmniSharp.exe",
|
||||
"platformId": "win-arm64",
|
||||
"isFramework": true,
|
||||
"integrity": "32FA0067B0639F87760CD1A769B16E6A53588C137C4D31661836CA4FB28D3DD6",
|
||||
"dotnet_version": "4",
|
||||
"binaryName": "OmniSharp.exe"
|
||||
},
|
||||
{
|
||||
"id": "OmniSharp",
|
||||
"description": "OmniSharp for Windows (.NET 6 / arm64)",
|
||||
"url": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.10/omnisharp-win-arm64-net6.0-1.39.10.zip",
|
||||
"installPath": ".omnisharp/1.39.10-net6.0",
|
||||
"platforms": [
|
||||
"win32"
|
||||
],
|
||||
"architectures": [
|
||||
"arm64"
|
||||
],
|
||||
"installTestPath": "./.omnisharp/1.39.10-net6.0/OmniSharp.dll",
|
||||
"platformId": "win-arm64",
|
||||
"isFramework": false,
|
||||
"integrity": "433F9B360CAA7B4DDD85C604D5C5542C1A718BCF2E71B2BCFC7526E6D41F4E8F",
|
||||
"dotnet_version": "6",
|
||||
"binaryName": "OmniSharp.exe"
|
||||
},
|
||||
{
|
||||
"id": "OmniSharp",
|
||||
"description": "OmniSharp for OSX (Mono / x64)",
|
||||
"url": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.10/omnisharp-osx-1.39.10.zip",
|
||||
"installPath": ".omnisharp/1.39.10",
|
||||
"platforms": [
|
||||
"darwin"
|
||||
],
|
||||
"architectures": [
|
||||
"x86_64",
|
||||
"arm64"
|
||||
],
|
||||
"binaries": [
|
||||
"./mono.osx",
|
||||
"./run"
|
||||
],
|
||||
"installTestPath": "./.omnisharp/1.39.10/run",
|
||||
"platformId": "osx",
|
||||
"isFramework": true,
|
||||
"integrity": "2CC42F0EC7C30CFA8858501D12ECB6FB685A1FCFB8ECB35698A4B12406551968",
|
||||
"dotnet_version": "mono"
|
||||
},
|
||||
{
|
||||
"id": "OmniSharp",
|
||||
"description": "OmniSharp for OSX (.NET 6 / x64)",
|
||||
"url": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.10/omnisharp-osx-x64-net6.0-1.39.10.zip",
|
||||
"installPath": ".omnisharp/1.39.10-net6.0",
|
||||
"platforms": [
|
||||
"darwin"
|
||||
],
|
||||
"architectures": [
|
||||
"x86_64"
|
||||
],
|
||||
"installTestPath": "./.omnisharp/1.39.10-net6.0/OmniSharp.dll",
|
||||
"platformId": "osx-x64",
|
||||
"isFramework": false,
|
||||
"integrity": "C9D6E9F2C839A66A7283AE6A9EC545EE049B48EB230D33E91A6322CB67FF9D97",
|
||||
"dotnet_version": "6"
|
||||
},
|
||||
{
|
||||
"id": "OmniSharp",
|
||||
"description": "OmniSharp for OSX (.NET 6 / arm64)",
|
||||
"url": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.10/omnisharp-osx-arm64-net6.0-1.39.10.zip",
|
||||
"installPath": ".omnisharp/1.39.10-net6.0",
|
||||
"platforms": [
|
||||
"darwin"
|
||||
],
|
||||
"architectures": [
|
||||
"arm64"
|
||||
],
|
||||
"installTestPath": "./.omnisharp/1.39.10-net6.0/OmniSharp.dll",
|
||||
"platformId": "osx-arm64",
|
||||
"isFramework": false,
|
||||
"integrity": "851350F52F83E3BAD5A92D113E4B9882FCD1DEB16AA84FF94B6F2CEE3C70051E",
|
||||
"dotnet_version": "6"
|
||||
},
|
||||
{
|
||||
"id": "OmniSharp",
|
||||
"description": "OmniSharp for Linux (Mono / x86)",
|
||||
"url": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.10/omnisharp-linux-x86-1.39.10.zip",
|
||||
"installPath": ".omnisharp/1.39.10",
|
||||
"platforms": [
|
||||
"linux"
|
||||
],
|
||||
"architectures": [
|
||||
"x86",
|
||||
"i686"
|
||||
],
|
||||
"binaries": [
|
||||
"./mono.linux-x86",
|
||||
"./run"
|
||||
],
|
||||
"installTestPath": "./.omnisharp/1.39.10/run",
|
||||
"platformId": "linux-x86",
|
||||
"isFramework": true,
|
||||
"integrity": "474B1CDBAE64CFEC655FB6B0659BCE481023C48274441C72991E67B6E13E56A1",
|
||||
"dotnet_version": "mono"
|
||||
},
|
||||
{
|
||||
"id": "OmniSharp",
|
||||
"description": "OmniSharp for Linux (Mono / x64)",
|
||||
"url": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.10/omnisharp-linux-x64-1.39.10.zip",
|
||||
"installPath": ".omnisharp/1.39.10",
|
||||
"platforms": [
|
||||
"linux"
|
||||
],
|
||||
"architectures": [
|
||||
"x86_64"
|
||||
],
|
||||
"binaries": [
|
||||
"./mono.linux-x86_64",
|
||||
"./run"
|
||||
],
|
||||
"installTestPath": "./.omnisharp/1.39.10/run",
|
||||
"platformId": "linux-x64",
|
||||
"isFramework": true,
|
||||
"integrity": "FB4CAA47343265100349375D79DBCCE1868950CED675CB07FCBE8462EDBCDD37",
|
||||
"dotnet_version": "mono"
|
||||
},
|
||||
{
|
||||
"id": "OmniSharp",
|
||||
"description": "OmniSharp for Linux (.NET 6 / x64)",
|
||||
"url": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.10/omnisharp-linux-x64-net6.0-1.39.10.zip",
|
||||
"installPath": ".omnisharp/1.39.10-net6.0",
|
||||
"platforms": [
|
||||
"linux"
|
||||
],
|
||||
"architectures": [
|
||||
"x86_64"
|
||||
],
|
||||
"installTestPath": "./.omnisharp/1.39.10-net6.0/OmniSharp.dll",
|
||||
"platformId": "linux-x64",
|
||||
"isFramework": false,
|
||||
"integrity": "0926D3BEA060BF4373356B2FC0A68C10D0DE1B1150100B551BA5932814CE51E2",
|
||||
"dotnet_version": "6",
|
||||
"binaryName": "OmniSharp"
|
||||
},
|
||||
{
|
||||
"id": "OmniSharp",
|
||||
"description": "OmniSharp for Linux (Mono / arm64)",
|
||||
"url": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.10/omnisharp-linux-arm64-1.39.10.zip",
|
||||
"installPath": ".omnisharp/1.39.10",
|
||||
"platforms": [
|
||||
"linux"
|
||||
],
|
||||
"architectures": [
|
||||
"arm64"
|
||||
],
|
||||
"binaries": [
|
||||
"./mono.linux-arm64",
|
||||
"./run"
|
||||
],
|
||||
"installTestPath": "./.omnisharp/1.39.10/run",
|
||||
"platformId": "linux-arm64",
|
||||
"isFramework": true,
|
||||
"integrity": "478F3594DFD0167E9A56E36F0364A86C73F8132A3E7EA916CA1419EFE141D2CC",
|
||||
"dotnet_version": "mono"
|
||||
},
|
||||
{
|
||||
"id": "OmniSharp",
|
||||
"description": "OmniSharp for Linux (.NET 6 / arm64)",
|
||||
"url": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.10/omnisharp-linux-arm64-net6.0-1.39.10.zip",
|
||||
"installPath": ".omnisharp/1.39.10-net6.0",
|
||||
"platforms": [
|
||||
"linux"
|
||||
],
|
||||
"architectures": [
|
||||
"arm64"
|
||||
],
|
||||
"installTestPath": "./.omnisharp/1.39.10-net6.0/OmniSharp.dll",
|
||||
"platformId": "linux-arm64",
|
||||
"isFramework": false,
|
||||
"integrity": "6FB6A572043A74220A92F6C19C7BB0C3743321C7563A815FD2702EF4FA7D688E",
|
||||
"dotnet_version": "6"
|
||||
},
|
||||
{
|
||||
"id": "OmniSharp",
|
||||
"description": "OmniSharp for Linux musl (.NET 6 / x64)",
|
||||
"url": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.10/omnisharp-linux-musl-x64-net6.0-1.39.10.zip",
|
||||
"installPath": ".omnisharp/1.39.10-net6.0",
|
||||
"platforms": [
|
||||
"linux-musl"
|
||||
],
|
||||
"architectures": [
|
||||
"x86_64"
|
||||
],
|
||||
"installTestPath": "./.omnisharp/1.39.10-net6.0/OmniSharp.dll",
|
||||
"platformId": "linux-musl-x64",
|
||||
"isFramework": false,
|
||||
"integrity": "6BFDA3AD11DBB0C6514B86ECC3E1597CC41C6E309B7575F7C599E07D9E2AE610",
|
||||
"dotnet_version": "6"
|
||||
},
|
||||
{
|
||||
"id": "OmniSharp",
|
||||
"description": "OmniSharp for Linux musl (.NET 6 / arm64)",
|
||||
"url": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.10/omnisharp-linux-musl-arm64-net6.0-1.39.10.zip",
|
||||
"installPath": ".omnisharp/1.39.10-net6.0",
|
||||
"platforms": [
|
||||
"linux-musl"
|
||||
],
|
||||
"architectures": [
|
||||
"arm64"
|
||||
],
|
||||
"installTestPath": "./.omnisharp/1.39.10-net6.0/OmniSharp.dll",
|
||||
"platformId": "linux-musl-arm64",
|
||||
"isFramework": false,
|
||||
"integrity": "DA63619EA024EB9BBF6DB5A85C6150CAB5C0BD554544A3596ED1B17F926D6875",
|
||||
"dotnet_version": "6"
|
||||
},
|
||||
{
|
||||
"id": "RazorOmnisharp",
|
||||
"description": "Razor Language Server for OmniSharp (Windows / x64)",
|
||||
"url": "https://download.visualstudio.microsoft.com/download/pr/aee63398-023f-48db-bba2-30162c68f0c4/8d42e62ea4051381c219b3e31bc4eced/razorlanguageserver-win-x64-7.0.0-preview.23363.1.zip",
|
||||
"installPath": ".razoromnisharp",
|
||||
"platforms": [
|
||||
"win32"
|
||||
],
|
||||
"architectures": [
|
||||
"x86_64"
|
||||
],
|
||||
"platformId": "win-x64",
|
||||
"dll_path": "OmniSharpPlugin/Microsoft.AspNetCore.Razor.OmniSharpPlugin.dll"
|
||||
},
|
||||
{
|
||||
"id": "RazorOmnisharp",
|
||||
"description": "Razor Language Server for OmniSharp (Windows / x86)",
|
||||
"url": "https://download.visualstudio.microsoft.com/download/pr/aee63398-023f-48db-bba2-30162c68f0c4/e440c4f3a4a96334fe177513935fa010/razorlanguageserver-win-x86-7.0.0-preview.23363.1.zip",
|
||||
"installPath": ".razoromnisharp",
|
||||
"platforms": [
|
||||
"win32"
|
||||
],
|
||||
"architectures": [
|
||||
"x86"
|
||||
],
|
||||
"platformId": "win-x86",
|
||||
"dll_path": "OmniSharpPlugin/Microsoft.AspNetCore.Razor.OmniSharpPlugin.dll"
|
||||
},
|
||||
{
|
||||
"id": "RazorOmnisharp",
|
||||
"description": "Razor Language Server for OmniSharp (Windows / ARM64)",
|
||||
"url": "https://download.visualstudio.microsoft.com/download/pr/aee63398-023f-48db-bba2-30162c68f0c4/4ef26e45cf32fe8d51c0e7dd21f1fef6/razorlanguageserver-win-arm64-7.0.0-preview.23363.1.zip",
|
||||
"installPath": ".razoromnisharp",
|
||||
"platforms": [
|
||||
"win32"
|
||||
],
|
||||
"architectures": [
|
||||
"arm64"
|
||||
],
|
||||
"platformId": "win-arm64",
|
||||
"dll_path": "OmniSharpPlugin/Microsoft.AspNetCore.Razor.OmniSharpPlugin.dll"
|
||||
},
|
||||
{
|
||||
"id": "RazorOmnisharp",
|
||||
"description": "Razor Language Server for OmniSharp (Linux / x64)",
|
||||
"url": "https://download.visualstudio.microsoft.com/download/pr/aee63398-023f-48db-bba2-30162c68f0c4/6d4e23a3c7cf0465743950a39515a716/razorlanguageserver-linux-x64-7.0.0-preview.23363.1.zip",
|
||||
"installPath": ".razoromnisharp",
|
||||
"platforms": [
|
||||
"linux"
|
||||
],
|
||||
"architectures": [
|
||||
"x86_64"
|
||||
],
|
||||
"binaries": [
|
||||
"./rzls"
|
||||
],
|
||||
"platformId": "linux-x64",
|
||||
"dll_path": "OmniSharpPlugin/Microsoft.AspNetCore.Razor.OmniSharpPlugin.dll"
|
||||
},
|
||||
{
|
||||
"id": "RazorOmnisharp",
|
||||
"description": "Razor Language Server for OmniSharp (Linux ARM64)",
|
||||
"url": "https://download.visualstudio.microsoft.com/download/pr/aee63398-023f-48db-bba2-30162c68f0c4/85deebd44647ebf65724cc291d722283/razorlanguageserver-linux-arm64-7.0.0-preview.23363.1.zip",
|
||||
"installPath": ".razoromnisharp",
|
||||
"platforms": [
|
||||
"linux"
|
||||
],
|
||||
"architectures": [
|
||||
"arm64"
|
||||
],
|
||||
"binaries": [
|
||||
"./rzls"
|
||||
],
|
||||
"platformId": "linux-arm64"
|
||||
},
|
||||
{
|
||||
"id": "RazorOmnisharp",
|
||||
"description": "Razor Language Server for OmniSharp (Linux musl / x64)",
|
||||
"url": "https://download.visualstudio.microsoft.com/download/pr/aee63398-023f-48db-bba2-30162c68f0c4/4f0caa94ae182785655efb15eafcef23/razorlanguageserver-linux-musl-x64-7.0.0-preview.23363.1.zip",
|
||||
"installPath": ".razoromnisharp",
|
||||
"platforms": [
|
||||
"linux-musl"
|
||||
],
|
||||
"architectures": [
|
||||
"x86_64"
|
||||
],
|
||||
"binaries": [
|
||||
"./rzls"
|
||||
],
|
||||
"platformId": "linux-musl-x64"
|
||||
},
|
||||
{
|
||||
"id": "RazorOmnisharp",
|
||||
"description": "Razor Language Server for OmniSharp (Linux musl ARM64)",
|
||||
"url": "https://download.visualstudio.microsoft.com/download/pr/aee63398-023f-48db-bba2-30162c68f0c4/0a24828206a6f3b4bc743d058ef88ce7/razorlanguageserver-linux-musl-arm64-7.0.0-preview.23363.1.zip",
|
||||
"installPath": ".razoromnisharp",
|
||||
"platforms": [
|
||||
"linux-musl"
|
||||
],
|
||||
"architectures": [
|
||||
"arm64"
|
||||
],
|
||||
"binaries": [
|
||||
"./rzls"
|
||||
],
|
||||
"platformId": "linux-musl-arm64"
|
||||
},
|
||||
{
|
||||
"id": "RazorOmnisharp",
|
||||
"description": "Razor Language Server for OmniSharp (macOS / x64)",
|
||||
"url": "https://download.visualstudio.microsoft.com/download/pr/aee63398-023f-48db-bba2-30162c68f0c4/2afcafaf41082989efcc10405abb9314/razorlanguageserver-osx-x64-7.0.0-preview.23363.1.zip",
|
||||
"installPath": ".razoromnisharp",
|
||||
"platforms": [
|
||||
"darwin"
|
||||
],
|
||||
"architectures": [
|
||||
"x86_64"
|
||||
],
|
||||
"binaries": [
|
||||
"./rzls"
|
||||
],
|
||||
"platformId": "osx-x64"
|
||||
},
|
||||
{
|
||||
"id": "RazorOmnisharp",
|
||||
"description": "Razor Language Server for OmniSharp (macOS ARM64)",
|
||||
"url": "https://download.visualstudio.microsoft.com/download/pr/aee63398-023f-48db-bba2-30162c68f0c4/8bf2ed2f00d481a5987e3eb5165afddd/razorlanguageserver-osx-arm64-7.0.0-preview.23363.1.zip",
|
||||
"installPath": ".razoromnisharp",
|
||||
"platforms": [
|
||||
"darwin"
|
||||
],
|
||||
"architectures": [
|
||||
"arm64"
|
||||
],
|
||||
"binaries": [
|
||||
"./rzls"
|
||||
],
|
||||
"platformId": "osx-arm64"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
{
|
||||
"RoslynExtensionsOptions": {
|
||||
"EnableDecompilationSupport": false,
|
||||
"EnableAnalyzersSupport": true,
|
||||
"EnableImportCompletion": true,
|
||||
"EnableAsyncCompletion": false,
|
||||
"DocumentAnalysisTimeoutMs": 30000,
|
||||
"DiagnosticWorkersThreadCount": 18,
|
||||
"AnalyzeOpenDocumentsOnly": true,
|
||||
"InlayHintsOptions": {
|
||||
"EnableForParameters": false,
|
||||
"ForLiteralParameters": false,
|
||||
"ForIndexerParameters": false,
|
||||
"ForObjectCreationParameters": false,
|
||||
"ForOtherParameters": false,
|
||||
"SuppressForParametersThatDifferOnlyBySuffix": false,
|
||||
"SuppressForParametersThatMatchMethodIntent": false,
|
||||
"SuppressForParametersThatMatchArgumentName": false,
|
||||
"EnableForTypes": false,
|
||||
"ForImplicitVariableTypes": false,
|
||||
"ForLambdaParameterTypes": false,
|
||||
"ForImplicitObjectCreation": false
|
||||
},
|
||||
"LocationPaths": null
|
||||
},
|
||||
"FormattingOptions": {
|
||||
"OrganizeImports": false,
|
||||
"EnableEditorConfigSupport": true,
|
||||
"NewLine": "\n",
|
||||
"UseTabs": false,
|
||||
"TabSize": 4,
|
||||
"IndentationSize": 4,
|
||||
"SpacingAfterMethodDeclarationName": false,
|
||||
"SeparateImportDirectiveGroups": false,
|
||||
"SpaceWithinMethodDeclarationParenthesis": false,
|
||||
"SpaceBetweenEmptyMethodDeclarationParentheses": false,
|
||||
"SpaceAfterMethodCallName": false,
|
||||
"SpaceWithinMethodCallParentheses": false,
|
||||
"SpaceBetweenEmptyMethodCallParentheses": false,
|
||||
"SpaceAfterControlFlowStatementKeyword": true,
|
||||
"SpaceWithinExpressionParentheses": false,
|
||||
"SpaceWithinCastParentheses": false,
|
||||
"SpaceWithinOtherParentheses": false,
|
||||
"SpaceAfterCast": false,
|
||||
"SpaceBeforeOpenSquareBracket": false,
|
||||
"SpaceBetweenEmptySquareBrackets": false,
|
||||
"SpaceWithinSquareBrackets": false,
|
||||
"SpaceAfterColonInBaseTypeDeclaration": true,
|
||||
"SpaceAfterComma": true,
|
||||
"SpaceAfterDot": false,
|
||||
"SpaceAfterSemicolonsInForStatement": true,
|
||||
"SpaceBeforeColonInBaseTypeDeclaration": true,
|
||||
"SpaceBeforeComma": false,
|
||||
"SpaceBeforeDot": false,
|
||||
"SpaceBeforeSemicolonsInForStatement": false,
|
||||
"SpacingAroundBinaryOperator": "single",
|
||||
"IndentBraces": false,
|
||||
"IndentBlock": true,
|
||||
"IndentSwitchSection": true,
|
||||
"IndentSwitchCaseSection": true,
|
||||
"IndentSwitchCaseSectionWhenBlock": true,
|
||||
"LabelPositioning": "oneLess",
|
||||
"WrappingPreserveSingleLine": true,
|
||||
"WrappingKeepStatementsOnSingleLine": true,
|
||||
"NewLinesForBracesInTypes": true,
|
||||
"NewLinesForBracesInMethods": true,
|
||||
"NewLinesForBracesInProperties": true,
|
||||
"NewLinesForBracesInAccessors": true,
|
||||
"NewLinesForBracesInAnonymousMethods": true,
|
||||
"NewLinesForBracesInControlBlocks": true,
|
||||
"NewLinesForBracesInAnonymousTypes": true,
|
||||
"NewLinesForBracesInObjectCollectionArrayInitializers": true,
|
||||
"NewLinesForBracesInLambdaExpressionBody": true,
|
||||
"NewLineForElse": true,
|
||||
"NewLineForCatch": true,
|
||||
"NewLineForFinally": true,
|
||||
"NewLineForMembersInObjectInit": true,
|
||||
"NewLineForMembersInAnonymousTypes": true,
|
||||
"NewLineForClausesInQuery": true
|
||||
},
|
||||
"FileOptions": {
|
||||
"SystemExcludeSearchPatterns": [
|
||||
"**/node_modules/**/*",
|
||||
"**/bin/**/*",
|
||||
"**/obj/**/*",
|
||||
"**/.git/**/*",
|
||||
"**/.git",
|
||||
"**/.svn",
|
||||
"**/.hg",
|
||||
"**/CVS",
|
||||
"**/.DS_Store",
|
||||
"**/Thumbs.db"
|
||||
],
|
||||
"ExcludeSearchPatterns": []
|
||||
},
|
||||
"RenameOptions": {
|
||||
"RenameOverloads": false,
|
||||
"RenameInStrings": false,
|
||||
"RenameInComments": false
|
||||
},
|
||||
"ImplementTypeOptions": {
|
||||
"InsertionBehavior": 0,
|
||||
"PropertyGenerationBehavior": 0
|
||||
},
|
||||
"DotNetCliOptions": {
|
||||
"LocationPaths": null
|
||||
},
|
||||
"Plugins": {
|
||||
"LocationPaths": null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
"""
|
||||
Provides Python specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Python.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import AsyncIterator, Tuple
|
||||
|
||||
from overrides import override
|
||||
|
||||
from multilspy.multilspy_logger import MultilspyLogger
|
||||
from multilspy.language_server import LanguageServer
|
||||
from multilspy.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from multilspy.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from multilspy.multilspy_config import MultilspyConfig
|
||||
|
||||
|
||||
class PyrightServer(LanguageServer):
|
||||
"""
|
||||
Provides Python specific instantiation of the LanguageServer class using Pyright.
|
||||
Contains various configurations and settings specific to Python.
|
||||
"""
|
||||
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
|
||||
"""
|
||||
Creates a PyrightServer instance. This class is not meant to be instantiated directly.
|
||||
Use LanguageServer.create() instead.
|
||||
"""
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
# Note 1: we can also use `pyright-langserver --stdio` but it requires pyright to be installed with npm
|
||||
# Note 2: we can also use `bpyright-langserver --stdio` if we ever are unhappy with pyright
|
||||
ProcessLaunchInfo(cmd="python -m pyright.langserver --stdio", cwd=repository_root_path),
|
||||
"python",
|
||||
)
|
||||
|
||||
# Event to signal when initial workspace analysis is complete
|
||||
self.analysis_complete = asyncio.Event()
|
||||
self.found_source_files = False
|
||||
|
||||
@override
|
||||
def is_ignored_dirname(self, dirname: str) -> bool:
|
||||
return super().is_ignored_dirname(dirname) or dirname in ["venv", "__pycache__"]
|
||||
|
||||
def _get_initialize_params(self, repository_absolute_path: str) -> InitializeParams:
|
||||
"""
|
||||
Returns the initialize params for the Pyright Language Server.
|
||||
"""
|
||||
# Create basic initialization parameters
|
||||
initialize_params: InitializeParams = { # type: ignore
|
||||
"processId": os.getpid(),
|
||||
"rootPath": repository_absolute_path,
|
||||
"rootUri": pathlib.Path(repository_absolute_path).as_uri(),
|
||||
"initializationOptions": {
|
||||
"exclude": [
|
||||
"**/__pycache__",
|
||||
"**/.venv",
|
||||
"**/.env",
|
||||
"**/build",
|
||||
"**/dist",
|
||||
"**/.pixi",
|
||||
],
|
||||
"reportMissingImports": "error",
|
||||
},
|
||||
"capabilities": {
|
||||
"workspace": {
|
||||
"applyEdit": True,
|
||||
"workspaceEdit": {"documentChanges": True},
|
||||
"didChangeConfiguration": {"dynamicRegistration": True},
|
||||
"didChangeWatchedFiles": {"dynamicRegistration": True},
|
||||
"symbol": {
|
||||
"dynamicRegistration": True,
|
||||
"symbolKind": {
|
||||
"valueSet": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]
|
||||
},
|
||||
},
|
||||
"executeCommand": {"dynamicRegistration": True},
|
||||
},
|
||||
"textDocument": {
|
||||
"synchronization": {"dynamicRegistration": True, "willSave": True, "willSaveWaitUntil": True, "didSave": True},
|
||||
"completion": {
|
||||
"dynamicRegistration": True,
|
||||
"contextSupport": True,
|
||||
"completionItem": {
|
||||
"snippetSupport": True,
|
||||
"commitCharactersSupport": True,
|
||||
"documentationFormat": ["markdown", "plaintext"],
|
||||
"deprecatedSupport": True,
|
||||
"preselectSupport": True,
|
||||
},
|
||||
"completionItemKind": {
|
||||
"valueSet": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
|
||||
},
|
||||
},
|
||||
"hover": {"dynamicRegistration": True, "contentFormat": ["markdown", "plaintext"]},
|
||||
"signatureHelp": {
|
||||
"dynamicRegistration": True,
|
||||
"signatureInformation": {
|
||||
"documentationFormat": ["markdown", "plaintext"],
|
||||
"parameterInformation": {"labelOffsetSupport": True},
|
||||
},
|
||||
},
|
||||
"definition": {"dynamicRegistration": True},
|
||||
"references": {"dynamicRegistration": True},
|
||||
"documentHighlight": {"dynamicRegistration": True},
|
||||
"documentSymbol": {
|
||||
"dynamicRegistration": True,
|
||||
"symbolKind": {
|
||||
"valueSet": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]
|
||||
},
|
||||
"hierarchicalDocumentSymbolSupport": True,
|
||||
},
|
||||
"codeAction": {
|
||||
"dynamicRegistration": True,
|
||||
"codeActionLiteralSupport": {
|
||||
"codeActionKind": {
|
||||
"valueSet": [
|
||||
"",
|
||||
"quickfix",
|
||||
"refactor",
|
||||
"refactor.extract",
|
||||
"refactor.inline",
|
||||
"refactor.rewrite",
|
||||
"source",
|
||||
"source.organizeImports",
|
||||
]
|
||||
}
|
||||
},
|
||||
},
|
||||
"codeLens": {"dynamicRegistration": True},
|
||||
"formatting": {"dynamicRegistration": True},
|
||||
"rangeFormatting": {"dynamicRegistration": True},
|
||||
"onTypeFormatting": {"dynamicRegistration": True},
|
||||
"rename": {"dynamicRegistration": True},
|
||||
"publishDiagnostics": {"relatedInformation": True},
|
||||
},
|
||||
},
|
||||
"workspaceFolders": [
|
||||
{"uri": pathlib.Path(repository_absolute_path).as_uri(), "name": os.path.basename(repository_absolute_path)}
|
||||
],
|
||||
}
|
||||
|
||||
return initialize_params
|
||||
|
||||
@asynccontextmanager
|
||||
async def start_server(self) -> AsyncIterator["PyrightServer"]:
|
||||
"""
|
||||
Starts the Pyright Language Server and waits for initial workspace analysis to complete.
|
||||
|
||||
This prevents zombie processes by ensuring Pyright has finished its initial background
|
||||
tasks before we consider the server ready.
|
||||
|
||||
Usage:
|
||||
```
|
||||
async with lsp.start_server():
|
||||
# LanguageServer has been initialized and workspace analysis is complete
|
||||
await lsp.request_definition(...)
|
||||
await lsp.request_references(...)
|
||||
# Shutdown the LanguageServer on exit from scope
|
||||
# LanguageServer has been shutdown cleanly
|
||||
```
|
||||
"""
|
||||
|
||||
async def execute_client_command_handler(params):
|
||||
return []
|
||||
|
||||
async def do_nothing(params):
|
||||
return
|
||||
|
||||
async def window_log_message(msg):
|
||||
"""
|
||||
Monitor Pyright's log messages to detect when initial analysis is complete.
|
||||
Pyright logs "Found X source files" when it finishes scanning the workspace.
|
||||
"""
|
||||
message_text = msg.get("message", "")
|
||||
self.logger.log(f"LSP: window/logMessage: {message_text}", logging.INFO)
|
||||
|
||||
# Look for "Found X source files" which indicates workspace scanning is complete
|
||||
# Unfortunately, pyright is unreliable and there seems to be no better way
|
||||
if re.search(r"Found \d+ source files?", message_text):
|
||||
self.logger.log("Pyright workspace scanning complete", logging.INFO)
|
||||
self.found_source_files = True
|
||||
self.analysis_complete.set()
|
||||
self.completions_available.set()
|
||||
|
||||
async def check_experimental_status(params):
|
||||
"""
|
||||
Also listen for experimental/serverStatus as a backup signal
|
||||
"""
|
||||
if params.get("quiescent") == True:
|
||||
self.logger.log("Received experimental/serverStatus with quiescent=true", logging.INFO)
|
||||
if not self.found_source_files:
|
||||
self.analysis_complete.set()
|
||||
self.completions_available.set()
|
||||
|
||||
# Set up notification handlers
|
||||
self.server.on_request("client/registerCapability", do_nothing)
|
||||
self.server.on_notification("language/status", do_nothing)
|
||||
self.server.on_notification("window/logMessage", window_log_message)
|
||||
self.server.on_request("workspace/executeClientCommand", execute_client_command_handler)
|
||||
self.server.on_notification("$/progress", do_nothing)
|
||||
self.server.on_notification("textDocument/publishDiagnostics", do_nothing)
|
||||
self.server.on_notification("language/actionableNotification", do_nothing)
|
||||
self.server.on_notification("experimental/serverStatus", check_experimental_status)
|
||||
|
||||
async with super().start_server():
|
||||
self.logger.log("Starting pyright-langserver server process", logging.INFO)
|
||||
await self.server.start()
|
||||
|
||||
# Send proper initialization parameters
|
||||
initialize_params = self._get_initialize_params(self.repository_root_path)
|
||||
|
||||
self.logger.log(
|
||||
"Sending initialize request from LSP client to pyright server and awaiting response",
|
||||
logging.INFO,
|
||||
)
|
||||
init_response = await self.server.send.initialize(initialize_params)
|
||||
self.logger.log(f"Received initialize response from pyright server: {init_response}", logging.INFO)
|
||||
|
||||
# Verify that the server supports our required features
|
||||
assert "textDocumentSync" in init_response["capabilities"]
|
||||
assert "completionProvider" in init_response["capabilities"]
|
||||
assert "definitionProvider" in init_response["capabilities"]
|
||||
|
||||
# Complete the initialization handshake
|
||||
self.server.notify.initialized({})
|
||||
|
||||
# Wait for Pyright to complete its initial workspace analysis
|
||||
# This prevents zombie processes by ensuring background tasks finish
|
||||
self.logger.log("Waiting for Pyright to complete initial workspace analysis...", logging.INFO)
|
||||
try:
|
||||
await asyncio.wait_for(self.analysis_complete.wait(), timeout=1.0)
|
||||
self.logger.log("Pyright initial analysis complete, server ready", logging.INFO)
|
||||
except asyncio.TimeoutError:
|
||||
self.logger.log("Timeout waiting for Pyright analysis completion, proceeding anyway", logging.WARNING)
|
||||
# Fallback: assume analysis is complete after timeout
|
||||
self.analysis_complete.set()
|
||||
self.completions_available.set()
|
||||
|
||||
yield self
|
||||
@@ -0,0 +1,917 @@
|
||||
{
|
||||
"_description": "The parameters sent by the client when initializing the language server with the \"initialize\" request. More details at https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize",
|
||||
"processId": "os.getpid()",
|
||||
"clientInfo": {
|
||||
"name": "Visual Studio Code - Insiders",
|
||||
"version": "1.82.0-insider"
|
||||
},
|
||||
"locale": "en",
|
||||
"rootPath": "$rootPath",
|
||||
"rootUri": "$rootUri",
|
||||
"capabilities": {
|
||||
"workspace": {
|
||||
"applyEdit": true,
|
||||
"workspaceEdit": {
|
||||
"documentChanges": true,
|
||||
"resourceOperations": [
|
||||
"create",
|
||||
"rename",
|
||||
"delete"
|
||||
],
|
||||
"failureHandling": "textOnlyTransactional",
|
||||
"normalizesLineEndings": true,
|
||||
"changeAnnotationSupport": {
|
||||
"groupsOnLabel": true
|
||||
}
|
||||
},
|
||||
"configuration": true,
|
||||
"didChangeWatchedFiles": {
|
||||
"dynamicRegistration": true,
|
||||
"relativePatternSupport": true
|
||||
},
|
||||
"symbol": {
|
||||
"dynamicRegistration": true,
|
||||
"symbolKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26
|
||||
]
|
||||
},
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"location.range"
|
||||
]
|
||||
}
|
||||
},
|
||||
"codeLens": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"executeCommand": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"didChangeConfiguration": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"workspaceFolders": true,
|
||||
"semanticTokens": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"fileOperations": {
|
||||
"dynamicRegistration": true,
|
||||
"didCreate": true,
|
||||
"didRename": true,
|
||||
"didDelete": true,
|
||||
"willCreate": true,
|
||||
"willRename": true,
|
||||
"willDelete": true
|
||||
},
|
||||
"inlineValue": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"inlayHint": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"diagnostics": {
|
||||
"refreshSupport": true
|
||||
}
|
||||
},
|
||||
"textDocument": {
|
||||
"publishDiagnostics": {
|
||||
"relatedInformation": true,
|
||||
"versionSupport": false,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2
|
||||
]
|
||||
},
|
||||
"codeDescriptionSupport": true,
|
||||
"dataSupport": true
|
||||
},
|
||||
"synchronization": {
|
||||
"dynamicRegistration": true,
|
||||
"willSave": true,
|
||||
"willSaveWaitUntil": true,
|
||||
"didSave": true
|
||||
},
|
||||
"completion": {
|
||||
"dynamicRegistration": true,
|
||||
"contextSupport": true,
|
||||
"completionItem": {
|
||||
"snippetSupport": true,
|
||||
"commitCharactersSupport": true,
|
||||
"documentationFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
],
|
||||
"deprecatedSupport": true,
|
||||
"preselectSupport": true,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"insertReplaceSupport": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"documentation",
|
||||
"detail",
|
||||
"additionalTextEdits"
|
||||
]
|
||||
},
|
||||
"insertTextModeSupport": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2
|
||||
]
|
||||
},
|
||||
"labelDetailsSupport": true
|
||||
},
|
||||
"insertTextMode": 2,
|
||||
"completionItemKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25
|
||||
]
|
||||
},
|
||||
"completionList": {
|
||||
"itemDefaults": [
|
||||
"commitCharacters",
|
||||
"editRange",
|
||||
"insertTextFormat",
|
||||
"insertTextMode"
|
||||
]
|
||||
}
|
||||
},
|
||||
"hover": {
|
||||
"dynamicRegistration": true,
|
||||
"contentFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
]
|
||||
},
|
||||
"signatureHelp": {
|
||||
"dynamicRegistration": true,
|
||||
"signatureInformation": {
|
||||
"documentationFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
],
|
||||
"parameterInformation": {
|
||||
"labelOffsetSupport": true
|
||||
},
|
||||
"activeParameterSupport": true
|
||||
},
|
||||
"contextSupport": true
|
||||
},
|
||||
"definition": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"references": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"documentHighlight": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"documentSymbol": {
|
||||
"dynamicRegistration": true,
|
||||
"symbolKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26
|
||||
]
|
||||
},
|
||||
"hierarchicalDocumentSymbolSupport": true,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"labelSupport": true
|
||||
},
|
||||
"codeAction": {
|
||||
"dynamicRegistration": true,
|
||||
"isPreferredSupport": true,
|
||||
"disabledSupport": true,
|
||||
"dataSupport": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"edit"
|
||||
]
|
||||
},
|
||||
"codeActionLiteralSupport": {
|
||||
"codeActionKind": {
|
||||
"valueSet": [
|
||||
"",
|
||||
"quickfix",
|
||||
"refactor",
|
||||
"refactor.extract",
|
||||
"refactor.inline",
|
||||
"refactor.rewrite",
|
||||
"source",
|
||||
"source.organizeImports"
|
||||
]
|
||||
}
|
||||
},
|
||||
"honorsChangeAnnotations": false
|
||||
},
|
||||
"codeLens": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"formatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"rangeFormatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"onTypeFormatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"rename": {
|
||||
"dynamicRegistration": true,
|
||||
"prepareSupport": true,
|
||||
"prepareSupportDefaultBehavior": 1,
|
||||
"honorsChangeAnnotations": true
|
||||
},
|
||||
"documentLink": {
|
||||
"dynamicRegistration": true,
|
||||
"tooltipSupport": true
|
||||
},
|
||||
"typeDefinition": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"implementation": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"colorProvider": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"foldingRange": {
|
||||
"dynamicRegistration": true,
|
||||
"rangeLimit": 5000,
|
||||
"lineFoldingOnly": true,
|
||||
"foldingRangeKind": {
|
||||
"valueSet": [
|
||||
"comment",
|
||||
"imports",
|
||||
"region"
|
||||
]
|
||||
},
|
||||
"foldingRange": {
|
||||
"collapsedText": false
|
||||
}
|
||||
},
|
||||
"declaration": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"selectionRange": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"callHierarchy": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"semanticTokens": {
|
||||
"dynamicRegistration": true,
|
||||
"tokenTypes": [
|
||||
"namespace",
|
||||
"type",
|
||||
"class",
|
||||
"enum",
|
||||
"interface",
|
||||
"struct",
|
||||
"typeParameter",
|
||||
"parameter",
|
||||
"variable",
|
||||
"property",
|
||||
"enumMember",
|
||||
"event",
|
||||
"function",
|
||||
"method",
|
||||
"macro",
|
||||
"keyword",
|
||||
"modifier",
|
||||
"comment",
|
||||
"string",
|
||||
"number",
|
||||
"regexp",
|
||||
"operator",
|
||||
"decorator"
|
||||
],
|
||||
"tokenModifiers": [
|
||||
"declaration",
|
||||
"definition",
|
||||
"readonly",
|
||||
"static",
|
||||
"deprecated",
|
||||
"abstract",
|
||||
"async",
|
||||
"modification",
|
||||
"documentation",
|
||||
"defaultLibrary"
|
||||
],
|
||||
"formats": [
|
||||
"relative"
|
||||
],
|
||||
"requests": {
|
||||
"range": true,
|
||||
"full": {
|
||||
"delta": true
|
||||
}
|
||||
},
|
||||
"multilineTokenSupport": false,
|
||||
"overlappingTokenSupport": false,
|
||||
"serverCancelSupport": true,
|
||||
"augmentsSyntaxTokens": false
|
||||
},
|
||||
"linkedEditingRange": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"typeHierarchy": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"inlineValue": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"inlayHint": {
|
||||
"dynamicRegistration": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"tooltip",
|
||||
"textEdits",
|
||||
"label.tooltip",
|
||||
"label.location",
|
||||
"label.command"
|
||||
]
|
||||
}
|
||||
},
|
||||
"diagnostic": {
|
||||
"dynamicRegistration": true,
|
||||
"relatedDocumentSupport": false
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
"showMessage": {
|
||||
"messageActionItem": {
|
||||
"additionalPropertiesSupport": true
|
||||
}
|
||||
},
|
||||
"showDocument": {
|
||||
"support": true
|
||||
},
|
||||
"workDoneProgress": true
|
||||
},
|
||||
"general": {
|
||||
"staleRequestSupport": {
|
||||
"cancel": true,
|
||||
"retryOnContentModified": [
|
||||
"textDocument/semanticTokens/full",
|
||||
"textDocument/semanticTokens/range",
|
||||
"textDocument/semanticTokens/full/delta"
|
||||
]
|
||||
},
|
||||
"regularExpressions": {
|
||||
"engine": "ECMAScript",
|
||||
"version": "ES2020"
|
||||
},
|
||||
"markdown": {
|
||||
"parser": "marked",
|
||||
"version": "1.1.0",
|
||||
"allowedTags": [
|
||||
"ul",
|
||||
"li",
|
||||
"p",
|
||||
"code",
|
||||
"blockquote",
|
||||
"ol",
|
||||
"h1",
|
||||
"h2",
|
||||
"h3",
|
||||
"h4",
|
||||
"h5",
|
||||
"h6",
|
||||
"hr",
|
||||
"em",
|
||||
"pre",
|
||||
"table",
|
||||
"thead",
|
||||
"tbody",
|
||||
"tr",
|
||||
"th",
|
||||
"td",
|
||||
"div",
|
||||
"del",
|
||||
"a",
|
||||
"strong",
|
||||
"br",
|
||||
"img",
|
||||
"span"
|
||||
]
|
||||
},
|
||||
"positionEncodings": [
|
||||
"utf-16"
|
||||
]
|
||||
},
|
||||
"notebookDocument": {
|
||||
"synchronization": {
|
||||
"dynamicRegistration": true,
|
||||
"executionSummarySupport": true
|
||||
}
|
||||
},
|
||||
"experimental": {
|
||||
"snippetTextEdit": true,
|
||||
"codeActionGroup": true,
|
||||
"hoverActions": true,
|
||||
"serverStatusNotification": true,
|
||||
"colorDiagnosticOutput": true,
|
||||
"openServerLogs": true,
|
||||
"localDocs": true,
|
||||
"commands": {
|
||||
"commands": [
|
||||
"rust-analyzer.runSingle",
|
||||
"rust-analyzer.debugSingle",
|
||||
"rust-analyzer.showReferences",
|
||||
"rust-analyzer.gotoLocation",
|
||||
"editor.action.triggerParameterHints"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"initializationOptions": {
|
||||
"cargoRunner": null,
|
||||
"runnables": {
|
||||
"extraEnv": null,
|
||||
"problemMatcher": [
|
||||
"$rustc"
|
||||
],
|
||||
"command": null,
|
||||
"extraArgs": []
|
||||
},
|
||||
"statusBar": {
|
||||
"clickAction": "openLogs"
|
||||
},
|
||||
"server": {
|
||||
"path": null,
|
||||
"extraEnv": null
|
||||
},
|
||||
"trace": {
|
||||
"server": "verbose",
|
||||
"extension": false
|
||||
},
|
||||
"debug": {
|
||||
"engine": "auto",
|
||||
"sourceFileMap": {
|
||||
"/rustc/<id>": "${env:USERPROFILE}/.rustup/toolchains/<toolchain-id>/lib/rustlib/src/rust"
|
||||
},
|
||||
"openDebugPane": false,
|
||||
"engineSettings": {}
|
||||
},
|
||||
"restartServerOnConfigChange": false,
|
||||
"typing": {
|
||||
"continueCommentsOnNewline": true,
|
||||
"autoClosingAngleBrackets": {
|
||||
"enable": false
|
||||
}
|
||||
},
|
||||
"diagnostics": {
|
||||
"previewRustcOutput": false,
|
||||
"useRustcErrorCode": false,
|
||||
"disabled": [],
|
||||
"enable": true,
|
||||
"experimental": {
|
||||
"enable": false
|
||||
},
|
||||
"remapPrefix": {},
|
||||
"warningsAsHint": [],
|
||||
"warningsAsInfo": []
|
||||
},
|
||||
"discoverProjectRunner": null,
|
||||
"showUnlinkedFileNotification": true,
|
||||
"showDependenciesExplorer": true,
|
||||
"assist": {
|
||||
"emitMustUse": false,
|
||||
"expressionFillDefault": "todo"
|
||||
},
|
||||
"cachePriming": {
|
||||
"enable": true,
|
||||
"numThreads": 0
|
||||
},
|
||||
"cargo": {
|
||||
"autoreload": true,
|
||||
"buildScripts": {
|
||||
"enable": true,
|
||||
"invocationLocation": "workspace",
|
||||
"invocationStrategy": "per_workspace",
|
||||
"overrideCommand": null,
|
||||
"useRustcWrapper": true
|
||||
},
|
||||
"cfgs": {},
|
||||
"extraArgs": [],
|
||||
"extraEnv": {},
|
||||
"features": [],
|
||||
"noDefaultFeatures": false,
|
||||
"sysroot": "discover",
|
||||
"sysrootSrc": null,
|
||||
"target": null,
|
||||
"unsetTest": [
|
||||
"core"
|
||||
]
|
||||
},
|
||||
"checkOnSave": true,
|
||||
"check": {
|
||||
"allTargets": true,
|
||||
"command": "check",
|
||||
"extraArgs": [],
|
||||
"extraEnv": {},
|
||||
"features": null,
|
||||
"ignore": [],
|
||||
"invocationLocation": "workspace",
|
||||
"invocationStrategy": "per_workspace",
|
||||
"noDefaultFeatures": null,
|
||||
"overrideCommand": null,
|
||||
"targets": null
|
||||
},
|
||||
"completion": {
|
||||
"autoimport": {
|
||||
"enable": true
|
||||
},
|
||||
"autoself": {
|
||||
"enable": true
|
||||
},
|
||||
"callable": {
|
||||
"snippets": "fill_arguments"
|
||||
},
|
||||
"fullFunctionSignatures": {
|
||||
"enable": false
|
||||
},
|
||||
"limit": null,
|
||||
"postfix": {
|
||||
"enable": true
|
||||
},
|
||||
"privateEditable": {
|
||||
"enable": false
|
||||
},
|
||||
"snippets": {
|
||||
"custom": {
|
||||
"Arc::new": {
|
||||
"postfix": "arc",
|
||||
"body": "Arc::new(${receiver})",
|
||||
"requires": "std::sync::Arc",
|
||||
"description": "Put the expression into an `Arc`",
|
||||
"scope": "expr"
|
||||
},
|
||||
"Rc::new": {
|
||||
"postfix": "rc",
|
||||
"body": "Rc::new(${receiver})",
|
||||
"requires": "std::rc::Rc",
|
||||
"description": "Put the expression into an `Rc`",
|
||||
"scope": "expr"
|
||||
},
|
||||
"Box::pin": {
|
||||
"postfix": "pinbox",
|
||||
"body": "Box::pin(${receiver})",
|
||||
"requires": "std::boxed::Box",
|
||||
"description": "Put the expression into a pinned `Box`",
|
||||
"scope": "expr"
|
||||
},
|
||||
"Ok": {
|
||||
"postfix": "ok",
|
||||
"body": "Ok(${receiver})",
|
||||
"description": "Wrap the expression in a `Result::Ok`",
|
||||
"scope": "expr"
|
||||
},
|
||||
"Err": {
|
||||
"postfix": "err",
|
||||
"body": "Err(${receiver})",
|
||||
"description": "Wrap the expression in a `Result::Err`",
|
||||
"scope": "expr"
|
||||
},
|
||||
"Some": {
|
||||
"postfix": "some",
|
||||
"body": "Some(${receiver})",
|
||||
"description": "Wrap the expression in an `Option::Some`",
|
||||
"scope": "expr"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"excludeDirs": [],
|
||||
"watcher": "client"
|
||||
},
|
||||
"highlightRelated": {
|
||||
"breakPoints": {
|
||||
"enable": true
|
||||
},
|
||||
"closureCaptures": {
|
||||
"enable": true
|
||||
},
|
||||
"exitPoints": {
|
||||
"enable": true
|
||||
},
|
||||
"references": {
|
||||
"enable": true
|
||||
},
|
||||
"yieldPoints": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"hover": {
|
||||
"actions": {
|
||||
"debug": {
|
||||
"enable": true
|
||||
},
|
||||
"enable": true,
|
||||
"gotoTypeDef": {
|
||||
"enable": true
|
||||
},
|
||||
"implementations": {
|
||||
"enable": true
|
||||
},
|
||||
"references": {
|
||||
"enable": false
|
||||
},
|
||||
"run": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"documentation": {
|
||||
"enable": true,
|
||||
"keywords": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"enable": true
|
||||
},
|
||||
"memoryLayout": {
|
||||
"alignment": "hexadecimal",
|
||||
"enable": true,
|
||||
"niches": false,
|
||||
"offset": "hexadecimal",
|
||||
"size": "both"
|
||||
}
|
||||
},
|
||||
"imports": {
|
||||
"granularity": {
|
||||
"enforce": false,
|
||||
"group": "crate"
|
||||
},
|
||||
"group": {
|
||||
"enable": true
|
||||
},
|
||||
"merge": {
|
||||
"glob": true
|
||||
},
|
||||
"preferNoStd": false,
|
||||
"preferPrelude": false,
|
||||
"prefix": "plain"
|
||||
},
|
||||
"inlayHints": {
|
||||
"bindingModeHints": {
|
||||
"enable": false
|
||||
},
|
||||
"chainingHints": {
|
||||
"enable": true
|
||||
},
|
||||
"closingBraceHints": {
|
||||
"enable": true,
|
||||
"minLines": 25
|
||||
},
|
||||
"closureCaptureHints": {
|
||||
"enable": false
|
||||
},
|
||||
"closureReturnTypeHints": {
|
||||
"enable": "never"
|
||||
},
|
||||
"closureStyle": "impl_fn",
|
||||
"discriminantHints": {
|
||||
"enable": "never"
|
||||
},
|
||||
"expressionAdjustmentHints": {
|
||||
"enable": "never",
|
||||
"hideOutsideUnsafe": false,
|
||||
"mode": "prefix"
|
||||
},
|
||||
"lifetimeElisionHints": {
|
||||
"enable": "never",
|
||||
"useParameterNames": false
|
||||
},
|
||||
"maxLength": 25,
|
||||
"parameterHints": {
|
||||
"enable": true
|
||||
},
|
||||
"reborrowHints": {
|
||||
"enable": "never"
|
||||
},
|
||||
"renderColons": true,
|
||||
"typeHints": {
|
||||
"enable": true,
|
||||
"hideClosureInitialization": false,
|
||||
"hideNamedConstructor": false
|
||||
}
|
||||
},
|
||||
"interpret": {
|
||||
"tests": false
|
||||
},
|
||||
"joinLines": {
|
||||
"joinAssignments": true,
|
||||
"joinElseIf": true,
|
||||
"removeTrailingComma": true,
|
||||
"unwrapTrivialBlock": true
|
||||
},
|
||||
"lens": {
|
||||
"debug": {
|
||||
"enable": true
|
||||
},
|
||||
"enable": true,
|
||||
"forceCustomCommands": true,
|
||||
"implementations": {
|
||||
"enable": true
|
||||
},
|
||||
"location": "above_name",
|
||||
"references": {
|
||||
"adt": {
|
||||
"enable": false
|
||||
},
|
||||
"enumVariant": {
|
||||
"enable": false
|
||||
},
|
||||
"method": {
|
||||
"enable": false
|
||||
},
|
||||
"trait": {
|
||||
"enable": false
|
||||
}
|
||||
},
|
||||
"run": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"linkedProjects": [],
|
||||
"lru": {
|
||||
"capacity": null,
|
||||
"query": {
|
||||
"capacities": {}
|
||||
}
|
||||
},
|
||||
"notifications": {
|
||||
"cargoTomlNotFound": true
|
||||
},
|
||||
"numThreads": null,
|
||||
"procMacro": {
|
||||
"attributes": {
|
||||
"enable": true
|
||||
},
|
||||
"enable": true,
|
||||
"ignored": {},
|
||||
"server": null
|
||||
},
|
||||
"references": {
|
||||
"excludeImports": false
|
||||
},
|
||||
"rust": {
|
||||
"analyzerTargetDir": null
|
||||
},
|
||||
"rustc": {
|
||||
"source": null
|
||||
},
|
||||
"rustfmt": {
|
||||
"extraArgs": [],
|
||||
"overrideCommand": null,
|
||||
"rangeFormatting": {
|
||||
"enable": false
|
||||
}
|
||||
},
|
||||
"semanticHighlighting": {
|
||||
"doc": {
|
||||
"comment": {
|
||||
"inject": {
|
||||
"enable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"nonStandardTokens": true,
|
||||
"operator": {
|
||||
"enable": true,
|
||||
"specialization": {
|
||||
"enable": false
|
||||
}
|
||||
},
|
||||
"punctuation": {
|
||||
"enable": false,
|
||||
"separate": {
|
||||
"macro": {
|
||||
"bang": false
|
||||
}
|
||||
},
|
||||
"specialization": {
|
||||
"enable": false
|
||||
}
|
||||
},
|
||||
"strings": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"signatureInfo": {
|
||||
"detail": "full",
|
||||
"documentation": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"workspace": {
|
||||
"symbol": {
|
||||
"search": {
|
||||
"kind": "only_types",
|
||||
"limit": 128,
|
||||
"scope": "workspace"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"trace": "verbose",
|
||||
"workspaceFolders": [
|
||||
{
|
||||
"uri": "$uri",
|
||||
"name": "$name"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"_description": "Used to download the runtime dependencies for running RustAnalyzer. Obtained from https://github.com/rust-lang/rust-analyzer/releases",
|
||||
"runtimeDependencies": [
|
||||
{
|
||||
"id": "RustAnalyzer",
|
||||
"description": "RustAnalyzer for Linux (x64)",
|
||||
"url": "https://github.com/rust-lang/rust-analyzer/releases/download/2023-10-09/rust-analyzer-aarch64-apple-darwin.gz",
|
||||
"platformId": "osx-arm64",
|
||||
"archiveType": "gz",
|
||||
"binaryName": "rust_analyzer"
|
||||
},
|
||||
{
|
||||
"id": "RustAnalyzer",
|
||||
"description": "RustAnalyzer for Linux (x64)",
|
||||
"url": "https://github.com/rust-lang/rust-analyzer/releases/download/2023-10-09/rust-analyzer-x86_64-unknown-linux-gnu.gz",
|
||||
"platformId": "linux-x64",
|
||||
"archiveType": "gz",
|
||||
"binaryName": "rust_analyzer"
|
||||
},
|
||||
{
|
||||
"id": "RustAnalyzer",
|
||||
"description": "RustAnalyzer for Windows (x64)",
|
||||
"url": "https://github.com/rust-lang/rust-analyzer/releases/download/2023-10-09/rust-analyzer-x86_64-pc-windows-msvc.zip",
|
||||
"platformId": "win-x64",
|
||||
"archiveType": "zip",
|
||||
"binaryName": "rust-analyzer.exe"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
"""
|
||||
Provides Rust specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Rust.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import stat
|
||||
import pathlib
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import AsyncIterator
|
||||
|
||||
from overrides import override
|
||||
|
||||
from multilspy.multilspy_logger import MultilspyLogger
|
||||
from multilspy.language_server import LanguageServer
|
||||
from multilspy.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from multilspy.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from multilspy.multilspy_config import MultilspyConfig
|
||||
from multilspy.multilspy_utils import FileUtils
|
||||
from multilspy.multilspy_utils import PlatformUtils
|
||||
|
||||
|
||||
class RustAnalyzer(LanguageServer):
|
||||
"""
|
||||
Provides Rust specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Rust.
|
||||
"""
|
||||
|
||||
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
|
||||
"""
|
||||
Creates a RustAnalyzer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
rustanalyzer_executable_path = self.setup_runtime_dependencies(logger, config)
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=rustanalyzer_executable_path, cwd=repository_root_path),
|
||||
"rust",
|
||||
)
|
||||
self.server_ready = asyncio.Event()
|
||||
|
||||
@override
|
||||
def is_ignored_dirname(self, dirname: str) -> bool:
|
||||
return super().is_ignored_dirname(dirname) or dirname in ["target"]
|
||||
|
||||
def setup_runtime_dependencies(self, logger: MultilspyLogger, config: MultilspyConfig) -> str:
|
||||
"""
|
||||
Setup runtime dependencies for rust_analyzer.
|
||||
"""
|
||||
platform_id = PlatformUtils.get_platform_id()
|
||||
|
||||
with open(os.path.join(os.path.dirname(__file__), "runtime_dependencies.json"), "r", encoding="utf-8") as f:
|
||||
d = json.load(f)
|
||||
del d["_description"]
|
||||
|
||||
# assert platform_id.value in [
|
||||
# "linux-x64",
|
||||
# "win-x64",
|
||||
# ], "Only linux-x64 and win-x64 platform is supported for in multilspy at the moment"
|
||||
|
||||
runtime_dependencies = d["runtimeDependencies"]
|
||||
runtime_dependencies = [
|
||||
dependency for dependency in runtime_dependencies if dependency["platformId"] == platform_id.value
|
||||
]
|
||||
assert len(runtime_dependencies) == 1
|
||||
dependency = runtime_dependencies[0]
|
||||
|
||||
rustanalyzer_ls_dir = os.path.join(os.path.dirname(__file__), "static", "RustAnalyzer")
|
||||
rustanalyzer_executable_path = os.path.join(rustanalyzer_ls_dir, dependency["binaryName"])
|
||||
if not os.path.exists(rustanalyzer_ls_dir):
|
||||
os.makedirs(rustanalyzer_ls_dir)
|
||||
if dependency["archiveType"] == "gz":
|
||||
FileUtils.download_and_extract_archive(
|
||||
logger, dependency["url"], rustanalyzer_executable_path, dependency["archiveType"]
|
||||
)
|
||||
else:
|
||||
FileUtils.download_and_extract_archive(
|
||||
logger, dependency["url"], rustanalyzer_ls_dir, dependency["archiveType"]
|
||||
)
|
||||
assert os.path.exists(rustanalyzer_executable_path)
|
||||
os.chmod(rustanalyzer_executable_path, stat.S_IEXEC)
|
||||
|
||||
return rustanalyzer_executable_path
|
||||
|
||||
def _get_initialize_params(self, repository_absolute_path: str) -> InitializeParams:
|
||||
"""
|
||||
Returns the initialize params for the Rust Analyzer Language Server.
|
||||
"""
|
||||
with open(os.path.join(os.path.dirname(__file__), "initialize_params.json"), "r", encoding="utf-8") as f:
|
||||
d = json.load(f)
|
||||
|
||||
del d["_description"]
|
||||
|
||||
d["processId"] = os.getpid()
|
||||
assert d["rootPath"] == "$rootPath"
|
||||
d["rootPath"] = repository_absolute_path
|
||||
|
||||
assert d["rootUri"] == "$rootUri"
|
||||
d["rootUri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["uri"] == "$uri"
|
||||
d["workspaceFolders"][0]["uri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["name"] == "$name"
|
||||
d["workspaceFolders"][0]["name"] = os.path.basename(repository_absolute_path)
|
||||
|
||||
return d
|
||||
|
||||
@asynccontextmanager
|
||||
async def start_server(self) -> AsyncIterator["RustAnalyzer"]:
|
||||
"""
|
||||
Starts the Rust Analyzer Language Server, waits for the server to be ready and yields the LanguageServer instance.
|
||||
|
||||
Usage:
|
||||
```
|
||||
async with lsp.start_server():
|
||||
# LanguageServer has been initialized and ready to serve requests
|
||||
await lsp.request_definition(...)
|
||||
await lsp.request_references(...)
|
||||
# Shutdown the LanguageServer on exit from scope
|
||||
# LanguageServer has been shutdown
|
||||
"""
|
||||
|
||||
async def register_capability_handler(params):
|
||||
assert "registrations" in params
|
||||
for registration in params["registrations"]:
|
||||
if registration["method"] == "workspace/executeCommand":
|
||||
self.initialize_searcher_command_available.set()
|
||||
self.resolve_main_method_available.set()
|
||||
return
|
||||
|
||||
async def lang_status_handler(params):
|
||||
# TODO: Should we wait for
|
||||
# server -> client: {'jsonrpc': '2.0', 'method': 'language/status', 'params': {'type': 'ProjectStatus', 'message': 'OK'}}
|
||||
# Before proceeding?
|
||||
if params["type"] == "ServiceReady" and params["message"] == "ServiceReady":
|
||||
self.service_ready_event.set()
|
||||
|
||||
async def execute_client_command_handler(params):
|
||||
return []
|
||||
|
||||
async def do_nothing(params):
|
||||
return
|
||||
|
||||
async def check_experimental_status(params):
|
||||
if params["quiescent"] == True:
|
||||
self.server_ready.set()
|
||||
|
||||
async def window_log_message(msg):
|
||||
self.logger.log(f"LSP: window/logMessage: {msg}", logging.INFO)
|
||||
|
||||
self.server.on_request("client/registerCapability", register_capability_handler)
|
||||
self.server.on_notification("language/status", lang_status_handler)
|
||||
self.server.on_notification("window/logMessage", window_log_message)
|
||||
self.server.on_request("workspace/executeClientCommand", execute_client_command_handler)
|
||||
self.server.on_notification("$/progress", do_nothing)
|
||||
self.server.on_notification("textDocument/publishDiagnostics", do_nothing)
|
||||
self.server.on_notification("language/actionableNotification", do_nothing)
|
||||
self.server.on_notification("experimental/serverStatus", check_experimental_status)
|
||||
|
||||
async with super().start_server():
|
||||
self.logger.log("Starting RustAnalyzer server process", logging.INFO)
|
||||
await self.server.start()
|
||||
initialize_params = self._get_initialize_params(self.repository_root_path)
|
||||
|
||||
self.logger.log(
|
||||
"Sending initialize request from LSP client to LSP server and awaiting response",
|
||||
logging.INFO,
|
||||
)
|
||||
init_response = await self.server.send.initialize(initialize_params)
|
||||
assert init_response["capabilities"]["textDocumentSync"]["change"] == 2
|
||||
assert "completionProvider" in init_response["capabilities"]
|
||||
assert init_response["capabilities"]["completionProvider"] == {
|
||||
"resolveProvider": True,
|
||||
"triggerCharacters": [":", ".", "'", "("],
|
||||
"completionItem": {"labelDetailsSupport": True},
|
||||
}
|
||||
self.server.notify.initialized({})
|
||||
self.completions_available.set()
|
||||
|
||||
await self.server_ready.wait()
|
||||
|
||||
yield self
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"_description": "This file contains the initialization parameters for the Solargraph Language Server.",
|
||||
"processId": "$processId",
|
||||
"rootPath": "$rootPath",
|
||||
"rootUri": "$rootUri",
|
||||
"capabilities": {
|
||||
},
|
||||
"trace": "verbose",
|
||||
"workspaceFolders": [
|
||||
{
|
||||
"uri": "$uri",
|
||||
"name": "$name"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"_description": "This file contains URLs and other metadata required for downloading and installing the Solargraph language server.",
|
||||
"runtimeDependencies": [
|
||||
{
|
||||
"url": "https://rubygems.org/downloads/solargraph-0.51.1.gem",
|
||||
"installCommand": "gem install solargraph -v 0.51.1",
|
||||
"binaryName": "solargraph",
|
||||
"archiveType": "gem"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
"""
|
||||
Provides Ruby specific instantiation of the LanguageServer class using Solargraph.
|
||||
Contains various configurations and settings specific to Ruby.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import stat
|
||||
import subprocess
|
||||
import pathlib
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import AsyncIterator, override
|
||||
|
||||
from multilspy.multilspy_logger import MultilspyLogger
|
||||
from multilspy.language_server import LanguageServer
|
||||
from multilspy.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from multilspy.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from multilspy.multilspy_config import MultilspyConfig
|
||||
from multilspy.multilspy_utils import FileUtils
|
||||
from multilspy.multilspy_utils import PlatformUtils, PlatformId
|
||||
|
||||
|
||||
class Solargraph(LanguageServer):
|
||||
"""
|
||||
Provides Ruby specific instantiation of the LanguageServer class using Solargraph.
|
||||
Contains various configurations and settings specific to Ruby.
|
||||
"""
|
||||
|
||||
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
|
||||
"""
|
||||
Creates a Solargraph instance. This class is not meant to be instantiated directly.
|
||||
Use LanguageServer.create() instead.
|
||||
"""
|
||||
solargraph_executable_path = self.setup_runtime_dependencies(logger, config, repository_root_path)
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=f"{solargraph_executable_path} stdio", cwd=repository_root_path),
|
||||
"ruby",
|
||||
)
|
||||
self.server_ready = asyncio.Event()
|
||||
|
||||
@override
|
||||
def is_ignored_dirname(self, dirname: str) -> bool:
|
||||
return super().is_ignored_dirname(dirname) or dirname in ["vendor"]
|
||||
|
||||
def setup_runtime_dependencies(self, logger: MultilspyLogger, config: MultilspyConfig, repository_root_path: str) -> str:
|
||||
"""
|
||||
Setup runtime dependencies for Solargraph.
|
||||
"""
|
||||
|
||||
with open(os.path.join(os.path.dirname(__file__), "runtime_dependencies.json"), "r", encoding="utf-8") as f:
|
||||
d = json.load(f)
|
||||
del d["_description"]
|
||||
|
||||
dependency = d["runtimeDependencies"][0]
|
||||
|
||||
# Check if Ruby is installed
|
||||
try:
|
||||
result = subprocess.run(["ruby", "--version"], check=True, capture_output=True, cwd=repository_root_path)
|
||||
ruby_version = result.stdout.strip()
|
||||
logger.log(f"Ruby version: {ruby_version}", logging.INFO)
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise RuntimeError(f"Error checking for Ruby installation: {e.stderr}")
|
||||
except FileNotFoundError:
|
||||
raise RuntimeError("Ruby is not installed. Please install Ruby before continuing.")
|
||||
|
||||
# Check if solargraph is installed
|
||||
try:
|
||||
result = subprocess.run(["gem", "list", "^solargraph$", "-i"], check=False, capture_output=True, text=True, cwd=repository_root_path)
|
||||
if result.stdout.strip() == "false":
|
||||
logger.log("Installing Solargraph...", logging.INFO)
|
||||
subprocess.run(dependency["installCommand"].split(), check=True, capture_output=True, cwd=repository_root_path)
|
||||
|
||||
# Get the gem executable path directly
|
||||
result = subprocess.run(["gem", "which", "solargraph"], check=True, capture_output=True, text=True, cwd=repository_root_path)
|
||||
gem_path = result.stdout.strip()
|
||||
bin_dir = os.path.join(os.path.dirname(os.path.dirname(gem_path)), "bin")
|
||||
executable_path = os.path.join(bin_dir, "solargraph")
|
||||
|
||||
if not os.path.exists(executable_path):
|
||||
raise RuntimeError(f"Solargraph executable not found at {executable_path}")
|
||||
|
||||
# Ensure the executable has the right permissions
|
||||
os.chmod(executable_path, os.stat(executable_path).st_mode | stat.S_IEXEC)
|
||||
|
||||
return executable_path
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise RuntimeError(f"Failed to check or install Solargraph. {e.stderr}")
|
||||
|
||||
def _get_initialize_params(self, repository_absolute_path: str) -> InitializeParams:
|
||||
"""
|
||||
Returns the initialize params for the Solargraph Language Server.
|
||||
"""
|
||||
with open(os.path.join(os.path.dirname(__file__), "initialize_params.json"), "r", encoding="utf-8") as f:
|
||||
d = json.load(f)
|
||||
|
||||
del d["_description"]
|
||||
|
||||
d["processId"] = os.getpid()
|
||||
assert d["rootPath"] == "$rootPath"
|
||||
d["rootPath"] = repository_absolute_path
|
||||
|
||||
assert d["rootUri"] == "$rootUri"
|
||||
d["rootUri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["uri"] == "$uri"
|
||||
d["workspaceFolders"][0]["uri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["name"] == "$name"
|
||||
d["workspaceFolders"][0]["name"] = os.path.basename(repository_absolute_path)
|
||||
|
||||
return d
|
||||
|
||||
@asynccontextmanager
|
||||
async def start_server(self) -> AsyncIterator["Solargraph"]:
|
||||
"""
|
||||
Starts the Solargraph Language Server for Ruby, waits for the server to be ready and yields the LanguageServer instance.
|
||||
|
||||
Usage:
|
||||
```
|
||||
async with lsp.start_server():
|
||||
# LanguageServer has been initialized and ready to serve requests
|
||||
await lsp.request_definition(...)
|
||||
await lsp.request_references(...)
|
||||
# Shutdown the LanguageServer on exit from scope
|
||||
# LanguageServer has been shutdown
|
||||
"""
|
||||
|
||||
async def register_capability_handler(params):
|
||||
assert "registrations" in params
|
||||
for registration in params["registrations"]:
|
||||
if registration["method"] == "workspace/executeCommand":
|
||||
self.initialize_searcher_command_available.set()
|
||||
self.resolve_main_method_available.set()
|
||||
return
|
||||
|
||||
async def lang_status_handler(params):
|
||||
# TODO: Should we wait for
|
||||
# server -> client: {'jsonrpc': '2.0', 'method': 'language/status', 'params': {'type': 'ProjectStatus', 'message': 'OK'}}
|
||||
# Before proceeding?
|
||||
if params["type"] == "ServiceReady" and params["message"] == "ServiceReady":
|
||||
self.service_ready_event.set()
|
||||
|
||||
async def execute_client_command_handler(params):
|
||||
return []
|
||||
|
||||
async def do_nothing(params):
|
||||
return
|
||||
|
||||
async def window_log_message(msg):
|
||||
self.logger.log(f"LSP: window/logMessage: {msg}", logging.INFO)
|
||||
|
||||
self.server.on_request("client/registerCapability", register_capability_handler)
|
||||
self.server.on_notification("language/status", lang_status_handler)
|
||||
self.server.on_notification("window/logMessage", window_log_message)
|
||||
self.server.on_request("workspace/executeClientCommand", execute_client_command_handler)
|
||||
self.server.on_notification("$/progress", do_nothing)
|
||||
self.server.on_notification("textDocument/publishDiagnostics", do_nothing)
|
||||
self.server.on_notification("language/actionableNotification", do_nothing)
|
||||
|
||||
async with super().start_server():
|
||||
self.logger.log("Starting solargraph server process", logging.INFO)
|
||||
await self.server.start()
|
||||
initialize_params = self._get_initialize_params(self.repository_root_path)
|
||||
|
||||
self.logger.log(
|
||||
"Sending initialize request from LSP client to LSP server and awaiting response",
|
||||
logging.INFO,
|
||||
)
|
||||
self.logger.log(f"Sending init params: {json.dumps(initialize_params, indent=4)}", logging.INFO)
|
||||
init_response = await self.server.send.initialize(initialize_params)
|
||||
self.logger.log(f"Received init response: {init_response}", logging.INFO)
|
||||
assert init_response["capabilities"]["textDocumentSync"] == 2
|
||||
assert "completionProvider" in init_response["capabilities"]
|
||||
assert init_response["capabilities"]["completionProvider"] == {
|
||||
"resolveProvider": True,
|
||||
"triggerCharacters": [".", ":", "@"],
|
||||
}
|
||||
self.server.notify.initialized({})
|
||||
self.completions_available.set()
|
||||
|
||||
self.server_ready.set()
|
||||
await self.server_ready.wait()
|
||||
|
||||
yield self
|
||||
@@ -0,0 +1,906 @@
|
||||
{
|
||||
"_description": "The parameters sent by the client when initializing the language server with the \"initialize\" request. More details at https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize",
|
||||
"processId": "os.getpid()",
|
||||
"clientInfo": {
|
||||
"name": "Visual Studio Code - Insiders",
|
||||
"version": "1.82.0-insider"
|
||||
},
|
||||
"locale": "en",
|
||||
"rootPath": "$rootPath",
|
||||
"rootUri": "$rootUri",
|
||||
"capabilities": {
|
||||
"workspace": {
|
||||
"applyEdit": true,
|
||||
"workspaceEdit": {
|
||||
"documentChanges": true,
|
||||
"resourceOperations": [
|
||||
"create",
|
||||
"rename",
|
||||
"delete"
|
||||
],
|
||||
"failureHandling": "textOnlyTransactional",
|
||||
"normalizesLineEndings": true,
|
||||
"changeAnnotationSupport": {
|
||||
"groupsOnLabel": true
|
||||
}
|
||||
},
|
||||
"configuration": true,
|
||||
"didChangeWatchedFiles": {
|
||||
"dynamicRegistration": true,
|
||||
"relativePatternSupport": true
|
||||
},
|
||||
"symbol": {
|
||||
"dynamicRegistration": true,
|
||||
"symbolKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26
|
||||
]
|
||||
},
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"location.range"
|
||||
]
|
||||
}
|
||||
},
|
||||
"codeLens": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"executeCommand": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"didChangeConfiguration": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"workspaceFolders": true,
|
||||
"semanticTokens": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"fileOperations": {
|
||||
"dynamicRegistration": true,
|
||||
"didCreate": true,
|
||||
"didRename": true,
|
||||
"didDelete": true,
|
||||
"willCreate": true,
|
||||
"willRename": true,
|
||||
"willDelete": true
|
||||
},
|
||||
"inlineValue": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"inlayHint": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"diagnostics": {
|
||||
"refreshSupport": true
|
||||
}
|
||||
},
|
||||
"textDocument": {
|
||||
"publishDiagnostics": {
|
||||
"relatedInformation": true,
|
||||
"versionSupport": false,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2
|
||||
]
|
||||
},
|
||||
"codeDescriptionSupport": true,
|
||||
"dataSupport": true
|
||||
},
|
||||
"synchronization": {
|
||||
"dynamicRegistration": true,
|
||||
"willSave": true,
|
||||
"willSaveWaitUntil": true,
|
||||
"didSave": true
|
||||
},
|
||||
"completion": {
|
||||
"dynamicRegistration": true,
|
||||
"contextSupport": true,
|
||||
"completionItem": {
|
||||
"snippetSupport": true,
|
||||
"commitCharactersSupport": true,
|
||||
"documentationFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
],
|
||||
"deprecatedSupport": true,
|
||||
"preselectSupport": true,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"insertReplaceSupport": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"documentation",
|
||||
"detail",
|
||||
"additionalTextEdits"
|
||||
]
|
||||
},
|
||||
"insertTextModeSupport": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2
|
||||
]
|
||||
},
|
||||
"labelDetailsSupport": true
|
||||
},
|
||||
"insertTextMode": 2,
|
||||
"completionItemKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25
|
||||
]
|
||||
},
|
||||
"completionList": {
|
||||
"itemDefaults": [
|
||||
"commitCharacters",
|
||||
"editRange",
|
||||
"insertTextFormat",
|
||||
"insertTextMode"
|
||||
]
|
||||
}
|
||||
},
|
||||
"hover": {
|
||||
"dynamicRegistration": true,
|
||||
"contentFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
]
|
||||
},
|
||||
"signatureHelp": {
|
||||
"dynamicRegistration": true,
|
||||
"signatureInformation": {
|
||||
"documentationFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
],
|
||||
"parameterInformation": {
|
||||
"labelOffsetSupport": true
|
||||
},
|
||||
"activeParameterSupport": true
|
||||
},
|
||||
"contextSupport": true
|
||||
},
|
||||
"definition": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"references": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"documentHighlight": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"documentSymbol": {
|
||||
"dynamicRegistration": true,
|
||||
"symbolKind": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26
|
||||
]
|
||||
},
|
||||
"hierarchicalDocumentSymbolSupport": true,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"labelSupport": true
|
||||
},
|
||||
"codeAction": {
|
||||
"dynamicRegistration": true,
|
||||
"isPreferredSupport": true,
|
||||
"disabledSupport": true,
|
||||
"dataSupport": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"edit"
|
||||
]
|
||||
},
|
||||
"codeActionLiteralSupport": {
|
||||
"codeActionKind": {
|
||||
"valueSet": [
|
||||
"",
|
||||
"quickfix",
|
||||
"refactor",
|
||||
"refactor.extract",
|
||||
"refactor.inline",
|
||||
"refactor.rewrite",
|
||||
"source",
|
||||
"source.organizeImports"
|
||||
]
|
||||
}
|
||||
},
|
||||
"honorsChangeAnnotations": false
|
||||
},
|
||||
"codeLens": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"formatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"rangeFormatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"onTypeFormatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"rename": {
|
||||
"dynamicRegistration": true,
|
||||
"prepareSupport": true,
|
||||
"prepareSupportDefaultBehavior": 1,
|
||||
"honorsChangeAnnotations": true
|
||||
},
|
||||
"documentLink": {
|
||||
"dynamicRegistration": true,
|
||||
"tooltipSupport": true
|
||||
},
|
||||
"typeDefinition": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"implementation": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"colorProvider": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"foldingRange": {
|
||||
"dynamicRegistration": true,
|
||||
"rangeLimit": 5000,
|
||||
"lineFoldingOnly": true,
|
||||
"foldingRangeKind": {
|
||||
"valueSet": [
|
||||
"comment",
|
||||
"imports",
|
||||
"region"
|
||||
]
|
||||
},
|
||||
"foldingRange": {
|
||||
"collapsedText": false
|
||||
}
|
||||
},
|
||||
"declaration": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"selectionRange": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"callHierarchy": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"semanticTokens": {
|
||||
"dynamicRegistration": true,
|
||||
"tokenTypes": [
|
||||
"namespace",
|
||||
"type",
|
||||
"class",
|
||||
"enum",
|
||||
"interface",
|
||||
"struct",
|
||||
"typeParameter",
|
||||
"parameter",
|
||||
"variable",
|
||||
"property",
|
||||
"enumMember",
|
||||
"event",
|
||||
"function",
|
||||
"method",
|
||||
"macro",
|
||||
"keyword",
|
||||
"modifier",
|
||||
"comment",
|
||||
"string",
|
||||
"number",
|
||||
"regexp",
|
||||
"operator",
|
||||
"decorator"
|
||||
],
|
||||
"tokenModifiers": [
|
||||
"declaration",
|
||||
"definition",
|
||||
"readonly",
|
||||
"static",
|
||||
"deprecated",
|
||||
"abstract",
|
||||
"async",
|
||||
"modification",
|
||||
"documentation",
|
||||
"defaultLibrary"
|
||||
],
|
||||
"formats": [
|
||||
"relative"
|
||||
],
|
||||
"requests": {
|
||||
"range": true,
|
||||
"full": {
|
||||
"delta": true
|
||||
}
|
||||
},
|
||||
"multilineTokenSupport": false,
|
||||
"overlappingTokenSupport": false,
|
||||
"serverCancelSupport": true,
|
||||
"augmentsSyntaxTokens": false
|
||||
},
|
||||
"linkedEditingRange": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"typeHierarchy": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"inlineValue": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"inlayHint": {
|
||||
"dynamicRegistration": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"tooltip",
|
||||
"textEdits",
|
||||
"label.tooltip",
|
||||
"label.location",
|
||||
"label.command"
|
||||
]
|
||||
}
|
||||
},
|
||||
"diagnostic": {
|
||||
"dynamicRegistration": true,
|
||||
"relatedDocumentSupport": false
|
||||
}
|
||||
},
|
||||
"general": {
|
||||
"staleRequestSupport": {
|
||||
"cancel": true,
|
||||
"retryOnContentModified": [
|
||||
"textDocument/semanticTokens/full",
|
||||
"textDocument/semanticTokens/range",
|
||||
"textDocument/semanticTokens/full/delta"
|
||||
]
|
||||
},
|
||||
"regularExpressions": {
|
||||
"engine": "ECMAScript",
|
||||
"version": "ES2020"
|
||||
},
|
||||
"markdown": {
|
||||
"parser": "marked",
|
||||
"version": "1.1.0",
|
||||
"allowedTags": [
|
||||
"ul",
|
||||
"li",
|
||||
"p",
|
||||
"code",
|
||||
"blockquote",
|
||||
"ol",
|
||||
"h1",
|
||||
"h2",
|
||||
"h3",
|
||||
"h4",
|
||||
"h5",
|
||||
"h6",
|
||||
"hr",
|
||||
"em",
|
||||
"pre",
|
||||
"table",
|
||||
"thead",
|
||||
"tbody",
|
||||
"tr",
|
||||
"th",
|
||||
"td",
|
||||
"div",
|
||||
"del",
|
||||
"a",
|
||||
"strong",
|
||||
"br",
|
||||
"img",
|
||||
"span"
|
||||
]
|
||||
},
|
||||
"positionEncodings": [
|
||||
"utf-16"
|
||||
]
|
||||
},
|
||||
"notebookDocument": {
|
||||
"synchronization": {
|
||||
"dynamicRegistration": true,
|
||||
"executionSummarySupport": true
|
||||
}
|
||||
},
|
||||
"experimental": {
|
||||
"snippetTextEdit": true,
|
||||
"codeActionGroup": true,
|
||||
"hoverActions": true,
|
||||
"serverStatusNotification": true,
|
||||
"colorDiagnosticOutput": true,
|
||||
"openServerLogs": true,
|
||||
"localDocs": true,
|
||||
"commands": {
|
||||
"commands": [
|
||||
"rust-analyzer.runSingle",
|
||||
"rust-analyzer.debugSingle",
|
||||
"rust-analyzer.showReferences",
|
||||
"rust-analyzer.gotoLocation",
|
||||
"editor.action.triggerParameterHints"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"initializationOptions": {
|
||||
"cargoRunner": null,
|
||||
"runnables": {
|
||||
"extraEnv": null,
|
||||
"problemMatcher": [
|
||||
"$rustc"
|
||||
],
|
||||
"command": null,
|
||||
"extraArgs": []
|
||||
},
|
||||
"statusBar": {
|
||||
"clickAction": "openLogs"
|
||||
},
|
||||
"server": {
|
||||
"path": null,
|
||||
"extraEnv": null
|
||||
},
|
||||
"trace": {
|
||||
"server": "verbose",
|
||||
"extension": false
|
||||
},
|
||||
"debug": {
|
||||
"engine": "auto",
|
||||
"sourceFileMap": {
|
||||
"/rustc/<id>": "${env:USERPROFILE}/.rustup/toolchains/<toolchain-id>/lib/rustlib/src/rust"
|
||||
},
|
||||
"openDebugPane": false,
|
||||
"engineSettings": {}
|
||||
},
|
||||
"restartServerOnConfigChange": false,
|
||||
"typing": {
|
||||
"continueCommentsOnNewline": true,
|
||||
"autoClosingAngleBrackets": {
|
||||
"enable": false
|
||||
}
|
||||
},
|
||||
"diagnostics": {
|
||||
"previewRustcOutput": false,
|
||||
"useRustcErrorCode": false,
|
||||
"disabled": [],
|
||||
"enable": true,
|
||||
"experimental": {
|
||||
"enable": false
|
||||
},
|
||||
"remapPrefix": {},
|
||||
"warningsAsHint": [],
|
||||
"warningsAsInfo": []
|
||||
},
|
||||
"discoverProjectRunner": null,
|
||||
"showUnlinkedFileNotification": true,
|
||||
"showDependenciesExplorer": true,
|
||||
"assist": {
|
||||
"emitMustUse": false,
|
||||
"expressionFillDefault": "todo"
|
||||
},
|
||||
"cachePriming": {
|
||||
"enable": true,
|
||||
"numThreads": 0
|
||||
},
|
||||
"cargo": {
|
||||
"autoreload": true,
|
||||
"buildScripts": {
|
||||
"enable": true,
|
||||
"invocationLocation": "workspace",
|
||||
"invocationStrategy": "per_workspace",
|
||||
"overrideCommand": null,
|
||||
"useRustcWrapper": true
|
||||
},
|
||||
"cfgs": {},
|
||||
"extraArgs": [],
|
||||
"extraEnv": {},
|
||||
"features": [],
|
||||
"noDefaultFeatures": false,
|
||||
"sysroot": "discover",
|
||||
"sysrootSrc": null,
|
||||
"target": null,
|
||||
"unsetTest": [
|
||||
"core"
|
||||
]
|
||||
},
|
||||
"checkOnSave": true,
|
||||
"check": {
|
||||
"allTargets": true,
|
||||
"command": "check",
|
||||
"extraArgs": [],
|
||||
"extraEnv": {},
|
||||
"features": null,
|
||||
"ignore": [],
|
||||
"invocationLocation": "workspace",
|
||||
"invocationStrategy": "per_workspace",
|
||||
"noDefaultFeatures": null,
|
||||
"overrideCommand": null,
|
||||
"targets": null
|
||||
},
|
||||
"completion": {
|
||||
"autoimport": {
|
||||
"enable": true
|
||||
},
|
||||
"autoself": {
|
||||
"enable": true
|
||||
},
|
||||
"callable": {
|
||||
"snippets": "fill_arguments"
|
||||
},
|
||||
"fullFunctionSignatures": {
|
||||
"enable": false
|
||||
},
|
||||
"limit": null,
|
||||
"postfix": {
|
||||
"enable": true
|
||||
},
|
||||
"privateEditable": {
|
||||
"enable": false
|
||||
},
|
||||
"snippets": {
|
||||
"custom": {
|
||||
"Arc::new": {
|
||||
"postfix": "arc",
|
||||
"body": "Arc::new(${receiver})",
|
||||
"requires": "std::sync::Arc",
|
||||
"description": "Put the expression into an `Arc`",
|
||||
"scope": "expr"
|
||||
},
|
||||
"Rc::new": {
|
||||
"postfix": "rc",
|
||||
"body": "Rc::new(${receiver})",
|
||||
"requires": "std::rc::Rc",
|
||||
"description": "Put the expression into an `Rc`",
|
||||
"scope": "expr"
|
||||
},
|
||||
"Box::pin": {
|
||||
"postfix": "pinbox",
|
||||
"body": "Box::pin(${receiver})",
|
||||
"requires": "std::boxed::Box",
|
||||
"description": "Put the expression into a pinned `Box`",
|
||||
"scope": "expr"
|
||||
},
|
||||
"Ok": {
|
||||
"postfix": "ok",
|
||||
"body": "Ok(${receiver})",
|
||||
"description": "Wrap the expression in a `Result::Ok`",
|
||||
"scope": "expr"
|
||||
},
|
||||
"Err": {
|
||||
"postfix": "err",
|
||||
"body": "Err(${receiver})",
|
||||
"description": "Wrap the expression in a `Result::Err`",
|
||||
"scope": "expr"
|
||||
},
|
||||
"Some": {
|
||||
"postfix": "some",
|
||||
"body": "Some(${receiver})",
|
||||
"description": "Wrap the expression in an `Option::Some`",
|
||||
"scope": "expr"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"excludeDirs": [],
|
||||
"watcher": "client"
|
||||
},
|
||||
"highlightRelated": {
|
||||
"breakPoints": {
|
||||
"enable": true
|
||||
},
|
||||
"closureCaptures": {
|
||||
"enable": true
|
||||
},
|
||||
"exitPoints": {
|
||||
"enable": true
|
||||
},
|
||||
"references": {
|
||||
"enable": true
|
||||
},
|
||||
"yieldPoints": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"hover": {
|
||||
"actions": {
|
||||
"debug": {
|
||||
"enable": true
|
||||
},
|
||||
"enable": true,
|
||||
"gotoTypeDef": {
|
||||
"enable": true
|
||||
},
|
||||
"implementations": {
|
||||
"enable": true
|
||||
},
|
||||
"references": {
|
||||
"enable": false
|
||||
},
|
||||
"run": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"documentation": {
|
||||
"enable": true,
|
||||
"keywords": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"enable": true
|
||||
},
|
||||
"memoryLayout": {
|
||||
"alignment": "hexadecimal",
|
||||
"enable": true,
|
||||
"niches": false,
|
||||
"offset": "hexadecimal",
|
||||
"size": "both"
|
||||
}
|
||||
},
|
||||
"imports": {
|
||||
"granularity": {
|
||||
"enforce": false,
|
||||
"group": "crate"
|
||||
},
|
||||
"group": {
|
||||
"enable": true
|
||||
},
|
||||
"merge": {
|
||||
"glob": true
|
||||
},
|
||||
"preferNoStd": false,
|
||||
"preferPrelude": false,
|
||||
"prefix": "plain"
|
||||
},
|
||||
"inlayHints": {
|
||||
"bindingModeHints": {
|
||||
"enable": false
|
||||
},
|
||||
"chainingHints": {
|
||||
"enable": true
|
||||
},
|
||||
"closingBraceHints": {
|
||||
"enable": true,
|
||||
"minLines": 25
|
||||
},
|
||||
"closureCaptureHints": {
|
||||
"enable": false
|
||||
},
|
||||
"closureReturnTypeHints": {
|
||||
"enable": "never"
|
||||
},
|
||||
"closureStyle": "impl_fn",
|
||||
"discriminantHints": {
|
||||
"enable": "never"
|
||||
},
|
||||
"expressionAdjustmentHints": {
|
||||
"enable": "never",
|
||||
"hideOutsideUnsafe": false,
|
||||
"mode": "prefix"
|
||||
},
|
||||
"lifetimeElisionHints": {
|
||||
"enable": "never",
|
||||
"useParameterNames": false
|
||||
},
|
||||
"maxLength": 25,
|
||||
"parameterHints": {
|
||||
"enable": true
|
||||
},
|
||||
"reborrowHints": {
|
||||
"enable": "never"
|
||||
},
|
||||
"renderColons": true,
|
||||
"typeHints": {
|
||||
"enable": true,
|
||||
"hideClosureInitialization": false,
|
||||
"hideNamedConstructor": false
|
||||
}
|
||||
},
|
||||
"interpret": {
|
||||
"tests": false
|
||||
},
|
||||
"joinLines": {
|
||||
"joinAssignments": true,
|
||||
"joinElseIf": true,
|
||||
"removeTrailingComma": true,
|
||||
"unwrapTrivialBlock": true
|
||||
},
|
||||
"lens": {
|
||||
"debug": {
|
||||
"enable": true
|
||||
},
|
||||
"enable": true,
|
||||
"forceCustomCommands": true,
|
||||
"implementations": {
|
||||
"enable": true
|
||||
},
|
||||
"location": "above_name",
|
||||
"references": {
|
||||
"adt": {
|
||||
"enable": false
|
||||
},
|
||||
"enumVariant": {
|
||||
"enable": false
|
||||
},
|
||||
"method": {
|
||||
"enable": false
|
||||
},
|
||||
"trait": {
|
||||
"enable": false
|
||||
}
|
||||
},
|
||||
"run": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"linkedProjects": [],
|
||||
"lru": {
|
||||
"capacity": null,
|
||||
"query": {
|
||||
"capacities": {}
|
||||
}
|
||||
},
|
||||
"notifications": {
|
||||
"cargoTomlNotFound": true
|
||||
},
|
||||
"numThreads": null,
|
||||
"procMacro": {
|
||||
"attributes": {
|
||||
"enable": true
|
||||
},
|
||||
"enable": true,
|
||||
"ignored": {},
|
||||
"server": null
|
||||
},
|
||||
"references": {
|
||||
"excludeImports": false
|
||||
},
|
||||
"rust": {
|
||||
"analyzerTargetDir": null
|
||||
},
|
||||
"rustc": {
|
||||
"source": null
|
||||
},
|
||||
"rustfmt": {
|
||||
"extraArgs": [],
|
||||
"overrideCommand": null,
|
||||
"rangeFormatting": {
|
||||
"enable": false
|
||||
}
|
||||
},
|
||||
"semanticHighlighting": {
|
||||
"doc": {
|
||||
"comment": {
|
||||
"inject": {
|
||||
"enable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"nonStandardTokens": true,
|
||||
"operator": {
|
||||
"enable": true,
|
||||
"specialization": {
|
||||
"enable": false
|
||||
}
|
||||
},
|
||||
"punctuation": {
|
||||
"enable": false,
|
||||
"separate": {
|
||||
"macro": {
|
||||
"bang": false
|
||||
}
|
||||
},
|
||||
"specialization": {
|
||||
"enable": false
|
||||
}
|
||||
},
|
||||
"strings": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"signatureInfo": {
|
||||
"detail": "full",
|
||||
"documentation": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"workspace": {
|
||||
"symbol": {
|
||||
"search": {
|
||||
"kind": "only_types",
|
||||
"limit": 128,
|
||||
"scope": "workspace"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"trace": "verbose",
|
||||
"workspaceFolders": [
|
||||
{
|
||||
"uri": "$uri",
|
||||
"name": "$name"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"_description": "Used to download the runtime dependencies for running typescript-language-server. Obtained from https://github.com/typescript-language-server/typescript-language-server/releases",
|
||||
"runtimeDependencies": [
|
||||
{
|
||||
"id": "typescript",
|
||||
"description": "typescript package for Linux, OSX, and Windows. Both x64 and arm64 are supported.",
|
||||
"command": "npm install --prefix ./ typescript@5.5.4"
|
||||
},
|
||||
{
|
||||
"id": "typescript-language-server",
|
||||
"description": "typescript-language-server package for Linux, OSX, and Windows. Both x64 and arm64 are supported.",
|
||||
"command": "npm install --prefix ./ typescript-language-server@4.3.3"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
"""
|
||||
Provides TypeScript specific instantiation of the LanguageServer class. Contains various configurations and settings specific to TypeScript.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import shutil
|
||||
import subprocess
|
||||
from collections.abc import AsyncIterator
|
||||
from contextlib import asynccontextmanager
|
||||
from time import sleep
|
||||
|
||||
from overrides import override
|
||||
|
||||
from multilspy.language_server import LanguageServer
|
||||
from multilspy.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from multilspy.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from multilspy.multilspy_config import MultilspyConfig
|
||||
from multilspy.multilspy_logger import MultilspyLogger
|
||||
from multilspy.multilspy_utils import PlatformId, PlatformUtils
|
||||
|
||||
# Platform-specific imports
|
||||
if os.name != 'nt': # Unix-like systems
|
||||
import pwd
|
||||
else:
|
||||
# Dummy pwd module for Windows
|
||||
class pwd:
|
||||
@staticmethod
|
||||
def getpwuid(uid):
|
||||
return type('obj', (), {'pw_name': os.environ.get('USERNAME', 'unknown')})()
|
||||
|
||||
|
||||
# Conditionally import pwd module (Unix-only)
|
||||
if not PlatformUtils.get_platform_id().value.startswith("win"):
|
||||
import pwd
|
||||
|
||||
|
||||
class TypeScriptLanguageServer(LanguageServer):
|
||||
"""
|
||||
Provides TypeScript specific instantiation of the LanguageServer class. Contains various configurations and settings specific to TypeScript.
|
||||
"""
|
||||
|
||||
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
|
||||
"""
|
||||
Creates a TypeScriptLanguageServer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
ts_lsp_executable_path = self.setup_runtime_dependencies(logger, config)
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=ts_lsp_executable_path, cwd=repository_root_path),
|
||||
"typescript",
|
||||
)
|
||||
self.server_ready = asyncio.Event()
|
||||
|
||||
@override
|
||||
def is_ignored_dirname(self, dirname: str) -> bool:
|
||||
return super().is_ignored_dirname(dirname) or dirname in [
|
||||
"node_modules",
|
||||
"dist",
|
||||
"build",
|
||||
"coverage",
|
||||
]
|
||||
|
||||
def setup_runtime_dependencies(self, logger: MultilspyLogger, config: MultilspyConfig) -> str:
|
||||
"""
|
||||
Setup runtime dependencies for TypeScript Language Server.
|
||||
"""
|
||||
platform_id = PlatformUtils.get_platform_id()
|
||||
|
||||
valid_platforms = [
|
||||
PlatformId.LINUX_x64,
|
||||
PlatformId.LINUX_arm64,
|
||||
PlatformId.OSX,
|
||||
PlatformId.OSX_x64,
|
||||
PlatformId.OSX_arm64,
|
||||
PlatformId.WIN_x64,
|
||||
PlatformId.WIN_arm64,
|
||||
]
|
||||
assert platform_id in valid_platforms, f"Platform {platform_id} is not supported for multilspy javascript/typescript at the moment"
|
||||
|
||||
with open(os.path.join(os.path.dirname(__file__), "runtime_dependencies.json")) as f:
|
||||
d = json.load(f)
|
||||
del d["_description"]
|
||||
|
||||
runtime_dependencies = d.get("runtimeDependencies", [])
|
||||
tsserver_ls_dir = os.path.join(os.path.dirname(__file__), "static", "ts-lsp")
|
||||
tsserver_executable_path = os.path.join(tsserver_ls_dir, "typescript-language-server")
|
||||
|
||||
# Verify both node and npm are installed
|
||||
is_node_installed = shutil.which('node') is not None
|
||||
assert is_node_installed, "node is not installed or isn't in PATH. Please install NodeJS and try again."
|
||||
is_npm_installed = shutil.which('npm') is not None
|
||||
assert is_npm_installed, "npm is not installed or isn't in PATH. Please install npm and try again."
|
||||
|
||||
# Install typescript and typescript-language-server if not already installed
|
||||
if not os.path.exists(tsserver_ls_dir):
|
||||
os.makedirs(tsserver_ls_dir, exist_ok=True)
|
||||
for dependency in runtime_dependencies:
|
||||
# Windows doesn't support the 'user' parameter and doesn't have pwd module
|
||||
if PlatformUtils.get_platform_id().value.startswith("win"):
|
||||
subprocess.run(
|
||||
dependency["command"],
|
||||
shell=True,
|
||||
check=True,
|
||||
cwd=tsserver_ls_dir,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL
|
||||
)
|
||||
else:
|
||||
# On Unix-like systems, run as non-root user
|
||||
user = pwd.getpwuid(os.getuid()).pw_name
|
||||
subprocess.run(
|
||||
dependency["command"],
|
||||
shell=True,
|
||||
check=True,
|
||||
user=user,
|
||||
cwd=tsserver_ls_dir,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL
|
||||
)
|
||||
|
||||
tsserver_executable_path = os.path.join(tsserver_ls_dir, "node_modules", ".bin", "typescript-language-server")
|
||||
|
||||
assert os.path.exists(tsserver_executable_path), "typescript-language-server executable not found. Please install typescript-language-server and try again."
|
||||
return f"{tsserver_executable_path} --stdio"
|
||||
|
||||
def _get_initialize_params(self, repository_absolute_path: str) -> InitializeParams:
|
||||
"""
|
||||
Returns the initialize params for the TypeScript Language Server.
|
||||
"""
|
||||
with open(os.path.join(os.path.dirname(__file__), "initialize_params.json")) as f:
|
||||
d = json.load(f)
|
||||
|
||||
del d["_description"]
|
||||
|
||||
d["processId"] = os.getpid()
|
||||
assert d["rootPath"] == "$rootPath"
|
||||
d["rootPath"] = repository_absolute_path
|
||||
|
||||
assert d["rootUri"] == "$rootUri"
|
||||
d["rootUri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["uri"] == "$uri"
|
||||
d["workspaceFolders"][0]["uri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["name"] == "$name"
|
||||
d["workspaceFolders"][0]["name"] = os.path.basename(repository_absolute_path)
|
||||
|
||||
return d
|
||||
|
||||
@asynccontextmanager
|
||||
async def start_server(self) -> AsyncIterator["TypeScriptLanguageServer"]:
|
||||
"""
|
||||
Starts the TypeScript Language Server, waits for the server to be ready and yields the LanguageServer instance.
|
||||
|
||||
Usage:
|
||||
```
|
||||
async with lsp.start_server():
|
||||
# LanguageServer has been initialized and ready to serve requests
|
||||
await lsp.request_definition(...)
|
||||
await lsp.request_references(...)
|
||||
# Shutdown the LanguageServer on exit from scope
|
||||
# LanguageServer has been shutdown
|
||||
"""
|
||||
|
||||
async def register_capability_handler(params):
|
||||
assert "registrations" in params
|
||||
for registration in params["registrations"]:
|
||||
if registration["method"] == "workspace/executeCommand":
|
||||
self.initialize_searcher_command_available.set()
|
||||
# TypeScript doesn't have a direct equivalent to resolve_main_method
|
||||
# You might want to set a different flag or remove this line
|
||||
# self.resolve_main_method_available.set()
|
||||
return
|
||||
|
||||
async def execute_client_command_handler(params):
|
||||
return []
|
||||
|
||||
async def do_nothing(params):
|
||||
return
|
||||
|
||||
async def window_log_message(msg):
|
||||
self.logger.log(f"LSP: window/logMessage: {msg}", logging.INFO)
|
||||
|
||||
|
||||
async def check_experimental_status(params):
|
||||
"""
|
||||
Also listen for experimental/serverStatus as a backup signal
|
||||
"""
|
||||
if params.get("quiescent") == True:
|
||||
self.server_ready.set()
|
||||
self.completions_available.set()
|
||||
|
||||
self.server.on_request("client/registerCapability", register_capability_handler)
|
||||
self.server.on_notification("window/logMessage", window_log_message)
|
||||
self.server.on_request("workspace/executeClientCommand", execute_client_command_handler)
|
||||
self.server.on_notification("$/progress", do_nothing)
|
||||
self.server.on_notification("textDocument/publishDiagnostics", do_nothing)
|
||||
self.server.on_notification("experimental/serverStatus", check_experimental_status)
|
||||
|
||||
async with super().start_server():
|
||||
self.logger.log("Starting TypeScript server process", logging.INFO)
|
||||
await self.server.start()
|
||||
initialize_params = self._get_initialize_params(self.repository_root_path)
|
||||
|
||||
self.logger.log(
|
||||
"Sending initialize request from LSP client to LSP server and awaiting response",
|
||||
logging.INFO,
|
||||
)
|
||||
init_response = await self.server.send.initialize(initialize_params)
|
||||
|
||||
# TypeScript-specific capability checks
|
||||
assert init_response["capabilities"]["textDocumentSync"] == 2
|
||||
assert "completionProvider" in init_response["capabilities"]
|
||||
assert init_response["capabilities"]["completionProvider"] == {
|
||||
"triggerCharacters": ['.', '"', "'", '/', '@', '<'],
|
||||
"resolveProvider": True
|
||||
}
|
||||
|
||||
self.server.notify.initialized({})
|
||||
try:
|
||||
await asyncio.wait_for(self.server_ready.wait(), timeout=1.0)
|
||||
except asyncio.TimeoutError:
|
||||
self.logger.log("Timeout waiting for TypeScript server to become ready, proceeding anyway", logging.INFO)
|
||||
# Fallback: assume server is ready after timeout
|
||||
self.server_ready.set()
|
||||
self.completions_available.set()
|
||||
|
||||
yield self
|
||||
|
||||
@override
|
||||
# For some reason, the LS may need longer to process this, so we just retry
|
||||
async def _send_references_request(self, relative_file_path: str, line: int, column: int):
|
||||
# TODO: The LS doesn't return references contained in other files if it doesn't sleep. This is
|
||||
# despite the LS having processed requests already. I don't know what causes this, but sleeping
|
||||
# one second helps. It may be that sleeping only once is enough but that's hard to reliably test.
|
||||
# It may be that even this 1sec is not enough in larger TS projects, at some point we should find what
|
||||
# causes this and solve it.
|
||||
sleep(1)
|
||||
return await super()._send_references_request(relative_file_path, line, column)
|
||||
Reference in New Issue
Block a user