usse/scrape/venv/lib/python3.10/site-packages/esbonio/server/setup.py
2023-12-22 15:26:01 +01:00

136 lines
4.1 KiB
Python

from __future__ import annotations
import importlib
import inspect
import typing
from typing import Iterable
from typing import Type
from lsprotocol import types
if typing.TYPE_CHECKING:
from .server import EsbonioLanguageServer
def create_language_server(
server_cls: Type[EsbonioLanguageServer], modules: Iterable[str], *args, **kwargs
) -> EsbonioLanguageServer:
"""Create a new language server instance.
Parameters
----------
server_cls:
The class definition to create the server from.
modules:
The list of modules that should be loaded.
args, kwargs:
Any additional arguments that should be passed to the language server's
constructor.
"""
server = server_cls(*args, **kwargs)
for module in modules:
_load_module(server, module)
return _configure_lsp_methods(server)
def _configure_lsp_methods(server: EsbonioLanguageServer) -> EsbonioLanguageServer:
"""Configure method handlers for the portions of the LSP spec we support."""
@server.feature(types.INITIALIZE)
async def on_initialize(ls: EsbonioLanguageServer, params: types.InitializeParams):
ls.initialize(params)
@server.feature(types.TEXT_DOCUMENT_DID_CHANGE)
async def on_document_change(
ls: EsbonioLanguageServer, params: types.DidChangeTextDocumentParams
):
await call_features(ls, "document_change", params)
@server.feature(types.TEXT_DOCUMENT_DID_CLOSE)
async def on_document_close(
ls: EsbonioLanguageServer, params: types.DidCloseTextDocumentParams
):
await call_features(ls, "document_close", params)
@server.feature(types.TEXT_DOCUMENT_DID_OPEN)
async def on_document_open(
ls: EsbonioLanguageServer, params: types.DidOpenTextDocumentParams
):
await call_features(ls, "document_open", params)
@server.feature(types.TEXT_DOCUMENT_DID_SAVE)
async def on_document_save(
ls: EsbonioLanguageServer, params: types.DidSaveTextDocumentParams
):
# Record the version number of the document
doc = ls.workspace.get_document(params.text_document.uri)
doc.saved_version = doc.version or 0
await call_features(ls, "document_save", params)
@server.feature(types.TEXT_DOCUMENT_DOCUMENT_SYMBOL)
async def on_document_symbol(
ls: EsbonioLanguageServer, params: types.DocumentSymbolParams
):
return await call_features_return_first(ls, "document_symbol", params)
return server
async def call_features(ls: EsbonioLanguageServer, method: str, *args, **kwargs):
"""Call all features."""
for cls, feature in ls:
try:
impl = getattr(feature, method)
result = impl(*args, **kwargs)
if inspect.isawaitable(result):
await result
except Exception:
name = f"{cls.__name__}"
ls.logger.error("Error in '%s.%s' handler", name, method, exc_info=True)
async def call_features_return_first(
ls: EsbonioLanguageServer, method: str, *args, **kwargs
):
"""Call all features, returning the first non ``None`` result we find."""
for cls, feature in ls:
try:
impl = getattr(feature, method)
result = impl(*args, **kwargs)
if inspect.isawaitable(result):
await result
if result is not None:
return result
except Exception:
name = f"{cls.__name__}"
ls.logger.error("Error in '%s.%s' handler", name, method, exc_info=True)
def _load_module(server: EsbonioLanguageServer, modname: str):
"""Load an extension module by calling its ``esbonio_setup`` function, if it exists."""
try:
module = importlib.import_module(modname)
except ImportError:
server.logger.error("Unable to import module '%s'", modname, exc_info=True)
return None
setup = getattr(module, "esbonio_setup", None)
if setup is None:
server.logger.debug(
"Skipping module '%s', missing 'esbonio_setup' function", modname
)
return None
server.load_extension(modname, setup)