refactor(lsp): replace controller layer with client module and LSPManager orchestration
* Rename legacy controller subsystem (LSPController, websocket controller, controller events, and base classes)
into clarified client module for LSP communication
* Structure around LSPManager and LSPManagerClient to handle orchestration and client lifecycle
* Update plugin integration to use LSPManager instead of LSPController
* Simplify architecture by reducing controller indirection
This commit is contained in:
3
plugins/code/ui/lsp_manager/client/__init__.py
Normal file
3
plugins/code/ui/lsp_manager/client/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
LSP Clients Module
|
||||||
|
"""
|
||||||
@@ -10,13 +10,13 @@ from gi.repository import GLib
|
|||||||
# Application imports
|
# Application imports
|
||||||
from libs.dto.code.lsp.lsp_messages import get_message_str
|
from libs.dto.code.lsp.lsp_messages import get_message_str
|
||||||
from libs.dto.code.lsp.lsp_message_structs import LSPResponseTypes, ClientRequest, ClientNotification
|
from libs.dto.code.lsp.lsp_message_structs import LSPResponseTypes, ClientRequest, ClientNotification
|
||||||
from .lsp_controller_websocket import LSPControllerWebsocket
|
from .lsp_client_websocket import LSPClientWebsocket
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LSPController(LSPControllerWebsocket):
|
class LSPClient(LSPClientWebsocket):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(LSPController, self).__init__()
|
super(LSPClient, self).__init__()
|
||||||
|
|
||||||
# https://github.com/microsoft/multilspy/tree/main/src/multilspy/language_servers
|
# https://github.com/microsoft/multilspy/tree/main/src/multilspy/language_servers
|
||||||
# initialize-params-slim.json was created off of jedi_language_server one
|
# initialize-params-slim.json was created off of jedi_language_server one
|
||||||
@@ -3,12 +3,12 @@
|
|||||||
# Lib imports
|
# Lib imports
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from .lsp_controller_events import LSPControllerEvents
|
from .lsp_client_events import LSPClientEvents
|
||||||
from libs.dto.code.lsp.lsp_message_structs import ClientRequest, ClientNotification
|
from libs.dto.code.lsp.lsp_message_structs import ClientRequest, ClientNotification
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LSPControllerBase(LSPControllerEvents):
|
class LSPClientBase(LSPClientEvents):
|
||||||
def _send_message(self, data: ClientRequest or ClientNotification):
|
def _send_message(self, data: ClientRequest or ClientNotification):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ from libs.dto.code.lsp.lsp_messages import symbols_request
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LSPControllerEvents:
|
class LSPClientEvents:
|
||||||
def send_initialize_message(self, init_ops: dict, workspace_file: str, workspace_uri: str):
|
def send_initialize_message(self, init_ops: dict, workspace_file: str, workspace_uri: str):
|
||||||
folder_name = os.path.basename(workspace_file)
|
folder_name = os.path.basename(workspace_file)
|
||||||
|
|
||||||
@@ -10,12 +10,12 @@ from libs.dto.code.lsp.lsp_message_structs import \
|
|||||||
LSPResponseTypes, ClientRequest, ClientNotification, \
|
LSPResponseTypes, ClientRequest, ClientNotification, \
|
||||||
LSPResponseRequest, LSPResponseNotification, LSPIDResponseNotification
|
LSPResponseRequest, LSPResponseNotification, LSPIDResponseNotification
|
||||||
|
|
||||||
from .lsp_controller_base import LSPControllerBase
|
from .lsp_client_base import LSPClientBase
|
||||||
from .websocket_client import WebsocketClient
|
from .websocket_client import WebsocketClient
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LSPControllerWebsocket(LSPControllerBase):
|
class LSPClientWebsocket(LSPClientBase):
|
||||||
def _send_message(self, data: ClientRequest | ClientNotification):
|
def _send_message(self, data: ClientRequest | ClientNotification):
|
||||||
if not data: return
|
if not data: return
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
"""
|
|
||||||
Plugin Controller Module
|
|
||||||
"""
|
|
||||||
@@ -8,14 +8,14 @@ from libs.dto.code.lsp.lsp_message_structs import LSPResponseTypes, LSPResponseR
|
|||||||
from .provider import Provider
|
from .provider import Provider
|
||||||
from .provider_response_cache import ProviderResponseCache
|
from .provider_response_cache import ProviderResponseCache
|
||||||
from .lsp_manager_ui import LSPManagerUI
|
from .lsp_manager_ui import LSPManagerUI
|
||||||
from .lsp_client_controller import LSPClientController
|
from .lsp_manager_client import LSPManagerClient
|
||||||
from .handlers.registry import HandlerRegistry
|
from .handlers.registry import HandlerRegistry
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LSPController:
|
class LSPManager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(LSPController, self).__init__()
|
super(LSPManager, self).__init__()
|
||||||
|
|
||||||
self._init()
|
self._init()
|
||||||
self._load_widgets()
|
self._load_widgets()
|
||||||
@@ -25,7 +25,7 @@ class LSPController:
|
|||||||
def _init(self):
|
def _init(self):
|
||||||
self.provider: Provider = Provider()
|
self.provider: Provider = Provider()
|
||||||
self.response_cache: ProviderResponseCache = ProviderResponseCache()
|
self.response_cache: ProviderResponseCache = ProviderResponseCache()
|
||||||
self.lsp_client_controller: LSPClientController = LSPClientController()
|
self.lsp_manager_client: LSPManagerClient = LSPManagerClient()
|
||||||
self.handler_registry: HandlerRegistry = HandlerRegistry()
|
self.handler_registry: HandlerRegistry = HandlerRegistry()
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
@@ -34,28 +34,27 @@ class LSPController:
|
|||||||
self.lsp_manager_ui.close_client = self.close_client
|
self.lsp_manager_ui.close_client = self.close_client
|
||||||
|
|
||||||
def _do_bind_mapping(self):
|
def _do_bind_mapping(self):
|
||||||
self.response_cache.process_file_load = self.lsp_client_controller.process_file_load
|
self.response_cache.process_file_load = self.lsp_manager_client.process_file_load
|
||||||
self.response_cache.process_file_close = self.lsp_client_controller.process_file_close
|
self.response_cache.process_file_close = self.lsp_manager_client.process_file_close
|
||||||
self.response_cache.process_file_save = self.lsp_client_controller.process_file_save
|
self.response_cache.process_file_save = self.lsp_manager_client.process_file_save
|
||||||
self.response_cache.process_file_change = self.lsp_client_controller.process_file_change
|
self.response_cache.process_file_change = self.lsp_manager_client.process_file_change
|
||||||
self.provider.response_cache = self.response_cache
|
self.provider.response_cache = self.response_cache
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_client(
|
def create_client(
|
||||||
self,
|
self,
|
||||||
lang_id: str = "python",
|
lang_id: str = "python",
|
||||||
workspace_uri: str = "",
|
workspace_uri: str = "",
|
||||||
init_opts: dict = {}
|
init_opts: dict = {}
|
||||||
) -> bool:
|
) -> bool:
|
||||||
client = self.lsp_client_controller.create_client(
|
client = self.lsp_manager_client.create_client(
|
||||||
lang_id, workspace_uri, init_opts
|
lang_id, workspace_uri, init_opts
|
||||||
)
|
)
|
||||||
handler = self.handler_registry.get_handler(lang_id)
|
handler = self.handler_registry.get_handler(lang_id)
|
||||||
self.lsp_client_controller.active_language_id = lang_id
|
self.lsp_manager_client.active_language_id = lang_id
|
||||||
|
|
||||||
if not client or not handler:
|
if not client or not handler:
|
||||||
logger.error(f"LSP Controller: Either 'client' or 'handler' didn't get created...'")
|
logger.error(f"LSP Manager: Either 'client' or 'handler' didn't get created...'")
|
||||||
self.close_client(lang_id)
|
self.close_client(lang_id)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -68,7 +67,7 @@ class LSPController:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def close_client(self, lang_id: str) -> bool:
|
def close_client(self, lang_id: str) -> bool:
|
||||||
self.lsp_client_controller.close_client(lang_id)
|
self.lsp_manager_client.close_client(lang_id)
|
||||||
self.handler_registry.close_handler(lang_id)
|
self.handler_registry.close_handler(lang_id)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -77,14 +76,14 @@ class LSPController:
|
|||||||
logger.debug(f"LSP Response: { lsp_response }")
|
logger.debug(f"LSP Response: { lsp_response }")
|
||||||
|
|
||||||
if isinstance(lsp_response, LSPResponseRequest):
|
if isinstance(lsp_response, LSPResponseRequest):
|
||||||
if not self.lsp_client_controller.active_language_id in self.lsp_client_controller.clients:
|
if not self.lsp_manager_client.active_language_id in self.lsp_manager_client.clients:
|
||||||
logger.debug(f"No LSP client for '{self.lsp_client_controller.active_language_id}', skipping 'server_response'")
|
logger.debug(f"No LSP client for '{self.lsp_manager_client.active_language_id}', skipping 'server_response'")
|
||||||
return
|
return
|
||||||
|
|
||||||
controller = self.lsp_client_controller.get_active_client()
|
controller = self.lsp_manager_client.get_active_client()
|
||||||
event = controller.get_event_by_id(lsp_response.id)
|
event = controller.get_event_by_id(lsp_response.id)
|
||||||
handler = self.handler_registry.get_handler(
|
handler = self.handler_registry.get_handler(
|
||||||
self.lsp_client_controller.active_language_id, event
|
self.lsp_manager_client.active_language_id, event
|
||||||
)
|
)
|
||||||
|
|
||||||
if not handler: return
|
if not handler: return
|
||||||
@@ -94,7 +93,6 @@ class LSPController:
|
|||||||
|
|
||||||
if not handler: return
|
if not handler: return
|
||||||
|
|
||||||
# TODO: Need to make default singleton so as to not need to set these here
|
|
||||||
handler.set_context(self.handler_registry)
|
handler.set_context(self.handler_registry)
|
||||||
handler.set_response_cache(self.response_cache)
|
handler.set_response_cache(self.response_cache)
|
||||||
handler.handle(lsp_response.method, lsp_response.params, None)
|
handler.handle(lsp_response.method, lsp_response.params, None)
|
||||||
@@ -5,13 +5,13 @@ from concurrent.futures import ThreadPoolExecutor
|
|||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from .mixins.lsp_client_events_mixin import LSPClientEventsMixin
|
from .mixins.lsp_client_events_mixin import LSPClientEventsMixin
|
||||||
from .controllers.lsp_controller import LSPController
|
from .client.lsp_client import LSPClient
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LSPClientController(LSPClientEventsMixin):
|
class LSPManagerClient(LSPClientEventsMixin):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(LSPClientController, self).__init__()
|
super(LSPManagerClient, self).__init__()
|
||||||
|
|
||||||
self._cache_refresh_timeout_id: int = None
|
self._cache_refresh_timeout_id: int = None
|
||||||
|
|
||||||
@@ -25,13 +25,13 @@ class LSPClientController(LSPClientEventsMixin):
|
|||||||
lang_id: str = "python",
|
lang_id: str = "python",
|
||||||
workspace_uri: str = "",
|
workspace_uri: str = "",
|
||||||
init_opts: dict = {}
|
init_opts: dict = {}
|
||||||
) -> LSPController:
|
) -> LSPClient:
|
||||||
if lang_id in self.clients: return None
|
if lang_id in self.clients: return None
|
||||||
|
|
||||||
address = "127.0.0.1"
|
address = "127.0.0.1"
|
||||||
port = 9999
|
port = 9999
|
||||||
uri = f"ws://{address}:{port}/{lang_id}"
|
uri = f"ws://{address}:{port}/{lang_id}"
|
||||||
client = LSPController()
|
client = LSPClient()
|
||||||
|
|
||||||
client.set_language(lang_id)
|
client.set_language(lang_id)
|
||||||
client.set_socket(uri)
|
client.set_socket(uri)
|
||||||
@@ -53,5 +53,5 @@ class LSPClientController(LSPClientEventsMixin):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_active_client(self) -> LSPController:
|
def get_active_client(self) -> LSPClient:
|
||||||
return self.clients[self.active_language_id]
|
return self.clients[self.active_language_id]
|
||||||
@@ -11,11 +11,11 @@ from libs.dto.states import SourceViewStates
|
|||||||
|
|
||||||
from plugins.plugin_types import PluginCode
|
from plugins.plugin_types import PluginCode
|
||||||
|
|
||||||
from .lsp_controller import LSPController
|
from .lsp_manager import LSPManager
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
lsp_controller = LSPController()
|
lsp_manager = LSPManager()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ class Plugin(PluginCode):
|
|||||||
def load(self):
|
def load(self):
|
||||||
window = self.request_ui_element("main-window")
|
window = self.request_ui_element("main-window")
|
||||||
|
|
||||||
lsp_controller.lsp_manager_ui.map_parent_resize_event(window)
|
lsp_manager.lsp_manager_ui.map_parent_resize_event(window)
|
||||||
|
|
||||||
event = Event_Factory.create_event("register_command",
|
event = Event_Factory.create_event("register_command",
|
||||||
command_name = "LSP Manager",
|
command_name = "LSP Manager",
|
||||||
@@ -43,7 +43,7 @@ class Plugin(PluginCode):
|
|||||||
event = Event_Factory.create_event(
|
event = Event_Factory.create_event(
|
||||||
"register_provider",
|
"register_provider",
|
||||||
provider_name = "LSP Completer",
|
provider_name = "LSP Completer",
|
||||||
provider = lsp_controller.provider,
|
provider = lsp_manager.provider,
|
||||||
language_ids = []
|
language_ids = []
|
||||||
)
|
)
|
||||||
self.emit_to("completion", event)
|
self.emit_to("completion", event)
|
||||||
@@ -55,14 +55,14 @@ class Plugin(PluginCode):
|
|||||||
self.emit_to("source_views", event)
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
source_view = event.response
|
source_view = event.response
|
||||||
lsp_controller.lsp_manager_ui.load_lsp_servers_config()
|
lsp_manager.lsp_manager_ui.load_lsp_servers_config()
|
||||||
lsp_controller.lsp_manager_ui.set_source_view(source_view)
|
lsp_manager.lsp_manager_ui.set_source_view(source_view)
|
||||||
lsp_controller.lsp_manager_ui.load_lsp_servers_config_placeholders()
|
lsp_manager.lsp_manager_ui.load_lsp_servers_config_placeholders()
|
||||||
|
|
||||||
lsp_controller.handler_registry.emit = self.emit
|
lsp_manager.handler_registry.emit = self.emit
|
||||||
lsp_controller.handler_registry.emit_to = self.emit_to
|
lsp_manager.handler_registry.emit_to = self.emit_to
|
||||||
lsp_controller.handler_registry._prompt_goto_request = self._prompt_goto_request
|
lsp_manager.handler_registry._prompt_goto_request = self._prompt_goto_request
|
||||||
lsp_controller.handler_registry._prompt_completion_request = self._prompt_completion_request
|
lsp_manager.handler_registry._prompt_completion_request = self._prompt_completion_request
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
@@ -98,7 +98,7 @@ class Plugin(PluginCode):
|
|||||||
event = Event_Factory.create_event(
|
event = Event_Factory.create_event(
|
||||||
"request_completion",
|
"request_completion",
|
||||||
view = view,
|
view = view,
|
||||||
provider = lsp_controller.provider
|
provider = lsp_manager.provider
|
||||||
)
|
)
|
||||||
self.emit_to("completion", event)
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ class Handler:
|
|||||||
column = iter.get_line_offset()
|
column = iter.get_line_offset()
|
||||||
|
|
||||||
if char_str == "g":
|
if char_str == "g":
|
||||||
lsp_controller.lsp_client_controller.process_goto_definition(
|
lsp_manager.lsp_manager_client.process_goto_definition(
|
||||||
file.ftype, file.fpath, line, column
|
file.ftype, file.fpath, line, column
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -130,4 +130,4 @@ class Handler:
|
|||||||
if char_str == "i":
|
if char_str == "i":
|
||||||
return
|
return
|
||||||
|
|
||||||
lsp_controller.lsp_manager_ui.hide() if lsp_controller.lsp_manager_ui.is_visible() else lsp_controller.lsp_manager_ui.show()
|
lsp_manager.lsp_manager_ui.hide() if lsp_manager.lsp_manager_ui.is_visible() else lsp_manager.lsp_manager_ui.show()
|
||||||
|
|||||||
Reference in New Issue
Block a user