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:
2026-03-12 00:04:08 -05:00
parent 52db0b8a31
commit 6cb66985aa
10 changed files with 50 additions and 52 deletions

View File

@@ -0,0 +1,3 @@
"""
LSP Clients Module
"""

View File

@@ -10,13 +10,13 @@ from gi.repository import GLib
# Application imports
from libs.dto.code.lsp.lsp_messages import get_message_str
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):
super(LSPController, self).__init__()
super(LSPClient, self).__init__()
# https://github.com/microsoft/multilspy/tree/main/src/multilspy/language_servers
# initialize-params-slim.json was created off of jedi_language_server one

View File

@@ -3,12 +3,12 @@
# Lib 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
class LSPControllerBase(LSPControllerEvents):
class LSPClientBase(LSPClientEvents):
def _send_message(self, data: ClientRequest or ClientNotification):
raise NotImplementedError

View File

@@ -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):
folder_name = os.path.basename(workspace_file)

View File

@@ -10,12 +10,12 @@ from libs.dto.code.lsp.lsp_message_structs import \
LSPResponseTypes, ClientRequest, ClientNotification, \
LSPResponseRequest, LSPResponseNotification, LSPIDResponseNotification
from .lsp_controller_base import LSPControllerBase
from .lsp_client_base import LSPClientBase
from .websocket_client import WebsocketClient
class LSPControllerWebsocket(LSPControllerBase):
class LSPClientWebsocket(LSPClientBase):
def _send_message(self, data: ClientRequest | ClientNotification):
if not data: return

View File

@@ -1,3 +0,0 @@
"""
Plugin Controller Module
"""

View File

@@ -8,14 +8,14 @@ from libs.dto.code.lsp.lsp_message_structs import LSPResponseTypes, LSPResponseR
from .provider import Provider
from .provider_response_cache import ProviderResponseCache
from .lsp_manager_ui import LSPManagerUI
from .lsp_client_controller import LSPClientController
from .lsp_manager_client import LSPManagerClient
from .handlers.registry import HandlerRegistry
class LSPController:
class LSPManager:
def __init__(self):
super(LSPController, self).__init__()
super(LSPManager, self).__init__()
self._init()
self._load_widgets()
@@ -25,7 +25,7 @@ class LSPController:
def _init(self):
self.provider: Provider = Provider()
self.response_cache: ProviderResponseCache = ProviderResponseCache()
self.lsp_client_controller: LSPClientController = LSPClientController()
self.lsp_manager_client: LSPManagerClient = LSPManagerClient()
self.handler_registry: HandlerRegistry = HandlerRegistry()
def _load_widgets(self):
@@ -34,28 +34,27 @@ class LSPController:
self.lsp_manager_ui.close_client = self.close_client
def _do_bind_mapping(self):
self.response_cache.process_file_load = self.lsp_client_controller.process_file_load
self.response_cache.process_file_close = self.lsp_client_controller.process_file_close
self.response_cache.process_file_save = self.lsp_client_controller.process_file_save
self.response_cache.process_file_change = self.lsp_client_controller.process_file_change
self.response_cache.process_file_load = self.lsp_manager_client.process_file_load
self.response_cache.process_file_close = self.lsp_manager_client.process_file_close
self.response_cache.process_file_save = self.lsp_manager_client.process_file_save
self.response_cache.process_file_change = self.lsp_manager_client.process_file_change
self.provider.response_cache = self.response_cache
def create_client(
self,
lang_id: str = "python",
workspace_uri: str = "",
init_opts: dict = {}
) -> bool:
client = self.lsp_client_controller.create_client(
client = self.lsp_manager_client.create_client(
lang_id, workspace_uri, init_opts
)
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:
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)
return False
@@ -68,7 +67,7 @@ class LSPController:
return True
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)
return True
@@ -77,14 +76,14 @@ class LSPController:
logger.debug(f"LSP Response: { lsp_response }")
if isinstance(lsp_response, LSPResponseRequest):
if not self.lsp_client_controller.active_language_id in self.lsp_client_controller.clients:
logger.debug(f"No LSP client for '{self.lsp_client_controller.active_language_id}', skipping 'server_response'")
if not self.lsp_manager_client.active_language_id in self.lsp_manager_client.clients:
logger.debug(f"No LSP client for '{self.lsp_manager_client.active_language_id}', skipping 'server_response'")
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)
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
@@ -94,7 +93,6 @@ class LSPController:
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_response_cache(self.response_cache)
handler.handle(lsp_response.method, lsp_response.params, None)

View File

@@ -5,13 +5,13 @@ from concurrent.futures import ThreadPoolExecutor
# Application imports
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):
super(LSPClientController, self).__init__()
super(LSPManagerClient, self).__init__()
self._cache_refresh_timeout_id: int = None
@@ -25,13 +25,13 @@ class LSPClientController(LSPClientEventsMixin):
lang_id: str = "python",
workspace_uri: str = "",
init_opts: dict = {}
) -> LSPController:
) -> LSPClient:
if lang_id in self.clients: return None
address = "127.0.0.1"
port = 9999
uri = f"ws://{address}:{port}/{lang_id}"
client = LSPController()
client = LSPClient()
client.set_language(lang_id)
client.set_socket(uri)
@@ -53,5 +53,5 @@ class LSPClientController(LSPClientEventsMixin):
return True
def get_active_client(self) -> LSPController:
def get_active_client(self) -> LSPClient:
return self.clients[self.active_language_id]

View File

@@ -11,11 +11,11 @@ from libs.dto.states import SourceViewStates
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):
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",
command_name = "LSP Manager",
@@ -43,7 +43,7 @@ class Plugin(PluginCode):
event = Event_Factory.create_event(
"register_provider",
provider_name = "LSP Completer",
provider = lsp_controller.provider,
provider = lsp_manager.provider,
language_ids = []
)
self.emit_to("completion", event)
@@ -55,14 +55,14 @@ class Plugin(PluginCode):
self.emit_to("source_views", event)
source_view = event.response
lsp_controller.lsp_manager_ui.load_lsp_servers_config()
lsp_controller.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()
lsp_manager.lsp_manager_ui.set_source_view(source_view)
lsp_manager.lsp_manager_ui.load_lsp_servers_config_placeholders()
lsp_controller.handler_registry.emit = self.emit
lsp_controller.handler_registry.emit_to = self.emit_to
lsp_controller.handler_registry._prompt_goto_request = self._prompt_goto_request
lsp_controller.handler_registry._prompt_completion_request = self._prompt_completion_request
lsp_manager.handler_registry.emit = self.emit
lsp_manager.handler_registry.emit_to = self.emit_to
lsp_manager.handler_registry._prompt_goto_request = self._prompt_goto_request
lsp_manager.handler_registry._prompt_completion_request = self._prompt_completion_request
def run(self):
...
@@ -98,7 +98,7 @@ class Plugin(PluginCode):
event = Event_Factory.create_event(
"request_completion",
view = view,
provider = lsp_controller.provider
provider = lsp_manager.provider
)
self.emit_to("completion", event)
@@ -121,7 +121,7 @@ class Handler:
column = iter.get_line_offset()
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
)
@@ -130,4 +130,4 @@ class Handler:
if char_str == "i":
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()