mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-03 05:12:50 +00:00
WIP: preliminary support for clojure-lsp
This commit is contained in:
1 parent
413097c8f9
commit
c7ac81b895
3 files changed
+547
No files matched your search
@@ -0,0 +1,178 @@
|
||||
"""
|
||||
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 ClojureLSP(LanguageServer):
|
||||
"""
|
||||
Provides a clojure-lsp specific instantiation of the LanguageServer class. Contains various configurations and settings specific to clojure.
|
||||
"""
|
||||
|
||||
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
|
||||
"""
|
||||
Creates a ClojureLSP instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
clojure_lsp_executable_path = self.setup_runtime_dependencies(logger, config)
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=clojure_lsp_executable_path, cwd=repository_root_path),
|
||||
"clojure",
|
||||
)
|
||||
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 clojure-lsp.
|
||||
"""
|
||||
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"]
|
||||
|
||||
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]
|
||||
|
||||
clojurelsp_ls_dir = os.path.join(os.path.dirname(__file__), "static", "clojure-lsp")
|
||||
clojurelsp_executable_path = os.path.join(clojurelsp_ls_dir, dependency["binaryName"])
|
||||
if not os.path.exists(clojurelsp_ls_dir):
|
||||
os.makedirs(clojurelsp_ls_dir)
|
||||
FileUtils.download_and_extract_archive(
|
||||
logger, dependency["url"], clojurelsp_ls_dir, dependency["archiveType"]
|
||||
)
|
||||
assert os.path.exists(clojurelsp_executable_path)
|
||||
os.chmod(clojurelsp_executable_path, stat.S_IEXEC)
|
||||
|
||||
return clojurelsp_executable_path
|
||||
|
||||
def _get_initialize_params(self, repository_absolute_path: str) -> InitializeParams:
|
||||
"""
|
||||
Returns the init params for clojure-lsp.
|
||||
"""
|
||||
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["ClojureLSP"]:
|
||||
"""
|
||||
Starts the Clojure 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 clojure-lsp 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
|
||||
|
||||
await self.server.shutdown()
|
||||
await self.server.stop()
|
||||
@@ -0,0 +1,332 @@
|
||||
{
|
||||
"_description": "Parameters sent by multilspy to initialize clojure-lsp (LSP v3.17)",
|
||||
"processId": "os.getpid()",
|
||||
"clientInfo": {
|
||||
"name": "multilspy",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"locale": "en",
|
||||
"rootPath": "$rootPath",
|
||||
"rootUri": "$rootUri",
|
||||
"capabilities": {
|
||||
"workspace": {
|
||||
"applyEdit": true,
|
||||
"workspaceEdit": {
|
||||
"documentChanges": true,
|
||||
"resourceOperations": [
|
||||
"create",
|
||||
"rename",
|
||||
"delete"
|
||||
]
|
||||
},
|
||||
"configuration": 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
|
||||
},
|
||||
"workspaceFolders": true,
|
||||
"semanticTokens": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"codeLens": {
|
||||
"refreshSupport": true
|
||||
},
|
||||
"fileOperations": {
|
||||
"dynamicRegistration": true,
|
||||
"didRename": true,
|
||||
"willRename": true
|
||||
}
|
||||
},
|
||||
"textDocument": {
|
||||
"publishDiagnostics": {
|
||||
"relatedInformation": true,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1,
|
||||
2
|
||||
]
|
||||
},
|
||||
"codeDescriptionSupport": true,
|
||||
"dataSupport": true
|
||||
},
|
||||
"synchronization": {
|
||||
"dynamicRegistration": true,
|
||||
"didSave": true
|
||||
},
|
||||
"completion": {
|
||||
"dynamicRegistration": true,
|
||||
"contextSupport": true,
|
||||
"completionItem": {
|
||||
"snippetSupport": true,
|
||||
"documentationFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
],
|
||||
"deprecatedSupport": true,
|
||||
"preselectSupport": true,
|
||||
"tagSupport": {
|
||||
"valueSet": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"insertReplaceSupport": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"documentation",
|
||||
"detail",
|
||||
"additionalTextEdits"
|
||||
]
|
||||
}
|
||||
},
|
||||
"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
|
||||
]
|
||||
}
|
||||
},
|
||||
"hover": {
|
||||
"dynamicRegistration": true,
|
||||
"contentFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
]
|
||||
},
|
||||
"signatureHelp": {
|
||||
"dynamicRegistration": true,
|
||||
"signatureInformation": {
|
||||
"documentationFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
],
|
||||
"parameterInformation": {
|
||||
"labelOffsetSupport": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"declaration": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"definition": {
|
||||
"dynamicRegistration": true,
|
||||
"linkSupport": true
|
||||
},
|
||||
"implementation": {
|
||||
"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
|
||||
},
|
||||
"codeAction": {
|
||||
"dynamicRegistration": true,
|
||||
"isPreferredSupport": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"edit"
|
||||
]
|
||||
},
|
||||
"codeActionLiteralSupport": {
|
||||
"codeActionKind": {
|
||||
"valueSet": [
|
||||
"",
|
||||
"quickfix",
|
||||
"refactor",
|
||||
"refactor.extract",
|
||||
"refactor.inline",
|
||||
"refactor.rewrite",
|
||||
"source",
|
||||
"source.organizeImports"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"codeLens": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"formatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"rangeFormatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"rename": {
|
||||
"dynamicRegistration": true,
|
||||
"prepareSupport": true
|
||||
},
|
||||
"foldingRange": {
|
||||
"dynamicRegistration": true,
|
||||
"lineFoldingOnly": true
|
||||
},
|
||||
"selectionRange": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"semanticTokens": {
|
||||
"dynamicRegistration": true,
|
||||
"tokenTypes": [
|
||||
"namespace",
|
||||
"class",
|
||||
"function",
|
||||
"method",
|
||||
"variable",
|
||||
"keyword",
|
||||
"string",
|
||||
"comment",
|
||||
"number",
|
||||
"regexp",
|
||||
"operator",
|
||||
"macro"
|
||||
],
|
||||
"tokenModifiers": [
|
||||
"declaration",
|
||||
"definition",
|
||||
"readonly",
|
||||
"static",
|
||||
"deprecated",
|
||||
"documentation"
|
||||
],
|
||||
"formats": [
|
||||
"relative"
|
||||
],
|
||||
"requests": {
|
||||
"range": true,
|
||||
"full": {
|
||||
"delta": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"linkedEditingRange": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"callHierarchy": {
|
||||
"dynamicRegistration": true
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
"workDoneProgress": true,
|
||||
"showMessage": {
|
||||
"messageActionItem": {
|
||||
"additionalPropertiesSupport": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"general": {
|
||||
"positionEncodings": [
|
||||
"utf-16"
|
||||
]
|
||||
},
|
||||
"experimental": {
|
||||
"testTree": true,
|
||||
"projectTree": true
|
||||
}
|
||||
},
|
||||
"initializationOptions": {
|
||||
"dependency-scheme": "jar",
|
||||
"document-formatting?": true,
|
||||
"document-range-formatting?": true,
|
||||
"text-document-sync-kind": "incremental",
|
||||
"semantic-tokens?": true
|
||||
},
|
||||
"trace": "verbose",
|
||||
"workspaceFolders": [
|
||||
{
|
||||
"uri": "$uri",
|
||||
"name": "$name"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"_description": "Binary distributions of clojure-lsp.",
|
||||
"runtimeDependencies": [
|
||||
{
|
||||
"id": "clojure-lsp",
|
||||
"description": "clojure-lsp for OSX (ARM64)",
|
||||
"url": "https://github.com/clojure-lsp/clojure-lsp/releases/latest/download/clojure-lsp-native-macos-aarch64.zip",
|
||||
"platformId": "osx-arm64",
|
||||
"archiveType": "zip",
|
||||
"binaryName": "clojure-lsp"
|
||||
},
|
||||
{
|
||||
"id": "clojure-lsp",
|
||||
"description": "clojure-lsp for Linux (ARM64)",
|
||||
"url": "https://github.com/clojure-lsp/clojure-lsp/releases/latest/download/clojure-lsp-native-linux-aarch64.zip",
|
||||
"platformId": "linux-arm64",
|
||||
"archiveType": "zip",
|
||||
"binaryName": "clojure-lsp"
|
||||
},
|
||||
{
|
||||
"id": "clojure-lsp",
|
||||
"description": "clojure-lsp for Linux (x64)",
|
||||
"url": "https://github.com/clojure-lsp/clojure-lsp/releases/latest/download/clojure-lsp-native-linux-amd64.zip",
|
||||
"platformId": "linux-x64",
|
||||
"archiveType": "zip",
|
||||
"binaryName": "clojure-lsp"
|
||||
},
|
||||
{
|
||||
"id": "clojure-lsp",
|
||||
"description": "clojure-lsp for Windows (x64)",
|
||||
"url": "https://github.com/clojure-lsp/clojure-lsp/releases/latest/download/clojure-lsp-native-windows-amd64.zip",
|
||||
"platformId": "win-x64",
|
||||
"archiveType": "zip",
|
||||
"binaryName": "clojure-lsp"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user