From 880c4839ccb849d8fb69503c8f8461f9f2eb4f12 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Wed, 17 Jan 2024 12:25:52 -0600 Subject: [PATCH 1/4] Text change track; workspaceb detrack temporary --- plugins/lsp_client/lsp_controller.py | 11 +++++++---- plugins/lsp_client/plugin.py | 13 ++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/plugins/lsp_client/lsp_controller.py b/plugins/lsp_client/lsp_controller.py index 720f15b..ee49d9d 100644 --- a/plugins/lsp_client/lsp_controller.py +++ b/plugins/lsp_client/lsp_controller.py @@ -21,7 +21,6 @@ class ReadPipe(threading.Thread): line = self.pipe.readline().decode('utf-8') - class LSPController: def __init__(self, lsp_servers_config = {}): super().__init__() @@ -29,6 +28,7 @@ class LSPController: self.lsp_servers_config = lsp_servers_config self.lsp_clients = {} + def _blame(self, response): for d in response['diagnostics']: if d['severity'] == 1: @@ -63,8 +63,10 @@ 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/' - workspace_folders = [{'name': 'python-lsp', 'uri': root_uri}] + # root_uri = 'file:///home/abaddon/Coding/Projects/Active/C_n_CPP_Projects/gtk/Newton/src/' + # workspace_folders = [{'name': 'python-lsp', 'uri': root_uri}] + root_uri = '' + workspace_folders = [{'name': '', 'uri': root_uri}] lsp_client = self._generate_client(language, server_proc) lsp_client.initialize( @@ -148,7 +150,8 @@ class LSPController: return self.lsp_clients[language_id].completion( pylspclient.lsp_structs.TextDocumentIdentifier(uri), pylspclient.lsp_structs.Position(line, offset), - pylspclient.lsp_structs.CompletionContext(trigger, _char) + None + # pylspclient.lsp_structs.CompletionContext(trigger, _char) ) return [] diff --git a/plugins/lsp_client/plugin.py b/plugins/lsp_client/plugin.py index 11f2954..494741c 100644 --- a/plugins/lsp_client/plugin.py +++ b/plugins/lsp_client/plugin.py @@ -53,7 +53,7 @@ class Plugin(PluginBase): def inner_subscribe_to_events(self): self._event_system.subscribe("shutting_down", self._shutting_down) - self._event_system.subscribe("textDocument/didChange", self._buffer_changed) + # self._event_system.subscribe("textDocument/didChange", self._buffer_changed) self._event_system.subscribe("textDocument/didOpen", self.lsp_controller.do_open) self._event_system.subscribe("textDocument/didSave", self.lsp_controller.do_save) self._event_system.subscribe("textDocument/didClose", self.lsp_controller.do_close) @@ -88,15 +88,13 @@ class Plugin(PluginBase): text = buffer.get_text(start, end, include_hidden_chars = False) result = self.lsp_controller.do_change(language_id, line, start, end, text) - # print(result) - 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): - filepath = source_view.get_current_file() + filepath = source_view.get_current_file() if not filepath: return @@ -106,10 +104,11 @@ class Plugin(PluginBase): line = iter.get_line() + 1 _char = iter.get_char() - if iter.backward_char(): - _char = iter.get_char() + # if iter.backward_char(): + # _char = iter.get_char() - offset = iter.get_line_offset() + 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) -- 2.27.0 From 0c6af185a26967c69bd52dfddcc8090980a28dc7 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sat, 27 Jan 2024 23:44:34 -0600 Subject: [PATCH 2/4] aligned to base template project; scroll past end added; move line selection preservation --- src/__main__.py | 5 -- src/app.py | 34 +++++++----- src/core/__init__.py | 3 - .../{core_widget.py => base_container.py} | 4 +- src/core/controllers/__init__.py | 3 + .../base_controller.py} | 11 ++-- .../base_controller_data.py} | 5 +- .../base/sourceview/source_view_controller.py | 55 +++++++++++++++++-- src/core/window.py | 32 ++++++++--- user_config/usr/share/newton/stylesheet.css | 5 ++ 10 files changed, 111 insertions(+), 46 deletions(-) delete mode 100644 src/core/__init__.py rename src/core/containers/{core_widget.py => base_container.py} (94%) create mode 100644 src/core/controllers/__init__.py rename src/core/{controller.py => controllers/base_controller.py} (87%) rename src/core/{controller_data.py => controllers/base_controller_data.py} (94%) diff --git a/src/__main__.py b/src/__main__.py index 5bbe908..d44b8cc 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -10,9 +10,6 @@ import tracemalloc tracemalloc.start() # Lib imports -import gi -gi.require_version('Gtk', '3.0') -from gi.repository import Gtk # Application imports from __builtins__ import * @@ -20,7 +17,6 @@ from app import Application - if __name__ == "__main__": ''' Set process title, get arguments, and create GTK main thread. ''' @@ -47,7 +43,6 @@ if __name__ == "__main__": settings_manager.do_dirty_start_check() Application(args, unknownargs) - Gtk.main() except Exception as e: traceback.print_exc() quit() \ No newline at end of file diff --git a/src/app.py b/src/app.py index e00fc89..b945b22 100644 --- a/src/app.py +++ b/src/app.py @@ -16,35 +16,39 @@ class AppLaunchException(Exception): -class Application(IPCServer): +class Application: """ docstring for Application. """ def __init__(self, args, unknownargs): super(Application, self).__init__() if not settings_manager.is_trace_debug(): - self.socket_realization_check() - - if not self.is_ipc_alive: - for arg in unknownargs + [args.new_tab,]: - if os.path.isfile(arg): - message = f"FILE|{arg}" - self.send_ipc_message(message) - - raise AppLaunchException(f"{app_name} IPC Server Exists: Have sent path(s) to it and closing...") + self.load_ipc(args, unknownargs) self.setup_debug_hook() - Window(args, unknownargs) + Window(args, unknownargs).main() - def socket_realization_check(self): + def load_ipc(self, args, unknownargs): + ipc_server = IPCServer() + self.ipc_realization_check(ipc_server) + + if not ipc_server.is_ipc_alive: + for arg in unknownargs + [args.new_tab,]: + if os.path.isfile(arg): + message = f"FILE|{arg}" + ipc_server.send_ipc_message(message) + + raise AppLaunchException(f"{app_name} IPC Server Exists: Have sent path(s) to it and closing...") + + def ipc_realization_check(self, ipc_server): try: - self.create_ipc_listener() + ipc_server.create_ipc_listener() except Exception: - self.send_test_ipc_message() + ipc_server.send_test_ipc_message() try: - self.create_ipc_listener() + ipc_server.create_ipc_listener() except Exception as e: ... diff --git a/src/core/__init__.py b/src/core/__init__.py deleted file mode 100644 index 90cfadc..0000000 --- a/src/core/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -""" - Gtk Bound Signal Module -""" diff --git a/src/core/containers/core_widget.py b/src/core/containers/base_container.py similarity index 94% rename from src/core/containers/core_widget.py rename to src/core/containers/base_container.py index e04841e..5670529 100644 --- a/src/core/containers/core_widget.py +++ b/src/core/containers/base_container.py @@ -14,9 +14,9 @@ from .editors_container import EditorsContainer -class CoreWidget(Gtk.Box): +class BaseContainer(Gtk.Box): def __init__(self): - super(CoreWidget, self).__init__() + super(BaseContainer, self).__init__() builder = settings_manager.get_builder() self.ctx = self.get_style_context() diff --git a/src/core/controllers/__init__.py b/src/core/controllers/__init__.py new file mode 100644 index 0000000..c004b70 --- /dev/null +++ b/src/core/controllers/__init__.py @@ -0,0 +1,3 @@ +""" + Controllers Module +""" \ No newline at end of file diff --git a/src/core/controller.py b/src/core/controllers/base_controller.py similarity index 87% rename from src/core/controller.py rename to src/core/controllers/base_controller.py index 27f15e2..341edd4 100644 --- a/src/core/controller.py +++ b/src/core/controllers/base_controller.py @@ -10,13 +10,14 @@ from gi.repository import Gdk from gi.repository import GLib # Application imports -from .controller_data import ControllerData -from .containers.core_widget import CoreWidget -from .mixins.signals_mixins import SignalsMixins +from ..mixins.signals_mixins import SignalsMixins +from ..containers.base_container import BaseContainer + +from .base_controller_data import BaseControllerData -class Controller(SignalsMixins, ControllerData): +class BaseController(SignalsMixins, BaseControllerData): def __init__(self, args, unknownargs): messages = [] for arg in unknownargs + [args.new_tab,]: @@ -60,7 +61,7 @@ class Controller(SignalsMixins, ControllerData): self.builder.expose_object("main_window", self.window) settings_manager.set_builder(self.builder) - self.core_widget = CoreWidget() + self.core_widget = BaseContainer() settings_manager.register_signals_to_builder([self, self.core_widget]) diff --git a/src/core/controller_data.py b/src/core/controllers/base_controller_data.py similarity index 94% rename from src/core/controller_data.py rename to src/core/controllers/base_controller_data.py index def6d80..3467eac 100644 --- a/src/core/controller_data.py +++ b/src/core/controllers/base_controller_data.py @@ -9,9 +9,8 @@ from plugins.plugins_controller import PluginsController - -class ControllerData: - ''' ControllerData contains most of the state of the app at ay given time. It also has some support methods. ''' +class BaseControllerData: + ''' BaseControllerData contains most of the state of the app at ay given time. It also has some support methods. ''' def setup_controller_data(self) -> None: self.window = settings_manager.get_main_window() diff --git a/src/core/widgets/base/sourceview/source_view_controller.py b/src/core/widgets/base/sourceview/source_view_controller.py index a173524..3b4831c 100644 --- a/src/core/widgets/base/sourceview/source_view_controller.py +++ b/src/core/widgets/base/sourceview/source_view_controller.py @@ -117,22 +117,67 @@ class SourceViewControllerMixin(KeyInputController, SourceViewEvents): buffer.redo() def keyboard_move_lines_up(self): - buffer = self.get_buffer() + buffer = self.get_buffer() self.begin_user_action(buffer) + had_selection = buffer.get_has_selection() + itr = buffer.get_iter_at_mark( buffer.get_insert() ) + line = itr.get_line() - 1 + line_index = itr.get_line_index() + selection_bounds = None + + if had_selection: + selection_bounds = buffer.get_selection_bounds() + sbounds_start = selection_bounds[0].get_line_offset() + sbounds_end = selection_bounds[1].get_line_offset() + self.emit("move-lines", *(False,)) - # unindent_lines - # self.emit("move-words", *(self, 4,)) + if not had_selection: + self.emit("select-all", *(False,)) + line_itr = buffer.get_iter_at_line_offset(line, line_index) + self.get_buffer().place_cursor(line_itr) + else: + buffer = self.get_buffer() + sbounds = buffer.get_selection_bounds() + start_itr = buffer.get_iter_at_line_offset( sbounds[0].get_line(), sbounds_start) + end_itr = buffer.get_iter_at_line_offset( sbounds[1].get_line() - 1, sbounds_end) + + self.emit("select-all", *(False,)) + buffer.select_range(start_itr, end_itr) self.end_user_action(buffer) def keyboard_move_lines_down(self): - buffer = self.get_buffer() + buffer = self.get_buffer() self.begin_user_action(buffer) + had_selection = buffer.get_has_selection() + itr = buffer.get_iter_at_mark( buffer.get_insert() ) + line = itr.get_line() + 1 + line_index = itr.get_line_index() + selection_bounds = None + sbounds_start = None + sbounds_end = None + + if had_selection: + selection_bounds = buffer.get_selection_bounds() + sbounds_start = selection_bounds[0].get_line_offset() + sbounds_end = selection_bounds[1].get_line_offset() + self.emit("move-lines", *(True,)) - # self.emit("move-words", *(self, -4,)) + if not had_selection: + self.emit("select-all", *(False,)) + line_itr = buffer.get_iter_at_line_offset(line, line_index) + self.get_buffer().place_cursor(line_itr) + else: + buffer = self.get_buffer() + sbounds = buffer.get_selection_bounds() + start_itr = buffer.get_iter_at_line_offset( sbounds[0].get_line(), sbounds_start) + end_itr = buffer.get_iter_at_line_offset( sbounds[1].get_line() - 1, sbounds_end) + + self.emit("select-all", *(False,)) + buffer.select_range(start_itr, end_itr) self.end_user_action(buffer) \ No newline at end of file diff --git a/src/core/window.py b/src/core/window.py index 66b374a..b3a54fd 100644 --- a/src/core/window.py +++ b/src/core/window.py @@ -1,5 +1,4 @@ # Python imports -import time import signal # Lib imports @@ -12,7 +11,8 @@ from gi.repository import Gdk from gi.repository import GLib # Application imports -from core.controller import Controller +from core.controllers.base_controller import BaseController + class ControllerStartExceptiom(Exception): @@ -20,7 +20,6 @@ class ControllerStartExceptiom(Exception): - class Window(Gtk.ApplicationWindow): """docstring for Window.""" @@ -30,12 +29,12 @@ class Window(Gtk.ApplicationWindow): self._controller = None - self._set_window_data() self._setup_styling() self._setup_signals() self._subscribe_to_events() - self._load_widgets(args, unknownargs) + + self._set_window_data() self._set_size_constraints() self.show() @@ -49,21 +48,26 @@ class Window(Gtk.ApplicationWindow): ctx = self.get_style_context() ctx.add_class("main-window") + ctx.add_class(f"mw_transparency_{settings.theming.transparency}") def _setup_signals(self): + self.connect("focus-in-event", self._on_focus_in_event) + self.connect("focus-out-event", self._on_focus_out_event) + self.connect("delete-event", self._tear_down) GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, self._tear_down) def _subscribe_to_events(self): event_system.subscribe("tear_down", self._tear_down) + event_system.subscribe("load_interactive_debug", self._load_interactive_debug) def _load_widgets(self, args, unknownargs): if settings_manager.is_debug(): self.set_interactive_debugging(True) - self._controller = Controller(args, unknownargs) + self._controller = BaseController(args, unknownargs) if not self._controller: - raise ControllerStartException("Controller exited and doesn't exist...") + raise ControllerStartException("BaseController exited and doesn't exist...") self.add( self._controller.get_core_widget() ) @@ -83,7 +87,7 @@ class Window(Gtk.ApplicationWindow): screen = self.get_screen() visual = screen.get_rgba_visual() - if visual != None and screen.is_composited(): + if visual != None and screen.is_composited() and settings.config.make_transparent == 0: self.set_visual(visual) self.set_app_paintable(True) self.connect("draw", self._area_draw) @@ -102,6 +106,15 @@ class Window(Gtk.ApplicationWindow): cr.set_operator(cairo.OPERATOR_OVER) + def _on_focus_in_event(self, widget, event): + event_system.emit("pause_dnd_signals") + + def _on_focus_out_event(self, widget, event): + event_system.emit("listen_dnd_signals") + + def _load_interactive_debug(self): + self.set_interactive_debugging(True) + def _tear_down(self, widget = None, eve = None): event_system.emit("shutting_down") @@ -116,3 +129,6 @@ class Window(Gtk.ApplicationWindow): settings_manager.clear_pid() Gtk.main_quit() + + def main(self): + Gtk.main() \ No newline at end of file diff --git a/user_config/usr/share/newton/stylesheet.css b/user_config/usr/share/newton/stylesheet.css index b63bcfc..85b7a72 100644 --- a/user_config/usr/share/newton/stylesheet.css +++ b/user_config/usr/share/newton/stylesheet.css @@ -81,6 +81,11 @@ notebook > stack > scrolledwindow > textview { color: rgba(255, 255, 255, 1); } +textview { + padding-bottom: 50em; +} + + /* any popover */ popover { background: rgba(39, 43, 52, 0.86); -- 2.27.0 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 3/4] 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 -- 2.27.0 From efbb6aef5b285cfd0cf4322dcbc4d111139c609a Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sat, 10 Feb 2024 23:27:42 -0600 Subject: [PATCH 4/4] added ctrl + k and u key bindings for buffer cut and paste --- plugins/lsp_client/plugin.py | 14 ++--- src/__main__.py | 48 +++++++++-------- .../base/sourceview/key_input_controller.py | 8 ++- .../mixins/source_file_events_mixin.py | 26 ++++++---- .../widgets/base/sourceview/source_view.py | 22 +++++++- .../base/sourceview/source_view_controller.py | 51 +++++++++++++++++++ .../base/sourceview/source_view_events.py | 5 +- 7 files changed, 132 insertions(+), 42 deletions(-) diff --git a/plugins/lsp_client/plugin.py b/plugins/lsp_client/plugin.py index 1c03646..b566e93 100644 --- a/plugins/lsp_client/plugin.py +++ b/plugins/lsp_client/plugin.py @@ -53,17 +53,18 @@ class Plugin(PluginBase): def inner_subscribe_to_events(self): self._event_system.subscribe("shutting_down", self._shutting_down) - # self._event_system.subscribe("textDocument/didChange", self._buffer_changed) - self._event_system.subscribe("textDocument/didOpen", self.lsp_controller.do_open) - 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("buffer_changed", self._buffer_changed) + self._event_system.subscribe("textDocument/didChange", self._buffer_changed) + self._event_system.subscribe("textDocument/didOpen", self.lsp_controller.do_open) + 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._do_completion) def _shutting_down(self): self.lsp_controller._shutting_down() - def _buffer_changed(self, language_id, buffer): + def _buffer_changed(self, file_type, buffer): iter = buffer.get_iter_at_mark( buffer.get_insert() ) line = iter.get_line() start = iter.copy() @@ -74,7 +75,8 @@ class Plugin(PluginBase): end.forward_to_line_end() text = buffer.get_text(start, end, include_hidden_chars = False) - result = self.lsp_controller.do_change(buffer.uri, language_id, line, start, end, text) + result = self.lsp_controller.do_change(buffer.uri, buffer.language_id, line, start, end, text) + def _do_completion(self, source_view): filepath = source_view.get_current_file() diff --git a/src/__main__.py b/src/__main__.py index d44b8cc..fcaf878 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -17,32 +17,38 @@ from app import Application +def main(args, unknownargs): + setproctitle(f'{app_name}') + + if args.debug == "true": + settings_manager.set_debug(True) + + if args.trace_debug == "true": + settings_manager.set_trace_debug(True) + + settings_manager.do_dirty_start_check() + Application(args, unknownargs) + + + if __name__ == "__main__": ''' Set process title, get arguments, and create GTK main thread. ''' + parser = argparse.ArgumentParser() + # Add long and short arguments + parser.add_argument("--debug", "-d", default="false", help="Do extra console messaging.") + parser.add_argument("--trace-debug", "-td", default="false", help="Disable saves, ignore IPC lock, do extra console messaging.") + parser.add_argument("--no-plugins", "-np", default="false", help="Do not load plugins.") + + parser.add_argument("--new-tab", "-nt", default="false", help="Opens a 'New Tab' if a handler is set for it.") + parser.add_argument("--new-window", "-w", default="", help="Open a file into a new window.") + + # Read arguments (If any...) + args, unknownargs = parser.parse_known_args() + try: - setproctitle(f'{app_name}') faulthandler.enable() # For better debug info - - parser = argparse.ArgumentParser() - # Add long and short arguments - parser.add_argument("--debug", "-d", default="false", help="Do extra console messaging.") - parser.add_argument("--trace-debug", "-td", default="false", help="Disable saves, ignore IPC lock, do extra console messaging.") - parser.add_argument("--no-plugins", "-np", default="false", help="Do not load plugins.") - parser.add_argument("--new-tab", "-t", default="", help="Open a file into new tab.") - parser.add_argument("--new-window", "-w", default="", help="Open a file into a new window.") - - # Read arguments (If any...) - args, unknownargs = parser.parse_known_args() - - if args.debug == "true": - settings_manager.set_debug(True) - - if args.trace_debug == "true": - settings_manager.set_trace_debug(True) - - settings_manager.do_dirty_start_check() - Application(args, unknownargs) + main(args, unknownargs) except Exception as e: traceback.print_exc() quit() \ No newline at end of file diff --git a/src/core/widgets/base/sourceview/key_input_controller.py b/src/core/widgets/base/sourceview/key_input_controller.py index a9384a3..0282ddd 100644 --- a/src/core/widgets/base/sourceview/key_input_controller.py +++ b/src/core/widgets/base/sourceview/key_input_controller.py @@ -81,7 +81,7 @@ class KeyInputController: return True - if keyname in ["z", "y", "m", "s", "h", "g", "equal", "minus", "Up", "Down"]: + if keyname in ["z", "y", "m", "s", "h", "g", "d", "k", "u", "equal", "minus", "Up", "Down"]: if keyname == "z": self.keyboard_undo() if keyname == "y": @@ -94,6 +94,12 @@ class KeyInputController: self.toggle_highlight_line() if keyname == "g": self.go_to_call() + if keyname == "d": + self.duplicate_line() + if keyname == "k": + self.cut_to_buffer() + if keyname == "u": + self.paste_cut_buffer() if keyname == "equal": self.scale_up_text() 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 7a77fdc..4c49150 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 @@ -11,8 +11,8 @@ from gi.repository import Gio from gi.repository import GtkSource # Application imports -from ..custom_completion_providers.lsp_completion_provider import LSPCompletionProvider - +# from ..custom_completion_providers.lsp_completion_provider import LSPCompletionProvider +from ..custom_completion_providers.python_completion_provider import PythonCompletionProvider class FileEventsMixin: @@ -140,18 +140,24 @@ class FileEventsMixin: def _document_loaded(self, line: int = 0): for provider in self._completion.get_providers(): self._completion.remove_provider(provider) - - uri = self._current_file.get_uri() - buffer = self.get_buffer() - buffer.uri = uri + + uri = self._current_file.get_uri() + buffer = self.get_buffer() + buffer.uri = uri + buffer.language_id = self._current_filetype event_system.emit("textDocument/didOpen", (self._current_filetype, uri,)) word_completion = GtkSource.CompletionWords.new("word_completion") word_completion.register(buffer) self._completion.add_provider(word_completion) - - lsp_completion_provider = LSPCompletionProvider(self) - self._completion.add_provider(lsp_completion_provider) - self.got_to_line(buffer, line) \ No newline at end of file + # lsp_completion_provider = LSPCompletionProvider(self) + # self._completion.add_provider(lsp_completion_provider) + + # if self._current_filetype in ("python", "python3"): + # py_lsp_completion_provider = PythonCompletionProvider(uri) + # self._completion.add_provider(py_lsp_completion_provider) + + self.got_to_line(buffer, line) + event_system.emit("buffer_changed_first_load", (buffer, )) \ No newline at end of file diff --git a/src/core/widgets/base/sourceview/source_view.py b/src/core/widgets/base/sourceview/source_view.py index f089bff..889e041 100644 --- a/src/core/widgets/base/sourceview/source_view.py +++ b/src/core/widgets/base/sourceview/source_view.py @@ -1,4 +1,5 @@ # Python imports +import threading # Lib imports import gi @@ -33,6 +34,9 @@ class SourceView(SourceViewControllerMixin, GtkSource.View): self._current_filename: str = "" self._current_filepath: str = None self._current_filetype: str = "buffer" + self._cut_buffer: str = "" + self._timer: threading.Timer = None + self._idle_id: int = None self._skip_file_load = False self._ignore_internal_change = False @@ -95,4 +99,20 @@ class SourceView(SourceViewControllerMixin, GtkSource.View): ... def _load_widgets(self): - self._set_up_dnd() \ No newline at end of file + self._set_up_dnd() + + def cancel_timer(self): + if self._timer: + self._timer.cancel() + GLib.idle_remove_by_data(self._idle_id) + + def delay_cut_buffer_clear_glib(self): + self._idle_id = GLib.idle_add(self._clear_cut_buffer) + + def clear_cut_buffer_delayed(self): + self._timer = threading.Timer(15, self.delay_cut_buffer_clear_glib, ()) + self._timer.daemon = True + self._timer.start() + + def _clear_cut_buffer(self): + self._cut_buffer = "" diff --git a/src/core/widgets/base/sourceview/source_view_controller.py b/src/core/widgets/base/sourceview/source_view_controller.py index 3b4831c..8e06910 100644 --- a/src/core/widgets/base/sourceview/source_view_controller.py +++ b/src/core/widgets/base/sourceview/source_view_controller.py @@ -34,6 +34,57 @@ class SourceViewControllerMixin(KeyInputController, SourceViewEvents): event_system.emit("textDocument/definition", (self.get_filetype(), uri, line, offset,)) + def duplicate_line(self, buffer = None): + buffer = self.get_buffer() if not buffer else buffer + itr = buffer.get_iter_at_mark( buffer.get_insert() ) + start_itr = itr.copy() + end_itr = itr.copy() + start_line = itr.get_line() + 1 + start_char = itr.get_line_offset() + + start_itr.backward_visible_line() + start_itr.forward_line() + end_itr.forward_line() + end_itr.backward_char() + + line_str = buffer.get_slice(start_itr, end_itr, True) + + end_itr.forward_char() + buffer.insert(end_itr, f"{line_str}\n", -1) + + new_itr = buffer.get_iter_at_line_offset(start_line, start_char) + buffer.place_cursor(new_itr) + + def cut_to_buffer(self, buffer = None): + self.cancel_timer() + + buffer = self.get_buffer() if not buffer else buffer + itr = buffer.get_iter_at_mark( buffer.get_insert() ) + start_itr = itr.copy() + end_itr = itr.copy() + start_line = itr.get_line() + 1 + start_char = itr.get_line_offset() + + start_itr.backward_visible_line() + start_itr.forward_line() + end_itr.forward_line() + + line_str = buffer.get_slice(start_itr, end_itr, True) + self._cut_buffer += f"{line_str}" + buffer.delete(start_itr, end_itr) + + self.clear_cut_buffer_delayed() + + def paste_cut_buffer(self, buffer = None): + self.cancel_timer() + + buffer = self.get_buffer() if not buffer else buffer + itr = buffer.get_iter_at_mark( buffer.get_insert() ) + insert_itr = itr.copy() + + buffer.insert(insert_itr, self._cut_buffer, -1) + + self.clear_cut_buffer_delayed() def update_cursor_position(self, buffer = None): buffer = self.get_buffer() if not buffer else buffer diff --git a/src/core/widgets/base/sourceview/source_view_events.py b/src/core/widgets/base/sourceview/source_view_events.py index acb7ace..e1bf652 100644 --- a/src/core/widgets/base/sourceview/source_view_events.py +++ b/src/core/widgets/base/sourceview/source_view_events.py @@ -26,9 +26,8 @@ class SourceViewEvents(SourceViewDnDMixin, MarkEventsMixin, FileEventsMixin): if not self._loading_file: event_system.emit("buffer_changed", (buffer, )) - event_system.emit("textDocument/didChange", (file_type, buffer, )) - else: - event_system.emit("buffer_changed_first_load", (buffer, )) + # event_system.emit("textDocument/didChange", (file_type, buffer, )) + # event_system.emit("textDocument/completion", (self, )) self.update_cursor_position(buffer) -- 2.27.0