generated from itdominator/Python-With-Gtk-Template
multi file open setup; search/replace plugin initial rework
This commit is contained in:
parent
070d94abc1
commit
5fcf2d6f1a
|
@ -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):
|
||||
...
|
||||
...
|
||||
|
||||
|
||||
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))
|
||||
|
||||
|
|
|
@ -72,7 +72,6 @@
|
|||
<object class="GtkToggleButton">
|
||||
<property name="label" translatable="yes">.*</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="focus-on-click">False</property>
|
||||
<property name="receives-default">True</property>
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"},
|
||||
|
|
Loading…
Reference in New Issue