about summary refs log tree commit diff
diff options
context:
space:
mode:
-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