pmacs3/mode_search.py

217 lines
6.7 KiB
Python

import sets, string
import color, method, minibuffer, mode2
from point2 import Point
class Search(mode2.Fundamental):
'''This is the default mode'''
def __init__(self, w):
mode2.Fundamental.__init__(self, w)
# clear out all the defaults that we don't want/need
self.actions = {}
self.bindings = {}
# add some useful bindings
self.add_action_and_bindings(SearchNext(), ('C-s',))
self.add_action_and_bindings(SearchPrevious(), ('C-r',))
self.add_action_and_bindings(EndSearch(), ('RETURN', 'C-n', 'C-p', 'C-a', 'C-e', 'C-f', 'C-b',))
self.add_action_and_bindings(CancelSearch(), ('C-]',))
self.add_action_and_bindings(SearchDeleteLeft(), ('DELETE', 'BACKSPACE',))
self.add_action_and_bindings(SearchDeleteLeftWord(), ('M-DELETE', 'M-BACKSPACE',))
# create all the insert actions for the character ranges we like
for collection in (string.letters, string.digits, string.punctuation):
for c in collection:
self.add_action_and_bindings(InsertSearchString(c), (c,))
self.add_action_and_bindings(InsertSearchString(' '), ('SPACE',))
def name(self):
return "Search"
class SearchNext(method.Method):
def execute(self, w, **vargs):
w.buffer.method.direction = 'next'
if not w.buffer.make_string():
w.buffer.set_data(w.application.last_search)
else:
old_w = w.buffer.method.old_window
_find_next(old_w, w, move=True)
class SearchPrevious(method.Method):
def execute(self, w, **vargs):
w.buffer.method.direction = 'previous'
if not w.buffer.make_string():
return
else:
old_w = w.buffer.method.old_window
_find_previous(old_w, w, move=True)
class EndSearch(method.Method):
def execute(self, w, **vargs):
old_w = w.buffer.method.old_window
old_c = w.buffer.method.old_cursor
_end(w)
old_w.set_mark_point(old_c)
w.set_error("Mark set to search start")
class CancelSearch(method.Method):
def execute(self, w, **vargs):
w.buffer.method.old_window.goto(w.buffer.method.old_cursor)
_end(w)
w.set_error("Search cancelled")
class SearchDeleteLeft(method.Method):
def execute(self, w, **vargs):
w.left_delete()
_post_delete(w)
class SearchDeleteLeftWord(method.Method):
def execute(self, w, **vargs):
w.kill_left_word()
_post_delete(w)
def _post_delete(w):
old_cursor = w.buffer.method.old_cursor
old_w = w.buffer.method.old_window
old_w.goto(old_cursor)
if not w.buffer.make_string():
w.application.clear_highlighted_ranges()
elif w.buffer.method.direction == 'next':
_find_next(old_w, w, move=False)
else:
_find_previous(old_w, w, move=False)
class InsertSearchString(method.Method):
def __init__(self, s):
self.name = 'insert-search-string-%s' % (s)
self.string = s
self.args = []
self.help = None
def execute(self, w, **vargs):
w.insert_string_at_cursor(self.string)
s = w.buffer.make_string()
if not s:
return
else:
old_w = w.buffer.method.old_window
if w.buffer.method.direction == 'next':
_find_next(old_w, w, move=False)
else:
_find_previous(old_w, w, move=False)
def _end(w):
w.application.close_mini_buffer()
w.application.clear_highlighted_ranges()
w.application.last_search = w.buffer.make_string()
w.buffer.method.old_cursor = None
w.buffer.method.old_window = None
def _find_ranges(w, s):
(x, y) = (0, 0)
ranges = []
while y < len(w.buffer.lines):
while x < len(w.buffer.lines[y]):
try:
i = w.buffer.lines[y].index(s, x)
x = i + len(s)
ranges.append([Point(i, y), Point(x, y), 'black', 'white'])
except ValueError:
break
x = 0
y += 1
return ranges
def _find(old_w, new_w, move=False, direction='next'):
# DOESN'T WORK WELL FOR NEXT
app = old_w.application
s = new_w.buffer.make_string()
c = old_w.logical_cursor()
(x, y) = c.xy()
newc = None
ranges = _find_ranges(old_w, s)
indices = range(0, len(ranges))
if direction == 'next':
if move:
limit = Point(x, y)
else:
limit = Point(x - 1, y)
else:
if move:
limit = Point(x + len(s), y)
else:
limit = Point(x + len(s) + 1, y)
indices.reverse()
for i in indices:
if (direction == 'next' and ranges[i][0] > limit) or ranges[i][1] < limit:
ranges[i][3] = 'magenta'
newc = ranges[i][0]
break
if ranges and not newc:
return
app.clear_highlighted_ranges()
if newc:
old_w.goto(newc)
for (p1, p2, fg, bg) in ranges:
if p1 < old_w.first:
continue
elif p2 > old_w.last:
break
app.add_highlighted_range(old_w, p1, p2, fg, bg)
def _find_previous(old_w, new_w, move=False):
return _find(old_w, new_w, move, 'previous')
app = old_w.application
s = new_w.buffer.make_string()
c = old_w.logical_cursor()
(x, y) = c.xy()
if move:
x -= 1
limit = Point(x + len(s) + 1, y)
newc = None
ranges = _find_ranges(old_w, s)
l = len(ranges) - 1
for i in range(0, len(ranges)):
if ranges[l - i][1] < limit:
ranges[l - i][3] = 'magenta'
newc = ranges[l - i][0]
break
if ranges and not newc:
return
app.clear_highlighted_ranges()
if newc:
old_w.goto(newc)
for (p1, p2, fg, bg) in ranges:
if p1 < old_w.first:
continue
elif p2 > old_w.last:
break
app.add_highlighted_range(old_w, p1, p2, fg, bg)
def _find_next(old_w, new_w, move=False):
#return _find(old_w, new_w, move, 'next') # in time
app = old_w.application
s = new_w.buffer.make_string()
c = old_w.logical_cursor()
(x, y) = c.xy()
if move:
x += 1
limit = Point(x - 1, y)
newc = None
ranges = _find_ranges(old_w, s)
l = len(ranges) - 1
for i in range(0, len(ranges)):
if ranges[i][0] > limit:
ranges[i][3] = 'magenta'
newc = ranges[i][0]
break
if ranges and not newc:
return
app.clear_highlighted_ranges()
if newc:
old_w.goto(newc)
for (p1, p2, fg, bg) in ranges:
if p1 < old_w.first:
continue
elif p2 > old_w.last:
break
app.add_highlighted_range(old_w, p1, p2, fg, bg)