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] 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)