|
Packit |
6978fb |
# -*- coding: utf-8 -*-
|
|
Packit |
6978fb |
#
|
|
Packit |
6978fb |
# finder.py - finder commander module
|
|
Packit |
6978fb |
#
|
|
Packit |
6978fb |
# Copyright (C) 2010 - Jesse van den Kieboom
|
|
Packit |
6978fb |
#
|
|
Packit |
6978fb |
# This program is free software; you can redistribute it and/or modify
|
|
Packit |
6978fb |
# it under the terms of the GNU General Public License as published by
|
|
Packit |
6978fb |
# the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
6978fb |
# (at your option) any later version.
|
|
Packit |
6978fb |
#
|
|
Packit |
6978fb |
# This program is distributed in the hope that it will be useful,
|
|
Packit |
6978fb |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
6978fb |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
6978fb |
# GNU General Public License for more details.
|
|
Packit |
6978fb |
#
|
|
Packit |
6978fb |
# You should have received a copy of the GNU General Public License
|
|
Packit |
6978fb |
# along with this program; if not, write to the Free Software
|
|
Packit |
6978fb |
# Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Packit |
6978fb |
# Boston, MA 02110-1301, USA.
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
from xml.sax import saxutils
|
|
Packit |
6978fb |
import commander.commands.result
|
|
Packit |
6978fb |
import commander.utils as utils
|
|
Packit |
6978fb |
from gi.repository import Gdk, Gtk
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
class Finder:
|
|
Packit |
6978fb |
FIND_STARTMARK = 'gedit-commander-find-startmark'
|
|
Packit |
6978fb |
FIND_ENDMARK = 'gedit-commander-find-endmark'
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
FIND_RESULT_STARTMARK = 'gedit-commander-find-result-startmark'
|
|
Packit |
6978fb |
FIND_RESULT_ENDMARK = 'gedit-commander-find-result-endmark'
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
def __init__(self, entry):
|
|
Packit |
6978fb |
self.entry = entry
|
|
Packit |
6978fb |
self.view = entry.view()
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
self.findstr = None
|
|
Packit |
6978fb |
self.replacestr = None
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
self.search_boundaries = utils.Struct({'start': None, 'end': None})
|
|
Packit |
6978fb |
self.find_result = utils.Struct({'start': None, 'end': None})
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
self.unescapes = [
|
|
Packit |
6978fb |
['\\n', '\n'],
|
|
Packit |
6978fb |
['\\r', '\r'],
|
|
Packit |
6978fb |
['\\t', '\t']
|
|
Packit |
6978fb |
]
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
self.from_start = False
|
|
Packit |
6978fb |
self.search_start_mark = None
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
def unescape(self, s):
|
|
Packit |
6978fb |
for esc in self.unescapes:
|
|
Packit |
6978fb |
s = s.replace(esc[0], esc[1])
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
return s
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
def do_find(self, bounds):
|
|
Packit |
6978fb |
return None
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
def get_replace(self, text):
|
|
Packit |
6978fb |
return self.replacestr
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
def set_replace(self, replacestr):
|
|
Packit |
6978fb |
self.replacestr = self.unescape(replacestr)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
def set_find(self, findstr):
|
|
Packit |
6978fb |
self.findstr = self.unescape(findstr)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
def get_find(self):
|
|
Packit |
6978fb |
return self.findstr
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
def select_last_result(self):
|
|
Packit |
6978fb |
buf = self.view.get_buffer()
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
startiter = buf.get_iter_at_mark(self.find_result.start)
|
|
Packit |
6978fb |
enditer = buf.get_iter_at_mark(self.find_result.end)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
buf.select_range(startiter, enditer)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
visible = self.view.get_visible_rect()
|
|
Packit |
6978fb |
loc = self.view.get_iter_location(startiter)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
# Scroll there if needed
|
|
Packit |
6978fb |
if loc.y + loc.height < visible.y or loc.y > visible.y + visible.height:
|
|
Packit |
6978fb |
self.view.scroll_to_iter(startiter, 0.2, True, 0, 0.5)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
def find_next(self, select=False):
|
|
Packit |
6978fb |
buf = self.view.get_buffer()
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
# Search from the end of the last result to the end of the search boundary
|
|
Packit |
6978fb |
bounds = [buf.get_iter_at_mark(self.find_result.end),
|
|
Packit |
6978fb |
buf.get_iter_at_mark(self.search_boundaries.end)]
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
ret = self.do_find(bounds)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
# Check if we need to wrap around if nothing is found
|
|
Packit |
6978fb |
if self.search_start_mark:
|
|
Packit |
6978fb |
startiter = buf.get_iter_at_mark(self.search_start_mark)
|
|
Packit |
6978fb |
else:
|
|
Packit |
6978fb |
startiter = None
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
startbound = buf.get_iter_at_mark(self.search_boundaries.start)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
if not ret and not self.from_start and (startiter and not startiter.equal(startbound)):
|
|
Packit |
6978fb |
self.from_start = True
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
# Try from beginning
|
|
Packit |
6978fb |
bounds[0] = buf.get_start_iter()
|
|
Packit |
6978fb |
bounds[1] = startiter
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
# Make sure to just stop at the start of the previous
|
|
Packit |
6978fb |
self.search_boundaries.end = self.search_start_mark
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
ret = self.do_find(bounds)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
if not ret:
|
|
Packit |
6978fb |
return False
|
|
Packit |
6978fb |
else:
|
|
Packit |
6978fb |
# Mark find result
|
|
Packit |
6978fb |
buf.move_mark(self.find_result.start, ret[0])
|
|
Packit |
6978fb |
buf.move_mark(self.find_result.end, ret[1])
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
if select:
|
|
Packit |
6978fb |
self.select_last_result()
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
return True
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
def _create_or_move(self, markname, piter, left_gravity):
|
|
Packit |
6978fb |
buf = self.view.get_buffer()
|
|
Packit |
6978fb |
mark = buf.get_mark(markname)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
if not mark:
|
|
Packit |
6978fb |
mark = buf.create_mark(markname, piter, left_gravity)
|
|
Packit |
6978fb |
else:
|
|
Packit |
6978fb |
buf.move_mark(mark, piter)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
return mark
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
def find_first(self, doend=True, select=False):
|
|
Packit |
6978fb |
words = []
|
|
Packit |
6978fb |
buf = self.view.get_buffer()
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
while not self.findstr:
|
|
Packit |
6978fb |
fstr, words, modifier = (yield commander.commands.result.Prompt('Find:'))
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
if fstr:
|
|
Packit |
6978fb |
self.set_find(fstr)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
# Determine search area
|
|
Packit |
6978fb |
bounds = list(buf.get_selection_bounds())
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
if self.search_start_mark:
|
|
Packit |
6978fb |
buf.delete_mark(self.search_start_mark)
|
|
Packit |
6978fb |
self.search_start_mark = None
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
if not bounds:
|
|
Packit |
6978fb |
# Search in the whole buffer, from the current cursor position on to the
|
|
Packit |
6978fb |
# end, and then continue to start from the beginning of the buffer if needed
|
|
Packit |
6978fb |
bounds = list(buf.get_bounds())
|
|
Packit |
6978fb |
self.search_start_mark = buf.create_mark(None, buf.get_iter_at_mark(buf.get_insert()), True)
|
|
Packit |
6978fb |
selection = False
|
|
Packit |
6978fb |
else:
|
|
Packit |
6978fb |
selection = True
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
bounds[0].order(bounds[1])
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
# Set marks at the boundaries
|
|
Packit |
6978fb |
self.search_boundaries.start = self._create_or_move(Finder.FIND_STARTMARK, bounds[0], True)
|
|
Packit |
6978fb |
self.search_boundaries.end = self._create_or_move(Finder.FIND_ENDMARK, bounds[1], False)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
# Set the result marks so the next find will start at the correct location
|
|
Packit |
6978fb |
if selection:
|
|
Packit |
6978fb |
piter = bounds[0]
|
|
Packit |
6978fb |
else:
|
|
Packit |
6978fb |
piter = buf.get_iter_at_mark(buf.get_insert())
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
self.find_result.start = self._create_or_move(Finder.FIND_RESULT_STARTMARK, piter, True)
|
|
Packit |
6978fb |
self.find_result.end = self._create_or_move(Finder.FIND_RESULT_ENDMARK, piter, False)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
if not self.find_next(select=select):
|
|
Packit |
6978fb |
if doend:
|
|
Packit |
6978fb |
self.entry.info_show('Search hit end of the document', True)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
yield commander.commands.result.DONE
|
|
Packit |
6978fb |
else:
|
|
Packit |
6978fb |
yield True
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
def cancel(self):
|
|
Packit |
6978fb |
buf = self.view.get_buffer()
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
buf.set_search_text('', 0)
|
|
Packit |
6978fb |
buf.move_mark(buf.get_selection_bound(), buf.get_iter_at_mark(buf.get_insert()))
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
if self.search_start_mark:
|
|
Packit |
6978fb |
buf.delete_mark(self.search_start_mark)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
def find(self, findstr):
|
|
Packit |
6978fb |
if findstr:
|
|
Packit |
6978fb |
self.set_find(findstr)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
buf = self.view.get_buffer()
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
try:
|
|
Packit |
6978fb |
if (yield self.find_first(select=True)):
|
|
Packit |
6978fb |
while True:
|
|
Packit |
6978fb |
argstr, words, modifier = (yield commander.commands.result.Prompt('Search next [%s]:' % (saxutils.escape(self.findstr),)))
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
if argstr:
|
|
Packit |
6978fb |
self.set_find(argstr)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
if not self.find_next(select=True):
|
|
Packit |
6978fb |
break
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
self.entry.info_show('Search hit end of the document', True)
|
|
Packit |
6978fb |
except GeneratorExit as e:
|
|
Packit |
6978fb |
self.cancel()
|
|
Packit |
6978fb |
raise e
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
self.cancel()
|
|
Packit |
6978fb |
yield commander.commands.result.DONE
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
def _restore_cursor(self, mark):
|
|
Packit |
6978fb |
buf = mark.get_buffer()
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
buf.place_cursor(buf.get_iter_at_mark(mark))
|
|
Packit |
6978fb |
buf.delete_mark(mark)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
self.view.scroll_to_mark(buf.get_insert(), 0.2, True, 0, 0.5)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
def get_current_replace(self):
|
|
Packit |
6978fb |
buf = self.view.get_buffer()
|
|
Packit |
6978fb |
bounds = utils.Struct({'start': buf.get_iter_at_mark(self.find_result.start),
|
|
Packit |
6978fb |
'end': buf.get_iter_at_mark(self.find_result.end)})
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
if not bounds.start.equal(bounds.end):
|
|
Packit |
6978fb |
text = bounds.start.get_text(bounds.end)
|
|
Packit |
6978fb |
return self.get_replace(text)
|
|
Packit |
6978fb |
else:
|
|
Packit |
6978fb |
return self.replacestr
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
def replace(self, findstr, replaceall=False, replacestr=None):
|
|
Packit |
6978fb |
if findstr:
|
|
Packit |
6978fb |
self.set_find(findstr)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
if replacestr != None:
|
|
Packit |
6978fb |
self.set_replace(replacestr)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
# First find something
|
|
Packit |
6978fb |
buf = self.view.get_buffer()
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
if replaceall:
|
|
Packit |
6978fb |
startmark = buf.create_mark(None, buf.get_iter_at_mark(buf.get_insert()), False)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
ret = (yield self.find_first(select=not replaceall))
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
if not ret:
|
|
Packit |
6978fb |
yield commander.commands.result.DONE
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
self.scroll_back = False
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
# Then ask for the replacement string
|
|
Packit |
6978fb |
if not self.replacestr:
|
|
Packit |
6978fb |
try:
|
|
Packit |
6978fb |
if replaceall:
|
|
Packit |
6978fb |
self.scroll_back = True
|
|
Packit |
6978fb |
self.select_last_result()
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
replacestr, words, modifier = (yield commander.commands.result.Prompt('Replace with:'))
|
|
Packit |
6978fb |
self.set_replace(replacestr)
|
|
Packit |
6978fb |
except GeneratorExit as e:
|
|
Packit |
6978fb |
if replaceall:
|
|
Packit |
6978fb |
self._restore_cursor(startmark)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
self.cancel()
|
|
Packit |
6978fb |
raise e
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
# On replace all, wrap it in begin/end user action
|
|
Packit |
6978fb |
if replaceall:
|
|
Packit |
6978fb |
buf.begin_user_action()
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
try:
|
|
Packit |
6978fb |
while True:
|
|
Packit |
6978fb |
if not replaceall:
|
|
Packit |
6978fb |
rep, words, modifier = (yield commander.commands.result.Prompt('Replace next [%s]:' % (saxutils.escape(self.get_current_replace()),)))
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
if rep:
|
|
Packit |
6978fb |
self.set_replace(rep)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
bounds = utils.Struct({'start': buf.get_iter_at_mark(self.find_result.start),
|
|
Packit |
6978fb |
'end': buf.get_iter_at_mark(self.find_result.end)})
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
# If there is a selection, replace it with the replacement string
|
|
Packit |
6978fb |
if not bounds.start.equal(bounds.end) and (replaceall or not (modifier & Gdk.ModifierType.CONTROL_MASK)):
|
|
Packit |
6978fb |
text = bounds.start.get_text(bounds.end)
|
|
Packit |
6978fb |
repl = self.get_replace(text)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
buf.begin_user_action()
|
|
Packit |
6978fb |
buf.delete(bounds.start, bounds.end)
|
|
Packit |
6978fb |
buf.insert(bounds.start, repl)
|
|
Packit |
6978fb |
buf.end_user_action()
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
# Find next
|
|
Packit |
6978fb |
if not self.find_next(select=not replaceall):
|
|
Packit |
6978fb |
if not replaceall:
|
|
Packit |
6978fb |
self.entry.info_show('Search hit end of the document', True)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
break
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
except GeneratorExit as e:
|
|
Packit |
6978fb |
if replaceall:
|
|
Packit |
6978fb |
self._restore_cursor(startmark)
|
|
Packit |
6978fb |
buf.end_user_action()
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
self.cancel()
|
|
Packit |
6978fb |
raise e
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
if replaceall:
|
|
Packit |
6978fb |
if self.scroll_back:
|
|
Packit |
6978fb |
self._restore_cursor(startmark)
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
buf.end_user_action()
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
self.cancel()
|
|
Packit |
6978fb |
yield commander.commands.result.DONE
|
|
Packit |
6978fb |
|
|
Packit |
6978fb |
# ex:ts=4:et
|