From defff39e2537d507290eb35f4255471c09d97063 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Mon, 29 Jan 2024 22:11:14 -0600 Subject: [PATCH] Reworking completion call and didChange logic --- plugins/lsp_client/lsp_controller.py | 25 ++++++---- plugins/lsp_client/plugin.py | 47 +++++++------------ plugins/lsp_client/pylspclient/lsp_client.py | 27 +++++------ .../lsp_completion_provider.py | 15 ++++-- .../mixins/source_file_events_mixin.py | 12 ++--- src/libs/event_system.py | 2 +- user_config/bin/newton | 16 ++++++- 7 files changed, 79 insertions(+), 65 deletions(-) diff --git a/plugins/lsp_client/lsp_controller.py b/plugins/lsp_client/lsp_controller.py index ee49d9d..902b555 100644 --- a/plugins/lsp_client/lsp_controller.py +++ b/plugins/lsp_client/lsp_controller.py @@ -13,7 +13,10 @@ from .capabilities import Capabilities class ReadPipe(threading.Thread): def __init__(self, pipe): threading.Thread.__init__(self) - self.pipe = pipe + + self.daemon = True + self.pipe = pipe + def run(self): line = self.pipe.readline().decode('utf-8') @@ -63,7 +66,7 @@ class LSPController: if not language or not server_proc: return False root_path = None - # root_uri = 'file:///home/abaddon/Coding/Projects/Active/C_n_CPP_Projects/gtk/Newton/src/' + # root_uri = 'file:///home/abaddon/Coding/Projects/Active/Python_Projects/000_Usable/gtk/Newton_Editor/src/' # workspace_folders = [{'name': 'python-lsp', 'uri': root_uri}] root_uri = '' workspace_folders = [{'name': '', 'uri': root_uri}] @@ -76,6 +79,7 @@ class LSPController: initializationOptions = initialization_options, \ capabilities = Capabilities.data, \ trace = "off", \ + # trace = "on", \ workspaceFolders = workspace_folders ) @@ -123,16 +127,17 @@ class LSPController: return [] - def do_change(self, language_id, line, start, end, text): + def do_change(self, uri, language_id, line, start, end, text): if language_id in self.lsp_clients.keys(): - start_pos = pylspclient.lsp_structs.Position(line, start.get_line_offset()) - end_pos = pylspclient.lsp_structs.Position(line, end.get_line_offset()) - range_info = pylspclient.lsp_structs.Range(start_pos, end_pos) - text_length = len(text) - change_event = pylspclient.lsp_structs.TextDocumentContentChangeEvent(range_info, text_length, text) + start_pos = pylspclient.lsp_structs.Position(line, start.get_line_offset()) + end_pos = pylspclient.lsp_structs.Position(line, end.get_line_offset()) + range_info = pylspclient.lsp_structs.Range(start_pos, end_pos) + text_length = len(text) + text_document = pylspclient.lsp_structs.TextDocumentItem(uri, language_id, 1, text) + change_event = pylspclient.lsp_structs.TextDocumentContentChangeEvent(range_info, text_length, text) - return self.lsp_clients[language_id].didChange( None, change_event ) + return self.lsp_clients[language_id].didChange( text_document, change_event ) return [] @@ -155,7 +160,7 @@ class LSPController: ) return [] - + def load_lsp_server(self, language_id): if not language_id in self.lsp_servers_config.keys(): diff --git a/plugins/lsp_client/plugin.py b/plugins/lsp_client/plugin.py index 494741c..1c03646 100644 --- a/plugins/lsp_client/plugin.py +++ b/plugins/lsp_client/plugin.py @@ -24,7 +24,7 @@ class Plugin(PluginBase): 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 + # 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 @@ -58,24 +58,11 @@ class Plugin(PluginBase): self._event_system.subscribe("textDocument/didSave", self.lsp_controller.do_save) self._event_system.subscribe("textDocument/didClose", self.lsp_controller.do_close) self._event_system.subscribe("textDocument/definition", self._do_goto) - self._event_system.subscribe("textDocument/completion", self.completion) + self._event_system.subscribe("textDocument/completion", self._do_completion) def _shutting_down(self): self.lsp_controller._shutting_down() - def cancel_timer(self): - if self.timer: - self.timer.cancel() - GLib.idle_remove_by_data(None) - - def delay_completion_glib(self, source_view, context, callback): - GLib.idle_add(self._do_completion, source_view, context, callback) - - def delay_completion(self, source_view, context, callback): - self.timer = threading.Timer(0.8, self.delay_completion_glib, (source_view, context, callback,)) - self.timer.daemon = True - self.timer.start() - def _buffer_changed(self, language_id, buffer): iter = buffer.get_iter_at_mark( buffer.get_insert() ) line = iter.get_line() @@ -86,14 +73,10 @@ class Plugin(PluginBase): start.forward_line() end.forward_to_line_end() - text = buffer.get_text(start, end, include_hidden_chars = False) - result = self.lsp_controller.do_change(language_id, line, start, end, text) + text = buffer.get_text(start, end, include_hidden_chars = False) + result = self.lsp_controller.do_change(buffer.uri, language_id, line, start, end, text) - def completion(self, source_view, context, callback): - self.cancel_timer() - self.delay_completion(source_view, context, callback) - - def _do_completion(self, source_view, context, callback): + def _do_completion(self, source_view): filepath = source_view.get_current_file() if not filepath: return @@ -101,16 +84,22 @@ class Plugin(PluginBase): uri = filepath.get_uri() buffer = source_view.get_buffer() iter = buffer.get_iter_at_mark( buffer.get_insert() ) - line = iter.get_line() + 1 + line = iter.get_line() _char = iter.get_char() - # if iter.backward_char(): - # _char = iter.get_char() + if iter.backward_char(): + _char = iter.get_char() - offset = iter.get_line_index() + 1 - # offset = iter.get_line_offset() - result = self.lsp_controller.do_completion(source_view.get_filetype(), uri, line, offset, _char) - callback(context, result) + offset = iter.get_line_offset() + result = self.lsp_controller.do_completion( + source_view.get_filetype(), + uri, + line, + offset, + _char + ) + + return result def _do_goto(self, language_id, uri, line, offset): results = self.lsp_controller.do_goto(language_id, uri, line, offset) diff --git a/plugins/lsp_client/pylspclient/lsp_client.py b/plugins/lsp_client/pylspclient/lsp_client.py index 57dfd35..ec42b5e 100644 --- a/plugins/lsp_client/pylspclient/lsp_client.py +++ b/plugins/lsp_client/pylspclient/lsp_client.py @@ -1,3 +1,8 @@ +# Python imports + +# Lib imports + +# Application imports from . import lsp_structs @@ -40,13 +45,13 @@ class LspClient(object): """ self.lsp_endpoint.start() - return self.lsp_endpoint.call_method("initialize", \ - processId = processId, \ - rootPath = rootPath, \ - rootUri = rootUri, \ - initializationOptions = initializationOptions, \ - capabilities = capabilities, \ - trace = trace, \ + return self.lsp_endpoint.call_method("initialize", + processId = processId, + rootPath = rootPath, + rootUri = rootUri, + initializationOptions = initializationOptions, + capabilities = capabilities, + trace = trace, workspaceFolders = workspaceFolders ) @@ -61,18 +66,12 @@ class LspClient(object): def shutdown(self): """ - The initialized notification is sent from the client to the server after the client received the result of the initialize request - but before the client is sending any other request or notification to the server. The server can use the initialized notification - for example to dynamically register capabilities. The initialized notification may only be sent once. """ return self.lsp_endpoint.call_method("shutdown") def exit(self): """ - The initialized notification is sent from the client to the server after the client received the result of the initialize request - but before the client is sending any other request or notification to the server. The server can use the initialized notification - for example to dynamically register capabilities. The initialized notification may only be sent once. """ self.lsp_endpoint.send_notification("exit") @@ -115,7 +114,7 @@ class LspClient(object): The document change notification is sent from the client to the server to signal changes to a text document. In 2.0 the shape of the params has changed to include proper version numbers and language ids. - :param VersionedTextDocumentIdentifier textDocument: The initial trace setting. If omitted trace is disabled ('off'). + :param TextDocumentItem textDocument: The text document. :param TextDocumentContentChangeEvent[] contentChanges: The actual content changes. The content changes describe single state changes to the document. So if there are two content changes c1 and c2 for a document in state S then c1 move the document to S' and c2 to S''. diff --git a/src/core/widgets/base/sourceview/custom_completion_providers/lsp_completion_provider.py b/src/core/widgets/base/sourceview/custom_completion_providers/lsp_completion_provider.py index 652cdae..dab2374 100644 --- a/src/core/widgets/base/sourceview/custom_completion_providers/lsp_completion_provider.py +++ b/src/core/widgets/base/sourceview/custom_completion_providers/lsp_completion_provider.py @@ -39,7 +39,13 @@ class LSPCompletionProvider(GObject.Object, GtkSource.CompletionProvider): if buffer.get_context_classes_at_iter(iter) != ['no-spell-check']: return False - event_system.emit("textDocument/completion", (self._source_view, context, self.do_populate)) + ch = iter.get_char() + # NOTE: Look to re-add or apply supprting logic to use spaces + # As is it slows down the editor in certain contexts... + if not (ch in ('_', '.', ' ') or ch.isalnum()): + # if not (ch in ('_', '.') or ch.isalnum()): + return False + return True def do_get_priority(self): @@ -49,7 +55,9 @@ class LSPCompletionProvider(GObject.Object, GtkSource.CompletionProvider): return GtkSource.CompletionActivation.INTERACTIVE def do_populate(self, context, result = None): + result = event_system.emit_and_await("textDocument/completion", (self._source_view,)) proposals = [] + if result: if not result.items is None: for item in result.items: @@ -86,6 +94,5 @@ class LSPCompletionProvider(GObject.Object, GtkSource.CompletionProvider): comp_item.set_icon( self.get_icon_for_type(item.kind) ) comp_item.set_info(item.documentation) - - - return comp_item + + return comp_item \ No newline at end of file diff --git a/src/core/widgets/base/sourceview/mixins/source_file_events_mixin.py b/src/core/widgets/base/sourceview/mixins/source_file_events_mixin.py index 1affe10..7a77fdc 100644 --- a/src/core/widgets/base/sourceview/mixins/source_file_events_mixin.py +++ b/src/core/widgets/base/sourceview/mixins/source_file_events_mixin.py @@ -6,6 +6,7 @@ import gi gi.require_version('Gtk', '3.0') gi.require_version('GtkSource', '4') from gi.repository import Gtk +from gi.repository import GLib from gi.repository import Gio from gi.repository import GtkSource @@ -79,7 +80,7 @@ class FileEventsMixin: self.update_labels(gfile) self._loading_file = False - self._file_loader.load_async(io_priority = 80, + self._file_loader.load_async(io_priority = GLib.PRIORITY_HIGH, cancellable = None, progress_callback = None, progress_callback_data = None, @@ -140,8 +141,9 @@ class FileEventsMixin: for provider in self._completion.get_providers(): self._completion.remove_provider(provider) - uri = self._current_file.get_uri() - buffer = self.get_buffer() + uri = self._current_file.get_uri() + buffer = self.get_buffer() + buffer.uri = uri event_system.emit("textDocument/didOpen", (self._current_filetype, uri,)) @@ -152,6 +154,4 @@ class FileEventsMixin: lsp_completion_provider = LSPCompletionProvider(self) self._completion.add_provider(lsp_completion_provider) - self.got_to_line(buffer, line) - - + self.got_to_line(buffer, line) \ No newline at end of file diff --git a/src/libs/event_system.py b/src/libs/event_system.py index cd6975f..897fca9 100644 --- a/src/libs/event_system.py +++ b/src/libs/event_system.py @@ -70,4 +70,4 @@ class EventSystem(Singleton): if not response in (None, ''): break - return response + return response \ No newline at end of file diff --git a/user_config/bin/newton b/user_config/bin/newton index 5eed8c6..afefa7f 100755 --- a/user_config/bin/newton +++ b/user_config/bin/newton @@ -12,13 +12,27 @@ function main() { files=() for f in "$@"; do +# ff=${f%:*} +# ii=${f#*:} +# target=$(readlink -f "${ff}") + target=$(readlink -f "${f}") i="${#files[@]}" size=$(($i + 1)) + files[$size]="${target}" + +# if [ -n "$ii" ]; then +# files[$size]="${target}:${ii}" +# else +# files[$size]="${target}${ii}" +# fi done + echo "${files[@]}" + + cd "/opt/" python /opt/newton.zip "${files[@]}" } -main "$@"; +main "$@"; \ No newline at end of file