Skip to main content
Glama
jedi_server.py9.13 kB
""" Provides Python specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Python. """ import logging import os import pathlib from typing import cast from overrides import override from solidlsp.ls import SolidLanguageServer from solidlsp.ls_config import LanguageServerConfig from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.settings import SolidLSPSettings log = logging.getLogger(__name__) class JediServer(SolidLanguageServer): """ Provides Python specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Python. """ def __init__(self, config: LanguageServerConfig, repository_root_path: str, solidlsp_settings: SolidLSPSettings): """ Creates a JediServer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead. """ super().__init__( config, repository_root_path, ProcessLaunchInfo(cmd="jedi-language-server", cwd=repository_root_path), "python", solidlsp_settings, ) @override def is_ignored_dirname(self, dirname: str) -> bool: return super().is_ignored_dirname(dirname) or dirname in ["venv", "__pycache__"] @staticmethod def _get_initialize_params(repository_absolute_path: str) -> InitializeParams: """ Returns the initialize params for the Jedi Language Server. """ root_uri = pathlib.Path(repository_absolute_path).as_uri() initialize_params = { "processId": os.getpid(), "clientInfo": {"name": "Serena", "version": "0.1.0"}, "locale": "en", "rootPath": repository_absolute_path, "rootUri": root_uri, # Note: this is not necessarily the minimal set of capabilities... "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": list(range(1, 27))}, "tagSupport": {"valueSet": [1]}, "resolveSupport": {"properties": ["location.range"]}, }, "workspaceFolders": 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}, "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": list(range(1, 27))}, "hierarchicalDocumentSymbolSupport": True, "tagSupport": {"valueSet": [1]}, "labelSupport": True, }, "documentLink": {"dynamicRegistration": True, "tooltipSupport": True}, "typeDefinition": {"dynamicRegistration": True, "linkSupport": True}, "implementation": {"dynamicRegistration": True, "linkSupport": True}, "declaration": {"dynamicRegistration": True, "linkSupport": True}, "selectionRange": {"dynamicRegistration": True}, "callHierarchy": {"dynamicRegistration": 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}, }, "notebookDocument": {"synchronization": {"dynamicRegistration": True, "executionSummarySupport": True}}, "experimental": { "serverStatusNotification": True, "openServerLogs": True, }, }, # See https://github.com/pappasam/jedi-language-server?tab=readme-ov-file # We use the default options except for maxSymbols, where 0 means no limit "initializationOptions": { "workspace": { "symbols": {"ignoreFolders": [".nox", ".tox", ".venv", "__pycache__", "venv"], "maxSymbols": 0}, }, }, "trace": "verbose", "workspaceFolders": [ { "uri": root_uri, "name": os.path.basename(repository_absolute_path), } ], } return cast(InitializeParams, initialize_params) def _start_server(self) -> None: """ Starts the JEDI Language Server """ def execute_client_command_handler(params: dict) -> list: return [] def do_nothing(params: dict) -> None: return def check_experimental_status(params: dict) -> None: if params["quiescent"] == True: self.completions_available.set() def window_log_message(msg: dict) -> None: log.info(f"LSP: window/logMessage: {msg}") 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) log.info("Starting jedi-language-server server process") self.server.start() initialize_params = self._get_initialize_params(self.repository_root_path) log.info("Sending initialize request from LSP client to LSP server and awaiting response") init_response = self.server.send.initialize(initialize_params) assert init_response["capabilities"]["textDocumentSync"]["change"] == 2 # type: ignore assert "completionProvider" in init_response["capabilities"] assert init_response["capabilities"]["completionProvider"] == { "triggerCharacters": [".", "'", '"'], "resolveProvider": True, } self.server.notify.initialized({})

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/oraios/serena'

If you have feedback or need assistance with the MCP directory API, please join our Discord server