fix up Terminal some more and make the searching work, and include a hacky backwards search
This commit is contained in:
parent
565257672a
commit
8d19561f85
@ -7,26 +7,37 @@ import gtk
|
||||
import gobject
|
||||
|
||||
from translation import _
|
||||
from config import Config
|
||||
from util import dbg
|
||||
|
||||
# pylint: disable-msg=R0904
|
||||
class Searchbar(gtk.HBox):
|
||||
"""Class implementing the Searchbar widget"""
|
||||
|
||||
__gsignals__ = {
|
||||
'do-search': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
|
||||
'next-search': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
|
||||
'end-search': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
|
||||
}
|
||||
|
||||
entry = None
|
||||
reslabel = None
|
||||
next = None
|
||||
prev = None
|
||||
|
||||
vte = None
|
||||
config = None
|
||||
|
||||
searchstring = None
|
||||
searchrow = None
|
||||
|
||||
searchits = None
|
||||
|
||||
def __init__(self):
|
||||
"""Class initialiser"""
|
||||
gtk.HBox.__init__(self)
|
||||
self.__gobject_init__()
|
||||
|
||||
self.config = Config()
|
||||
|
||||
# Search text
|
||||
self.entry = gtk.Entry()
|
||||
self.entry.set_activates_default(True)
|
||||
@ -59,14 +70,25 @@ class Searchbar(gtk.HBox):
|
||||
self.next = gtk.Button(_('Next'))
|
||||
self.next.connect('clicked', self.next_search)
|
||||
|
||||
# Previous Button
|
||||
self.prev = gtk.Button(_('Prev'))
|
||||
self.prev.connect('clicked', self.prev_search)
|
||||
|
||||
self.pack_start(label, False)
|
||||
self.pack_start(self.entry)
|
||||
self.pack_start(self.reslabel, False)
|
||||
self.pack_start(self.prev, False, False)
|
||||
self.pack_start(self.next, False, False)
|
||||
self.pack_end(close, False, False)
|
||||
|
||||
self.hide()
|
||||
|
||||
def get_vte(self):
|
||||
"""Find our parent widget"""
|
||||
parent = self.get_parent()
|
||||
if parent:
|
||||
self.vte = parent.vte
|
||||
|
||||
# pylint: disable-msg=W0613
|
||||
def search_keypress(self, widget, event):
|
||||
"""Handle keypress events"""
|
||||
@ -74,17 +96,88 @@ class Searchbar(gtk.HBox):
|
||||
if key == 'Escape':
|
||||
self.end_search()
|
||||
|
||||
def start_search(self):
|
||||
"""Show ourselves"""
|
||||
if not self.vte:
|
||||
self.get_vte()
|
||||
|
||||
self.show()
|
||||
self.entry.grab_focus()
|
||||
|
||||
def do_search(self, widget):
|
||||
"""Trap and re-emit the clicked signal"""
|
||||
self.emit('do-search', widget)
|
||||
self.searchhits = []
|
||||
searchtext = self.entry.get_text()
|
||||
if searchtext == '':
|
||||
return
|
||||
|
||||
if searchtext != self.searchstring:
|
||||
self.searchrow = self.get_vte_buffer_range()[0]
|
||||
self.searchstring = searchtext
|
||||
|
||||
self.reslabel.set_text(_("Searching scrollback"))
|
||||
self.next_search(None)
|
||||
|
||||
def next_search(self, widget):
|
||||
"""Trap and re-emit the next-search signal"""
|
||||
self.emit('next-search', widget)
|
||||
"""Search forwards and jump to the next result, if any"""
|
||||
# FIXME: I think we should emit a signal and have Terminal() do this.
|
||||
startrow,endrow = self.get_vte_buffer_range()
|
||||
while True:
|
||||
if self.searchrow == endrow:
|
||||
self.searchrow = startrow
|
||||
self.reslabel.set_text(_("Finished search"))
|
||||
self.next.hide()
|
||||
self.prev.hide()
|
||||
return
|
||||
buffer = self.vte.get_text_range(self.searchrow, 0,
|
||||
self.searchrow, -1,
|
||||
self.search_character)
|
||||
|
||||
def end_search(self, widget):
|
||||
index = buffer.find(self.searchstring)
|
||||
if index != -1:
|
||||
self.searchhits.append(self.searchrow)
|
||||
self.search_hit(self.searchrow)
|
||||
self.searchrow += 1
|
||||
return
|
||||
self.searchrow += 1
|
||||
|
||||
def prev_search(self, widget):
|
||||
"""Jump back to the previous search"""
|
||||
row = self.searchhits.pop()
|
||||
position = self.get_parent().scrollbar_position()
|
||||
while row >= position:
|
||||
row = self.searchhits.pop()
|
||||
self.search_hit(row)
|
||||
self.searchrow -= 1
|
||||
|
||||
def search_hit(self, row):
|
||||
"""Update the UI for a search hit"""
|
||||
dbg('Searchbar::search_hit row %d, history of %d' % (row,
|
||||
len(self.searchhits)))
|
||||
self.reslabel.set_text("%s %d" % (_('Found at row'), row))
|
||||
self.get_parent().scrollbar_jump(row)
|
||||
self.next.show()
|
||||
if len(self.searchhits) > 1:
|
||||
self.prev.show()
|
||||
else:
|
||||
self.prev.hide()
|
||||
|
||||
def search_character(self, widget, col, row, junk):
|
||||
"""We have to have a callback for each character"""
|
||||
return(True)
|
||||
|
||||
def get_vte_buffer_range(self):
|
||||
"""Get the range of a vte widget"""
|
||||
column, endrow = self.vte.get_cursor_position()
|
||||
startrow = max(0, endrow - self.config['scrollback_lines'])
|
||||
return(startrow, endrow)
|
||||
|
||||
def end_search(self, widget=None):
|
||||
"""Trap and re-emit the end-search signal"""
|
||||
self.emit('end-search', widget)
|
||||
self.searchrow = 0
|
||||
self.searchstring = None
|
||||
self.reslabel.set_text('')
|
||||
self.emit('end-search')
|
||||
|
||||
def get_search_term(self):
|
||||
"""Return the currently set search term"""
|
||||
|
@ -110,6 +110,7 @@ class Terminal(gtk.VBox):
|
||||
self.titlebar.connect('create-group', self.really_create_group)
|
||||
|
||||
self.searchbar = Searchbar()
|
||||
self.searchbar.connect('end-search', self.on_search_done)
|
||||
|
||||
self.show()
|
||||
self.pack_start(self.titlebar, False)
|
||||
@ -645,6 +646,20 @@ class Terminal(gtk.VBox):
|
||||
def on_vte_focus_in(self, widget, event):
|
||||
self.emit('focus-in')
|
||||
|
||||
def scrollbar_jump(self, position):
|
||||
"""Move the scrollbar to a particular row"""
|
||||
self.scrollbar.set_value(position)
|
||||
|
||||
def scrollbar_position(self):
|
||||
"""Return the current position of the scrollbar"""
|
||||
return(self.scrollbar.get_value())
|
||||
|
||||
def on_search_done(self, widget):
|
||||
"""We've finished searching, so clean up"""
|
||||
self.searchbar.hide()
|
||||
self.scrollbar.set_value(self.vte.get_cursor_position()[1])
|
||||
self.vte.grab_focus()
|
||||
|
||||
def on_edit_done(self, widget):
|
||||
"""A child widget is done editing a label, return focus to VTE"""
|
||||
self.vte.grab_focus()
|
||||
@ -761,7 +776,7 @@ class Terminal(gtk.VBox):
|
||||
|
||||
def paste_clipboard(self, primary=False):
|
||||
"""Paste one of the two clipboards"""
|
||||
for term in self.terminator.get_target_terms():
|
||||
for term in self.terminator.get_target_terms(self):
|
||||
if primary:
|
||||
term.vte.paste_primary()
|
||||
else:
|
||||
@ -810,7 +825,7 @@ class Terminal(gtk.VBox):
|
||||
self.vte.copy_clipboard()
|
||||
|
||||
def key_paste(self):
|
||||
self.vte-paste_clipboard()
|
||||
self.vte.paste_clipboard()
|
||||
|
||||
def key_toggle_scrollbar(self):
|
||||
self.do_scrollbar_toggle()
|
||||
@ -819,7 +834,7 @@ class Terminal(gtk.VBox):
|
||||
self.zoom_orig ()
|
||||
|
||||
def key_search(self):
|
||||
self.start_search()
|
||||
self.searchbar.start_search()
|
||||
|
||||
# bindings that should be moved to Terminator as they all just call
|
||||
# a function of Terminator. It would be cleaner if TerminatorTerm
|
||||
|
Loading…
Reference in New Issue
Block a user