From 5ea69d899019e02b3bf6a03d1a61bc4a12f5ac59 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sun, 5 Nov 2023 00:36:55 -0500 Subject: [PATCH] More work on wiring LSP --- plugins/lsp_client/lsp_controller.py | 37 +++++---- plugins/lsp_client/plugin.py | 79 +++++++++++++++---- .../lsp_client/pylspclient/lsp_endpoint.py | 4 +- .../usr/share/newton/lsp_servers_config.json | 32 ++++++++ 4 files changed, 117 insertions(+), 35 deletions(-) create mode 100644 user_config/usr/share/newton/lsp_servers_config.json diff --git a/plugins/lsp_client/lsp_controller.py b/plugins/lsp_client/lsp_controller.py index 2a54af2..d967ae9 100644 --- a/plugins/lsp_client/lsp_controller.py +++ b/plugins/lsp_client/lsp_controller.py @@ -26,27 +26,22 @@ class LSPController: def __init__(self): super().__init__() - self.lsp_clients = [] + self.lsp_clients = {} - def create_client(self, language = "", server_proc = None): + def create_client(self, language = "", server_proc = None, initialization_options = None): if not language or not server_proc: return False - json_rpc_endpoint = pylspclient.JsonRpcEndpoint(server_proc.stdin, server_proc.stdout) - lsp_endpoint = pylspclient.LspEndpoint(json_rpc_endpoint) - lsp_client = pylspclient.LspClient(lsp_endpoint) - - self.lsp_clients.append(lsp_client) - root_path = None root_uri = 'file:///home/abaddon/Coding/Projects/Active/C_n_CPP_Projects/gtk/Newton/src/' workspace_folders = [{'name': 'python-lsp', 'uri': root_uri}] + lsp_client = self._generate_client(language, server_proc) lsp_client.initialize( processId = server_proc.pid, \ rootPath = root_path, \ rootUri = root_uri, \ - initializationOptions = None, \ + initializationOptions = initialization_options, \ capabilities = Capabilities.data, \ trace = "off", \ workspaceFolders = workspace_folders @@ -55,6 +50,17 @@ class LSPController: lsp_client.initialized() return True + + def _generate_client(self, language = "", server_proc = None): + if not language or not server_proc: return False + + json_rpc_endpoint = pylspclient.JsonRpcEndpoint(server_proc.stdin, server_proc.stdout) + lsp_endpoint = pylspclient.LspEndpoint(json_rpc_endpoint) + lsp_client = pylspclient.LspClient(lsp_endpoint) + + self.lsp_clients[language] = lsp_client + return lsp_client + def create_lsp_server(self, server_command: [] = []): if not server_command: return None @@ -62,16 +68,13 @@ class LSPController: server_proc = subprocess.Popen(server_command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE) read_pipe = ReadPipe(server_proc.stderr) read_pipe.start() - return server_proc def _shutting_down(self): - for lsp_client in self.lsp_clients: - lsp_client.shutdown() - lsp_client.exit() - - - - + keys = self.lsp_clients.keys() + for key in keys: + print(f"LSP Server: ( {key} ) Shutting Down...") + self.lsp_clients[key].shutdown() + self.lsp_clients[key].exit() diff --git a/plugins/lsp_client/plugin.py b/plugins/lsp_client/plugin.py index 3571cc8..d92dccd 100644 --- a/plugins/lsp_client/plugin.py +++ b/plugins/lsp_client/plugin.py @@ -1,4 +1,6 @@ # Python imports +import os +import json # Lib imports @@ -14,22 +16,28 @@ class Plugin(PluginBase): def __init__(self): super().__init__() - self.name = "LSP Client" # NOTE: Need to remove after establishing private bidirectional 1-1 message bus - # where self.name should not be needed for message comms - self.lsp_controller = None - + self.name = "LSP Client" # NOTE: Need to remove after establishing private bidirectional 1-1 message bus + # where self.name should not be needed for message comms + self.lsp_config_path: str = os.path.dirname(os.path.realpath(__file__)) + "/../../lsp_servers_config.json" + self.lsp_servers_config: dict = {} + self.lsp_controller = None + self.lsp_client = None + self.lsp_disabled = False def generate_reference_ui_element(self): ... def run(self): - self.lsp_controller = LSPController() - server_proc = self.lsp_controller.create_lsp_server(["/usr/bin/clangd"]) - client_created = self.lsp_controller.create_client("c,cpp", server_proc) - if not client_created: - file_type = "dummy" - text = f"LSP could not be created for file type: {file_type} ..." + if os.path.exists(self.lsp_config_path): + with open(self.lsp_config_path, "r") as f: + self.lsp_servers_config = json.load(f) + else: + self.lsp_disabled = True + text = f"LSP NOT Enabled.\nFile:\n\t{self.lsp_config_path}\ndoes no exsist..." self._event_system.emit("bubble_message", ("warning", self.name, text,)) + + if not self.lsp_disabled: + self.lsp_controller = LSPController() # language_id = pylspclient.lsp_structs.LANGUAGE_IDENTIFIER.C # version = 1 @@ -60,21 +68,62 @@ class Plugin(PluginBase): self._event_system.subscribe("do_get_implementation", self._do_get_implementation) def _shutting_down(self): - self.lsp_controller._shutting_down() + if self.lsp_controller: + self.lsp_controller._shutting_down() def _set_active_src_view(self, source_view): + if self.lsp_disabled: return + self._active_src_view = source_view self._buffer = source_view.get_buffer() self._file_type = source_view.get_filetype() + + if self._file_type in self.lsp_servers_config.keys(): + self.set_lsp_server() + else: + text = f"LSP could not be created for file type: {self._file_type} ..." + self._event_system.emit("bubble_message", ("warning", self.name, text,)) + + def set_lsp_server(self): + if self._file_type in self.lsp_controller.lsp_clients.keys(): + self.lsp_client = self.lsp_controller.lsp_clients[self._file_type] + else: + self.lsp_client = self.load_lsp_server() + + def load_lsp_server(self): + command = self.lsp_servers_config[self._file_type]["command"] + if command: + server_proc = self.lsp_controller.create_lsp_server(command) + client_created = self.lsp_controller.create_client(self._file_type, server_proc) + + if client_created: + return self.lsp_controller.lsp_clients[self._file_type] + else: + text = f"LSP could not be created for file type: {self._file_type} ..." + self._event_system.emit("bubble_message", ("warning", self.name, text,)) + + return None + def _buffer_changed_first_load(self, buffer): + if self.lsp_disabled: return + self._buffer = buffer def _buffer_changed(self, buffer): - ... + if self.lsp_disabled: return def _do_goto(self): - ... - + if self.lsp_disabled: return + + iter = self._buffer.get_iter_at_mark( self._buffer.get_insert() ) + line = iter.get_line() + 1 + offset = iter.get_line_offset() + 1 + uri = self._active_src_view.get_current_filepath().get_uri() + result = self.lsp_client.declaration(pylspclient.lsp_structs.TextDocumentIdentifier(uri), pylspclient.lsp_structs.Position(line, offset)) + + print(result) + + def _do_get_implementation(self): - ... \ No newline at end of file + if self.lsp_disabled: return \ No newline at end of file diff --git a/plugins/lsp_client/pylspclient/lsp_endpoint.py b/plugins/lsp_client/pylspclient/lsp_endpoint.py index 2ddeab2..c442db9 100644 --- a/plugins/lsp_client/pylspclient/lsp_endpoint.py +++ b/plugins/lsp_client/pylspclient/lsp_endpoint.py @@ -32,9 +32,7 @@ class LspEndpoint(threading.Thread): while not self.shutdown_flag: try: jsonrpc_message = self.json_rpc_endpoint.recv_response() - if jsonrpc_message is None: - print("LSP Server Shutting Down...") - break + if jsonrpc_message is None: break method = jsonrpc_message.get("method") result = jsonrpc_message.get("result") diff --git a/user_config/usr/share/newton/lsp_servers_config.json b/user_config/usr/share/newton/lsp_servers_config.json new file mode 100644 index 0000000..3f90d1f --- /dev/null +++ b/user_config/usr/share/newton/lsp_servers_config.json @@ -0,0 +1,32 @@ +{ + "sh": { + "info": "", + "command": [], + "initialization_options": {} + }, + "python": { + "info": "https://pypi.org/project/jedi-language-server/", + "command": ["jedi-language-server"], + "initialization_options": {} + }, + "python3": { + "info": "https://pypi.org/project/jedi-language-server/", + "command": ["jedi-language-server"], + "initialization_options": {} + }, + "c": { + "info": "https://clangd.llvm.org/", + "command": ["/usr/bin/clangd"], + "initialization_options": {} + }, + "cpp": { + "info": "https://clangd.llvm.org/", + "command": ["/usr/bin/clangd"], + "initialization_options": {} + }, + "java": { + "info": "https://download.eclipse.org/jdtls/", + "command": ["java-language-server"], + "initialization_options": {} + } +} \ No newline at end of file