about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSören Tempel <soeren+git@soeren-tempel.net>2021-05-30 06:16:27 +0200
committerSören Tempel <soeren+git@soeren-tempel.net>2021-05-30 06:16:27 +0200
commit30969bb6e6170dacf8cb3f54657801492a42640e (patch)
tree9154319e07705d8aae8f559612f1bcfbca0b567d
parent6c57f6e59b721a39fd0b876a8f3752789b6fee19 (diff)
Preliminary TextBuffer SearchBar support
Still lacking some configuration options (highlight all, case
insensitive search, …) and focus is not currently restored to the
TermView on close currently.
-rw-r--r--saneterm/keys.py2
-rw-r--r--saneterm/search.py64
-rw-r--r--saneterm/terminal.py20
3 files changed, 83 insertions, 3 deletions
diff --git a/saneterm/keys.py b/saneterm/keys.py
index 6b85ede..ab471a2 100644
--- a/saneterm/keys.py
+++ b/saneterm/keys.py
@@ -17,7 +17,9 @@ class Bindings():
             bind "<ctrl>a" { "move-input-start" () };
             bind "<ctrl>e" { "move-input-end" () };
             bind "<ctrl>j" { "insert-at-cursor" ("\\n") };
+
             bind "<ctrl>l" { "clear-view" () };
+            bind "<ctrl>f" { "toggle-search" () };
 
             bind "<ctrl>w" { "delete-from-cursor" (word-ends, -1) };
             bind "<ctrl>h" { "backspace" () };
diff --git a/saneterm/search.py b/saneterm/search.py
new file mode 100644
index 0000000..98cfb34
--- /dev/null
+++ b/saneterm/search.py
@@ -0,0 +1,64 @@
+from gi.repository import Gtk
+
+class SearchBar(Gtk.SearchBar):
+    "SearchBar implements Gtk.SearchBar on a Gtk.TextBuffer."
+
+    BG_COLOR = "yellow"
+    FG_COLOR = "black"
+
+    def __init__(self, buffer):
+        Gtk.SearchBar.__init__(self)
+        self.__buffer = buffer
+
+        self.__match = None
+        self.__tag = buffer.create_tag("search-match",
+                background=self.BG_COLOR,
+                foreground=self.FG_COLOR)
+
+        search_entry = Gtk.SearchEntry.new()
+        search_entry.connect("search-changed", self.__search_changed)
+        search_entry.connect("next-match", self.__next_match)
+        search_entry.connect("previous-match", self.__prev_match)
+
+        self.set_show_close_button(True)
+        self.connect_entry(search_entry)
+        self.add(search_entry)
+
+    def __find_match(self, entry, start, forward=True):
+        buf = self.__buffer
+        text = entry.get_text()
+
+        # Remove old match.
+        buf.remove_tag(self.__tag,
+                buf.get_start_iter(),
+                buf.get_end_iter())
+
+        if forward:
+            self.__match = start.forward_search(text, 0, None)
+        else:
+            self.__match = start.backward_search(text, 0, None)
+
+        if self.__match:
+            mstart, mend = self.__match
+            buf.apply_tag(self.__tag, mstart, mend)
+
+    def __search_changed(self, entry):
+        self.__find_match(entry, self.__buffer.get_start_iter())
+
+    def __next_match(self, entry):
+        # Wrap around if no match was found previously.
+        if self.__match is None:
+            start = self.__buffer.get_start_iter()
+        else:
+            _, start = self.__match
+
+        self.__find_match(entry, start)
+
+    def __prev_match(self, entry):
+        # Wrap around if no match was found previously.
+        if self.__match is None:
+            start = self.__buffer.get_end_iter()
+        else:
+            start, _ = self.__match
+
+        self.__find_match(entry, start, forward=False)
diff --git a/saneterm/terminal.py b/saneterm/terminal.py
index 2f71245..c25f596 100644
--- a/saneterm/terminal.py
+++ b/saneterm/terminal.py
@@ -7,6 +7,7 @@ import fcntl
 import struct
 
 from . import keys
+from .search import SearchBar
 from .history import History
 from .termview import *
 
@@ -86,13 +87,22 @@ class Terminal(Gtk.Window):
         for key, idx in keys.CTRL.items():
             bindings.add_bind(key, "termios-ctrlkey", idx)
 
+        vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
+        self.add(vbox)
+
         self.scroll = Gtk.ScrolledWindow().new(None, None)
         self.scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.ALWAYS)
-
         self.scroll.add(self.termview)
-        self.add(self.scroll)
-
         self.update_wrapmode()
+        vbox.pack_start(self.scroll, True, True, 0)
+
+        self.search_bar = SearchBar(self.termview.get_buffer())
+        vbox.pack_start(self.search_bar, False, True, 0)
+
+        GObject.signal_new("toggle-search", self.termview,
+                GObject.SIGNAL_ACTION, GObject.TYPE_NONE,
+                ())
+        self.termview.connect("toggle-search", self.toggle_search, self.search_bar)
 
         GObject.signal_new("history-entry", self.termview,
                 GObject.SIGNAL_ACTION, GObject.TYPE_NONE,
@@ -155,6 +165,10 @@ class Terminal(Gtk.Window):
         self.termview.insert_data(self.decoder.decode(data))
         return GLib.SOURCE_CONTINUE
 
+    def toggle_search(self, termview, search_bar):
+        active = search_bar.get_search_mode()
+        search_bar.set_search_mode(not active)
+
     def reset_history_index(self):
         self.hist_index = -1