diff --git a/src/core/controllers/lsp_controller.py b/src/core/controllers/lsp_controller.py index b04f738..b87904c 100644 --- a/src/core/controllers/lsp_controller.py +++ b/src/core/controllers/lsp_controller.py @@ -1,5 +1,4 @@ # Python imports -import os import signal import subprocess import threading @@ -9,7 +8,7 @@ import json from gi.repository import GLib # Application imports -from libs.dto.lsp_messages import LEN_HEADER, TYPE_HEADER, get_message_str, get_message_obj, definition_query, references_query, symbols_query +from libs.dto.lsp_messages import LEN_HEADER, TYPE_HEADER, get_message_str, get_message_obj from libs.dto.lsp_message_structs import \ LSPResponseTypes, ClientRequest, ClientNotification, LSPResponseRequest, LSPResponseNotification from .lsp_controller_events import LSPControllerEvents @@ -48,9 +47,6 @@ class LSPController(LSPControllerEvents): def _subscribe_to_events(self): - # event_system.subscribe("client-send-request", self._client_send_request) - # event_system.subscribe("client-send-notification", self._client_send_notification) - event_system.subscribe("textDocument/didOpen", self._lsp_did_open) # event_system.subscribe("textDocument/didSave", self._lsp_did_save) # event_system.subscribe("textDocument/didClose", self._lsp_did_close) @@ -58,26 +54,6 @@ class LSPController(LSPControllerEvents): event_system.subscribe("textDocument/definition", self._lsp_goto) event_system.subscribe("textDocument/completion", self._lsp_completion) - def _client_send_request(self, method: str, uri: str, line: int, character: int): - if not method: return - - if "textDocument/definition": - params = symbols_query - elif "textDocument/references": - params = symbols_query - elif "textDocument/documentSymbol": - params = symbols_query - - params["textDocument"]["uri"] = uri - params["textDocument"]["languageId"] = self._language - params["position"]["line"] = line - params["position"]["character"] = character - - self.send_request(method, params) - - def _client_send_notification(self, method: str, line: int, char: int): - if not method: return - self.send_notification(method, params) def set_language(self, language): self._language = language @@ -91,25 +67,6 @@ class LSPController(LSPControllerEvents): def unset_start_command(self): self._start_command = None - def send_initialize_message(self, init_ops: str, workspace_file: str, workspace_uri: str): - folder_name = os.path.basename(workspace_file) - - self._init_params["processId"] = settings_manager.get_app_pid() - self._init_params["rootPath"] = workspace_file - self._init_params["rootUri"] = workspace_uri - self._init_params["workspaceFolders"] = [ - { - "name": folder_name, - "uri": workspace_uri - } - ] - - self._init_params["initializationOptions"] = get_message_obj(init_ops) - self.send_request("initialize", self._init_params) - - def send_initialized_message(self): - self.send_notification("initialized") - def send_notification(self, method: str, params: {} = {}): self._send_message( ClientNotification(method, params) ) @@ -237,4 +194,4 @@ class LSPController(LSPControllerEvents): def handle_lsp_response(self, lsp_response: LSPResponseTypes): self.log_list.add_log_entry("LSP Response", lsp_response) - event_system.emit("respond-to-client", (get_message_str(lsp_response),)) + event_system.emit("respond-to-client", (get_message_str(lsp_response),)) \ No newline at end of file diff --git a/src/core/controllers/lsp_controller_events.py b/src/core/controllers/lsp_controller_events.py index 9fefe35..1cc8295 100644 --- a/src/core/controllers/lsp_controller_events.py +++ b/src/core/controllers/lsp_controller_events.py @@ -1,15 +1,34 @@ # Python imports +import os # Lib imports from gi.repository import GLib # Application imports -# from libs.dto.lsp_messages import LEN_HEADER, TYPE_HEADER, get_message_str, get_message_obj, definition_query, references_query, symbols_query -from libs.dto.lsp_messages import didopen_notification +from libs.dto.lsp_messages import get_message_obj, didopen_notification, completion_request, didchange_notification class LSPControllerEvents: + def send_initialize_message(self, init_ops: str, workspace_file: str, workspace_uri: str): + folder_name = os.path.basename(workspace_file) + + self._init_params["processId"] = settings_manager.get_app_pid() + self._init_params["rootPath"] = workspace_file + self._init_params["rootUri"] = workspace_uri + self._init_params["workspaceFolders"] = [ + { + "name": folder_name, + "uri": workspace_uri + } + ] + + self._init_params["initializationOptions"] = get_message_obj(init_ops) + self.send_request("initialize", self._init_params) + + def send_initialized_message(self): + self.send_notification("initialized") + def _lsp_did_open(self, data: dict): method = data["method"] params = didopen_notification["params"] @@ -21,23 +40,30 @@ class LSPControllerEvents: GLib.idle_add( self.send_notification, method, params ) def _lsp_did_save(self, data: dict): - # self.send_notification(method, params) + # GLib.idle_add( self.send_notification, method, params ) ... def _lsp_did_close(self, data: dict): - # self.send_notification(method, params) + # GLib.idle_add( self.send_notification, method, params ) ... def _lsp_did_change(self, data: dict): - method = data["method"] - language_id = data["language_id"] - uri = data["uri"] - text = data["text"] - line = data["line"] - column = data["column"] + method = data["method"] + params = didchange_notification["params"] - self.send_notification(method, params) - # return "{'notification':'some kind of response'}" + params["textDocument"]["uri"] = data["uri"] + params["textDocument"]["languageId"] = data["language_id"] + params["textDocument"]["version"] = data["version"] + + contentChanges = params["contentChanges"][0] + start = contentChanges["range"]["start"] + end = contentChanges["range"]["end"] + start["line"] = data["line"] + start["character"] = 0 + end["line"] = data["line"] + end["character"] = data["column"] + + GLib.idle_add( self.send_notification, method, params ) def _lsp_goto(self, data: dict): method = data["method"] @@ -46,14 +72,17 @@ class LSPControllerEvents: line = data["line"] column = data["column"] - self._client_send_request(method, uri, line, column) - # return "{'response':'some kind of response'}" + GLib.idle_add( self.send_request, method, params ) def _lsp_completion(self, data: dict): - method = data["method"] - language_id = data["language_id"] - uri = data["uri"] - line = data["line"] - column = data["column"] + method = data["method"] + params = completion_request["params"] - # self._client_send_request(method, uri, line, column) \ No newline at end of file + params["textDocument"]["uri"] = data["uri"] + params["textDocument"]["languageId"] = data["language_id"] + params["textDocument"]["version"] = data["version"] + params["position"]["line"] = data["line"] + params["position"]["character"] = data["column"] + + + GLib.idle_add( self.send_request, method, params ) \ No newline at end of file diff --git a/src/core/widgets/buttons/workspace_folder_choser_button.py b/src/core/widgets/buttons/workspace_folder_choser_button.py index 2f71382..c6976b1 100644 --- a/src/core/widgets/buttons/workspace_folder_choser_button.py +++ b/src/core/widgets/buttons/workspace_folder_choser_button.py @@ -28,7 +28,8 @@ class WorkspaceFolderChoserButton(Gtk.FileChooserButton): self.set_title("Chose Workspace") self.set_action( Gtk.FileChooserAction.SELECT_FOLDER ) # self.set_uri("file:///home/abaddon/Coding/Projects/Active/Python_Projects/testing/lsp_manager") - self.set_uri("file:///home/abaddon/Coding/Projects/Active/Python_Projects/000_Usable/gtk/LSP-Manager") + # self.set_uri("file:///home/abaddon/Coding/Projects/Active/Python_Projects/000_Usable/gtk/LSP-Manager") + self.set_uri("file:///home/abaddon/Coding/Projects/Active/Python_Projects/000_Usable/gtk/Newton_Editor") def _setup_signals(self): diff --git a/src/libs/dto/lsp_messages.py b/src/libs/dto/lsp_messages.py index 5c693d6..d45a45b 100644 --- a/src/libs/dto/lsp_messages.py +++ b/src/libs/dto/lsp_messages.py @@ -28,7 +28,7 @@ content_part = { "params": { "textDocument": { "uri": "file:///", - "languageId": "python3", + "languageId": "python", "version": 1, "text": "" }, @@ -45,21 +45,72 @@ didopen_notification = { "params": { "textDocument": { "uri": "file://", - "languageId": "python3", + "languageId": "python", "version": 1, "text": "" } } } +didchange_notification = { + "method": "textDocument/didChange", + "params": { + "textDocument": { + "uri": "file://", + "languageId": "python", + "version": 1, + "text": "" + }, + "contentChanges": [ + { + "range": { + "start": { + "line": 1, + "character": 1, + }, + "end": { + "line": 1, + "character": 1, + } + } + } + ] + } +} -definition_query = { + +# CompletionTriggerKind = 1 | 2 | 3; +# export const Invoked: 1 = 1; +# export const TriggerCharacter: 2 = 2; +# export const TriggerForIncompleteCompletions: 3 = 3; +completion_request = { + "method": "textDocument/completion", + "params": { + "textDocument": { + "uri": "file://", + "languageId": "python", + "version": 1, + "text": "" + }, + "position": { + "line": 5, + "character": 12, + "offset": 0 + }, + "contet": { + "triggerKind": 3, + "triggerCharacter": + } + } +} + +definition_request = { "method": "textDocument/definition", "params": { "textDocument": { "uri": "file:///home/abaddon/Coding/Projects/Active/Python_Projects/000_Usable/gtk/LSP-Manager/src/core/widgets/lsp_message_box.py", - "languageId": "python3", + "languageId": "python", "version": 1, "text": "" }, @@ -71,7 +122,7 @@ definition_query = { } } -references_query = { +references_request = { "method": "textDocument/references", "params": { "context": { @@ -79,7 +130,7 @@ references_query = { }, "textDocument": { "uri": "file:///home/abaddon/Coding/Projects/Active/Python_Projects/000_Usable/gtk/LSP-Manager/src/core/widgets/lsp_message_box.py", - "languageId": "python3", + "languageId": "python", "version": 1, "text": "" }, @@ -92,12 +143,12 @@ references_query = { } -symbols_query = { +symbols_request = { "method": "textDocument/documentSymbol", "params": { "textDocument": { "uri": "file:///home/abaddon/Coding/Projects/Active/Python_Projects/000_Usable/gtk/LSP-Manager/src/core/widgets/lsp_message_box.py", - "languageId": "python3", + "languageId": "python", "version": 1, "text": "" } diff --git a/src/libs/lsp_endpoint_server.py b/src/libs/lsp_endpoint_server.py index 0cb9be0..2b9bd4d 100644 --- a/src/libs/lsp_endpoint_server.py +++ b/src/libs/lsp_endpoint_server.py @@ -1,4 +1,5 @@ # Python imports +import traceback import os import threading import time @@ -66,19 +67,21 @@ class LSPEndpointServer(Singleton): start_time = time.perf_counter() self._handle_ipc_message(conn, start_time) except Exception as e: - logger.debug( repr(e) ) + # logger.debug( repr(e) ) + logger.debug( traceback.print_exc() ) listener.close() def _handle_ipc_message(self, conn, start_time) -> None: while True: msg = conn.recv() - logger.debug(msg) if "CLIENT|" in msg: data = msg.split("CLIENT|")[1].strip() if data: data_str = base64.b64decode(data.encode("utf-8")).decode("utf-8") + logger.debug(data_str) + json_blob = json.loads(data_str) event_system.emit(json_blob["method"], (json_blob,)) @@ -145,4 +148,4 @@ class LSPEndpointServer(Singleton): logger.error("LSP Socket no longer valid.... Removing.") os.unlink(self._ipc_address) except Exception as e: - logger.error( repr(e) ) \ No newline at end of file + logger.error( repr(e) ) diff --git a/src/libs/settings/manager.py b/src/libs/settings/manager.py index 6817a6d..2d1ea2a 100644 --- a/src/libs/settings/manager.py +++ b/src/libs/settings/manager.py @@ -109,13 +109,13 @@ class SettingsManager(StartCheckMixin, Singleton): with open(self._LSP_CONFIG) as file: self._lsp_config_data = json.load(file) except Exception as e: - print( f"Settings Manager: {self._LSP_CONFIG}\n\t\t{repr(e)}" ) + print( f"Settings Manager: {self._LSP_CONFIG}\n\t\t{repr(e)}" ) try: with open(self._LSP_INIT_CONFIG) as file: self._lsp_init_data = json.load(file) except Exception as e: - print( f"Settings Manager: {self._LSP_INIT_CONFIG}\n\t\t{repr(e)}" ) + print( f"Settings Manager: {self._LSP_INIT_CONFIG}\n\t\t{repr(e)}" ) self.settings: Settings = None @@ -162,7 +162,7 @@ class SettingsManager(StartCheckMixin, Singleton): def get_ui_widgets_path(self) -> str: return self._UI_WIDEGTS_PATH def get_context_menu_data(self) -> str: return self._context_menu_data def get_lsp_config_data(self) -> str: return self._lsp_config_data - def get_lsp_init_data(self) -> {}: return self._lsp_init_data + def get_lsp_init_data(self) -> dict: return self._lsp_init_data def get_app_pid(self) -> int: return self.pid def get_context_path(self) -> str: return self._CONTEXT_PATH @@ -172,7 +172,7 @@ class SettingsManager(StartCheckMixin, Singleton): def get_home_config_path(self) -> str: return self._HOME_CONFIG_PATH def get_window_icon(self) -> str: return self._WINDOW_ICON def get_home_path(self) -> str: return self._USER_HOME - def get_starting_files(self) -> []: return self._starting_files + def get_starting_files(self) -> list: return self._starting_files def is_trace_debug(self) -> str: return self._trace_debug def is_debug(self) -> str: return self._debug @@ -197,7 +197,7 @@ class SettingsManager(StartCheckMixin, Singleton): def set_debug(self, debug): self._debug = debug - def set_is_starting_with_file(self, is_passed_in_file: False): + def set_is_starting_with_file(self, is_passed_in_file: bool = False): self._passed_in_file = is_passed_in_file def load_settings(self): @@ -212,4 +212,4 @@ class SettingsManager(StartCheckMixin, Singleton): def save_settings(self): with open(self._CONFIG_FILE, 'w') as outfile: - json.dump(self.settings.as_dict(), outfile, separators=(',', ':'), indent=4) \ No newline at end of file + json.dump(self.settings.as_dict(), outfile, separators=(',', ':'), indent=4) diff --git a/src/libs/settings/start_check_mixin.py b/src/libs/settings/start_check_mixin.py index 491332d..a71f35b 100644 --- a/src/libs/settings/start_check_mixin.py +++ b/src/libs/settings/start_check_mixin.py @@ -61,4 +61,4 @@ class StartCheckMixin: def _write_pid(self, pid): with open(self._PID_FILE, "w") as _pid: - _pid.write(f"{pid}") \ No newline at end of file + _pid.write(f"{pid}")