From 5fcf2d6f1aea16cdc50e018df3ccd6ddfafca8ed Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sun, 25 Feb 2024 15:46:51 -0600 Subject: [PATCH] multi file open setup; search/replace plugin initial rework --- plugins/search_replace/plugin.py | 251 +++++++++++------- plugins/search_replace/search_replace.glade | 1 - src/core/controllers/bridge_controller.py | 35 ++- src/core/controllers/files_controller.py | 9 +- src/core/widgets/base/webkit/ace_editor.py | 17 +- src/core/widgets/controls/open_file_button.py | 51 ++-- .../resources/js/newton/keybinding-newton.js | 11 +- 7 files changed, 247 insertions(+), 128 deletions(-) diff --git a/plugins/search_replace/plugin.py b/plugins/search_replace/plugin.py index b387f07..6a74acd 100644 --- a/plugins/search_replace/plugin.py +++ b/plugins/search_replace/plugin.py @@ -69,64 +69,70 @@ class Plugin(StylingMixin, ReplaceMixin, PluginBase): def subscribe_to_events(self): self._event_system.subscribe("tggl_search_replace", self._tggl_search_replace) - self._event_system.subscribe("set_active_src_view", self._set_active_src_view) + # self._event_system.subscribe("set_active_src_view", self._set_active_src_view) - def _set_active_src_view(self, source_view): - self._active_src_view = source_view - self._buffer = self._active_src_view.get_buffer() - self._tag_table = self._buffer.get_tag_table() - self.search_for_string(self._find_entry) + # def _set_active_src_view(self, source_view): + # self._active_src_view = source_view + # self._buffer = self._active_src_view.get_buffer() + # self._tag_table = self._buffer.get_tag_table() + # self.search_for_string(self._find_entry) def _show_search_replace(self, widget = None, eve = None): self._search_replace_dialog.popup() def _tggl_search_replace(self, widget = None, eve = None): is_visible = self._search_replace_dialog.is_visible() - buffer = self._active_src_view.get_buffer() - data = None - - if buffer.get_has_selection(): - start, end = buffer.get_selection_bounds() - data = buffer.get_text(start, end, include_hidden_chars = False) - - if data: - self._find_entry.set_text(data) - if not is_visible: self._search_replace_dialog.popup(); self._find_entry.grab_focus() - elif not data and is_visible: - self._search_replace_dialog.popdown() - self._find_entry.set_text("") else: - self._find_entry.grab_focus() + self._search_replace_dialog.popdown(); + + # buffer = self._active_src_view.get_buffer() + # data = None + + # if buffer.get_has_selection(): + # start, end = buffer.get_selection_bounds() + # data = buffer.get_text(start, end, include_hidden_chars = False) + + # if data: + # self._find_entry.set_text(data) + + # if not is_visible: + # self._search_replace_dialog.popup(); + # self._find_entry.grab_focus() + # elif not data and is_visible: + # self._search_replace_dialog.popdown() + # self._find_entry.set_text("") + # else: + # self._find_entry.grab_focus() - def get_search_tag(self, buffer): - tag_table = buffer.get_tag_table() - search_tag = tag_table.lookup(self.search_tag) - if not search_tag: - search_tag = buffer.create_tag(self.search_tag, background = self.highlight_color, foreground = self.text_color) + # def get_search_tag(self, buffer): + # tag_table = buffer.get_tag_table() + # search_tag = tag_table.lookup(self.search_tag) + # if not search_tag: + # search_tag = buffer.create_tag(self.search_tag, background = self.highlight_color, foreground = self.text_color) - buffer.remove_tag_by_name(self.search_tag, buffer.get_start_iter(), buffer.get_end_iter()) - return search_tag + # buffer.remove_tag_by_name(self.search_tag, buffer.get_start_iter(), buffer.get_end_iter()) + # return search_tag - def cancel_timer(self): - if self.timer: - self.timer.cancel() - GLib.idle_remove_by_data(None) + # def cancel_timer(self): + # if self.timer: + # self.timer.cancel() + # GLib.idle_remove_by_data(None) - def delay_search_glib(self): - GLib.idle_add(self._do_highlight) + # def delay_search_glib(self): + # GLib.idle_add(self._do_highlight) - def delay_search(self): - wait_time = self.search_time / len(self.find_text) - wait_time = max(wait_time, 0.05) + # def delay_search(self): + # wait_time = self.search_time / len(self.find_text) + # wait_time = max(wait_time, 0.05) - self.timer = threading.Timer(wait_time, self.delay_search_glib) - self.timer.daemon = True - self.timer.start() + # self.timer = threading.Timer(wait_time, self.delay_search_glib) + # self.timer.daemon = True + # self.timer.start() def on_enter_search(self, widget, eve): @@ -138,84 +144,133 @@ class Plugin(StylingMixin, ReplaceMixin, PluginBase): self.find_next(widget) def search_for_string(self, widget): - self.cancel_timer() + # query = self._find_entry.get_text() + query = widget.get_text() - self.find_text = widget.get_text() - if len(self.find_text) > 0 and len(self.find_text) < 5: - self.delay_search() - else: - self._do_highlight(self.find_text) + if not query: return + + isBackwwards = True + isWrap = True + isCaseSensitive = self.use_case_sensitive + useWholeWord = self.use_whole_word_search + useRegExp = self.use_regex + # self.search_only_in_selection + + self._event_system.emit( + "find_entry", + ( + query, + isBackwwards, + isWrap, + isCaseSensitive, + useWholeWord, + useRegExp, + ) + ) - def _do_highlight(self, query = None): - query = self.find_text if not query else query - buffer = self._active_src_view.get_buffer() - # Also clears tag from buffer so if no query we're clean in ui - search_tag = self.get_search_tag(buffer) + # def search_for_string(self, widget): + # self.cancel_timer() - self.update_style(1) - if not query: - self._find_status_lbl.set_label(f"Find in current buffer") - self.update_style(0) - return + # self.find_text = widget.get_text() + # if len(self.find_text) > 0 and len(self.find_text) < 5: + # self.delay_search() + # else: + # self._do_highlight(self.find_text) - start_itr = buffer.get_start_iter() - end_itr = buffer.get_end_iter() - results, total_count = self.search(start_itr, query) - self._update_status_lbl(total_count, query) - for start, end in results: - buffer.apply_tag(search_tag, start, end) + # def _do_highlight(self, query = None): + # query = self.find_text if not query else query + # buffer = self._active_src_view.get_buffer() + # # Also clears tag from buffer so if no query we're clean in ui + # search_tag = self.get_search_tag(buffer) - def search(self, start_itr = None, query = None, limit = None): - if not start_itr or not query: return None, None + # self.update_style(1) + # if not query: + # self._find_status_lbl.set_label(f"Find in current buffer") + # self.update_style(0) + # return - flags = Gtk.TextSearchFlags.VISIBLE_ONLY | Gtk.TextSearchFlags.TEXT_ONLY - if not self.use_case_sensitive: - flags = flags | Gtk.TextSearchFlags.CASE_INSENSITIVE + # start_itr = buffer.get_start_iter() + # end_itr = buffer.get_end_iter() - if self.search_only_in_selection and self._buffer.get_has_selection(): - start_itr, limit = self._buffer.get_selection_bounds() + # results, total_count = self.search(start_itr, query) + # self._update_status_lbl(total_count, query) + # for start, end in results: + # buffer.apply_tag(search_tag, start, end) - _results = [] - while True: - result = start_itr.forward_search(query, flags, limit) - if not result: break + # def search(self, start_itr = None, query = None, limit = None): + # if not start_itr or not query: return None, None - _results.append(result) - start_itr = result[1] + # flags = Gtk.TextSearchFlags.VISIBLE_ONLY | Gtk.TextSearchFlags.TEXT_ONLY + # if not self.use_case_sensitive: + # flags = flags | Gtk.TextSearchFlags.CASE_INSENSITIVE - results = self.apply_filters(_results, query) - return results, len(results) + # if self.search_only_in_selection and self._buffer.get_has_selection(): + # start_itr, limit = self._buffer.get_selection_bounds() - def apply_filters(self, _results, query): - results = [] - for start, end in _results: - text = self._buffer.get_slice(start, end, include_hidden_chars = False) - if self.use_whole_word_search: - if not self.is_whole_word(start, end): - continue + # _results = [] + # while True: + # result = start_itr.forward_search(query, flags, limit) + # if not result: break - results.append([start, end]) + # _results.append(result) + # start_itr = result[1] - return results + # results = self.apply_filters(_results, query) + # return results, len(results) + + # def apply_filters(self, _results, query): + # results = [] + # for start, end in _results: + # text = self._buffer.get_slice(start, end, include_hidden_chars = False) + # if self.use_whole_word_search: + # if not self.is_whole_word(start, end): + # continue + + # results.append([start, end]) + + # return results def find_next(self, widget, eve = None, use_data = None): - mark = self._buffer.get_insert() - iter = self._buffer.get_iter_at_mark(mark) - iter.forward_line() + self._event_system.emit("find_next_entry") - search_tag = self._tag_table.lookup(self.search_tag) - next_tag_found = iter.forward_to_tag_toggle(search_tag) - if not next_tag_found: - self._buffer.place_cursor( self._buffer.get_start_iter() ) - mark = self._buffer.get_insert() - iter = self._buffer.get_iter_at_mark(mark) - iter.forward_to_tag_toggle(search_tag) + def find_prior(self, widget, eve = None, use_data = None): + self._event_system.emit("find_prior_entry") - self._buffer.place_cursor(iter) - self._active_src_view.scroll_to_mark( self._buffer.get_insert(), 0.0, True, 0.0, 0.0 ) + # def find_next(self, widget, eve = None, use_data = None): + # mark = self._buffer.get_insert() + # iter = self._buffer.get_iter_at_mark(mark) + # iter.forward_line() + + # search_tag = self._tag_table.lookup(self.search_tag) + # next_tag_found = iter.forward_to_tag_toggle(search_tag) + # if not next_tag_found: + # self._buffer.place_cursor( self._buffer.get_start_iter() ) + # mark = self._buffer.get_insert() + # iter = self._buffer.get_iter_at_mark(mark) + # iter.forward_to_tag_toggle(search_tag) + + # self._buffer.place_cursor(iter) + # self._active_src_view.scroll_to_mark( self._buffer.get_insert(), 0.0, True, 0.0, 0.0 ) def find_all(self, widget): - ... \ No newline at end of file + ... + + + def replace(self, widget): + fromStr = self._find_entry.get_text() + toStr = self._replace_entry.get_text() + if not fromStr or not toStr: return + + self._event_system.emit("replace_entry", (fromStr, toStr)) + + + def replace_all(self, widget): + fromStr = self._find_entry.get_text() + toStr = self._replace_entry.get_text() + if not fromStr or not toStr: return + + self._event_system.emit("replace_all", (fromStr, toStr)) + diff --git a/plugins/search_replace/search_replace.glade b/plugins/search_replace/search_replace.glade index ccab6c8..6724b79 100644 --- a/plugins/search_replace/search_replace.glade +++ b/plugins/search_replace/search_replace.glade @@ -72,7 +72,6 @@ .* True - False True False True diff --git a/src/core/controllers/bridge_controller.py b/src/core/controllers/bridge_controller.py index 2a60168..b2daecb 100644 --- a/src/core/controllers/bridge_controller.py +++ b/src/core/controllers/bridge_controller.py @@ -24,6 +24,10 @@ class BridgeController: event_system.subscribe(f"keyboard_open_file", self.keyboard_open_file) event_system.subscribe(f"keyboard_scale_up_text", self.keyboard_scale_up_text) event_system.subscribe(f"keyboard_scale_down_text", self.keyboard_scale_down_text) + event_system.subscribe(f"find_entry", self.find_entry) + event_system.subscribe(f"find_next_entry", self.find_next_entry) + event_system.subscribe(f"find_previous_entry", self.find_previous_entry) + event_system.subscribe(f"replace_entry", self.replace_entry) event_system.subscribe(f"toggle_highlight_line", self.toggle_highlight_line) def keyboard_open_file(self, gfiles): @@ -38,6 +42,33 @@ class BridgeController: def toggle_highlight_line(self): event_system.emit(f"toggle_highlight_line_{self.originator}") + def find_entry(self, query, isBackwwards, isWrap, isCaseSensitive, + useWholeWord, + useRegExp): + event_system.emit( + f"find_entry_{self.originator}", + ( + query, + isBackwwards, + isWrap, + isCaseSensitive, + useWholeWord, + useRegExp + ) + ) + + def find_next_entry(self): + event_system.emit(f"find_next_entry_{self.originator}") + + def find_previous_entry(self): + event_system.emit(f"find_previous_entry_{self.originator}") + + def replace_entry(self, fromStr, toStr): + event_system.emit(f"replace_entry_{self.originator}", (fromStr, toStr,)) + + def replace_all(self, fromStr, toStr): + event_system.emit(f"replace_all_{self.originator}", (fromStr, toStr,)) + def handle_bridge_event(self, event): self.originator = event.originator @@ -56,10 +87,6 @@ class BridgeController: event_system.emit(f"handle_file_event_{event.originator}", (event,)) case "tggl_search_replace": event_system.emit(f"tggl_search_replace") - case "find_entry": - event_system.emit(f"find_entry_{event.originator}") - case "replace_entry": - event_system.emit(f"replace_entry_{event.originator}") case "tggl_top_main_menubar": event_system.emit("tggl_top_main_menubar") case "set_info_labels": diff --git a/src/core/controllers/files_controller.py b/src/core/controllers/files_controller.py index 0c75b28..0af5f52 100644 --- a/src/core/controllers/files_controller.py +++ b/src/core/controllers/files_controller.py @@ -86,7 +86,14 @@ class FilesController: content = base64.b64decode( event.content.encode() ).decode("utf-8") # event_system.emit(f"add_tab_with_name_{event.originator}", (event.fhash, content,)) case "open_file": - event_system.emit(f"open_files", (None, None, self.INDEX,)) + _gfiles = event_system.emit_and_await(f"open_files", (None, None, event.fpath,)) + if _gfiles: + event_system.emit( + f"set_pre_drop_dnd_{self.INDEX}", + ( + _gfiles, + ) + ) case _: return diff --git a/src/core/widgets/base/webkit/ace_editor.py b/src/core/widgets/base/webkit/ace_editor.py index 12031b0..07cd7c7 100644 --- a/src/core/widgets/base/webkit/ace_editor.py +++ b/src/core/widgets/base/webkit/ace_editor.py @@ -54,7 +54,10 @@ class AceEditor(WebKit2.WebView): event_system.subscribe(f"keyboard_scale_down_text_{self.INDEX}", self.keyboard_scale_down_text) event_system.subscribe(f"toggle_highlight_line_{self.INDEX}", self.toggle_highlight_line) event_system.subscribe(f"find_entry_{self.INDEX}", self.find_entry) + event_system.subscribe(f"find_next_entry_{self.INDEX}", self.find_next_entry) + event_system.subscribe(f"find_previous_entry_{self.INDEX}", self.find_previous_entry) event_system.subscribe(f"replace_entry_{self.INDEX}", self.replace_entry) + event_system.subscribe(f"replace_all_{self.INDEX}", self.replace_all) event_system.subscribe(f"ui_message_{self.INDEX}", self.ui_message) def _load_settings(self): @@ -126,8 +129,18 @@ class AceEditor(WebKit2.WebView): command = f"displayMessage('{message}', '{mtype}', '3')" self.run_javascript(command, None, None) - def find_entry(self, query): - command = f"findEntry('{query}')" + def find_entry(self, query, isBackwwards, isWrap, isCaseSensitive, + useWholeWord, + useRegExp): + command = f"findEntry('{query}', '{isBackwwards}', '{isWrap}', '{isCaseSensitive}', '{useWholeWord}', '{useRegExp}')" + self.run_javascript(command, None, None) + + def find_next_entry(self): + command = f"findNextEntry()" + self.run_javascript(command, None, None) + + def find_previous_entry(self): + command = f"findPreviousEntry()" self.run_javascript(command, None, None) def replace_entry(self, fromStr, toStr): diff --git a/src/core/widgets/controls/open_file_button.py b/src/core/widgets/controls/open_file_button.py index e60e1f4..a6f6a0b 100644 --- a/src/core/widgets/controls/open_file_button.py +++ b/src/core/widgets/controls/open_file_button.py @@ -41,37 +41,46 @@ class OpenFileButton(Gtk.Button): def _load_widgets(self): ... - def _open_files(self, widget = None, eve = None, widget_index = None): - chooser = Gtk.FileChooserDialog("Open File...", None, + def _open_files(self, widget = None, eve = None, fpath = None): + start_dir = None + gfile = Gio.File.new_for_path(fpath) + _gfiles = [] + + if gfile.query_exists(): + start_dir = gfile.get_parent() + + chooser = Gtk.FileChooserDialog("Open File(s)...", None, Gtk.FileChooserAction.OPEN, - (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, - Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) - + ( + Gtk.STOCK_CANCEL, + Gtk.ResponseType.CANCEL, + Gtk.STOCK_OPEN, + Gtk.ResponseType.OK + ) + ) + + chooser.set_select_multiple(True) + try: - folder = widget.get_current_file().get_parent() - chooser.set_current_folder( folder.get_uri() ) + folder = widget.get_current_file().get_parent() if not start_dir else start_dir + chooser.set_current_folder( folder.get_path() ) except Exception as e: ... response = chooser.run() if not response == Gtk.ResponseType.OK: chooser.destroy() - return + return _gfiles - filename = chooser.get_filename() - if not filename: + filenames = chooser.get_filenames() + if not filenames: chooser.destroy() - return + return _gfiles - - path = filename if os.path.isabs(filename) else os.path.abspath(filename) - _gfile = Gio.File.new_for_path(path) - - event_system.emit( - f"set_pre_drop_dnd_{widget_index}" if widget_index else "keyboard_open_file", - ( - [_gfile], - ) - ) + for file in filenames: + path = file if os.path.isabs(file) else os.path.abspath(file) + _gfiles.append( Gio.File.new_for_path(path) ) chooser.destroy() + + return _gfiles diff --git a/user_config/usr/share/newton/context_path/resources/js/newton/keybinding-newton.js b/user_config/usr/share/newton/context_path/resources/js/newton/keybinding-newton.js index 2d284a1..2e72570 100644 --- a/user_config/usr/share/newton/context_path/resources/js/newton/keybinding-newton.js +++ b/user_config/usr/share/newton/context_path/resources/js/newton/keybinding-newton.js @@ -17,13 +17,22 @@ const editorCommands = [ editor.showKeyboardShortcuts(); }) } + }, { + name: "search", + bindKey: {win: "ctrl-f", mac: "ctrl-f"}, + exec: function(editor) { + sendMessage("tggl_search_replace", "", "", "", ""); + }, + readOnly: true }, { name: "openFile", bindKey: {win: "ctrl-o", mac: "ctrl-o"}, exec: function(editor) { - sendMessage("open_file", "", "", "", ""); + fpath = aceSessions[currentSession]["fpath"] + sendMessage("open_file", "", "", fpath, ""); }, readOnly: true + }, { name: "saveSession", bindKey: {win: "ctrl-s", mac: "ctrl-s"},