import re from method import Method from mode import Fundamental import minibuffer, searchutil subgroup_re = re.compile(r'((?:\\\\)*)\\(0|[1-9][0-9]*)') class ReplaceOne(Method): 'In a replace command, replace the next occurance' def execute(self, w, **vargs): m = w.buffer.method _replace(m) _find_next(m, False) _finish(m, w) class ReplaceDone(Method): 'In a replace command, replace the next occurance and exit' def execute(self, w, **vargs): m = w.buffer.method _replace(m) _end(w) w.set_error("Replace done") class SkipReplace(Method): 'In a replace command, skip the next occurance' def execute(self, w, **vargs): m = w.buffer.method _find_next(m, True) _finish(m, w) class ReplaceAll(Method): 'In a replace command, replace all remaining occurances' # FIXME: this is super slow def execute(self, w, **vargs): m = w.buffer.method while m.p1 is not None: _replace(m) _find_next(m, False) _end(w) w.set_error("Replace ended") class CancelReplace(Method): 'Cancel a currently running replace command' def execute(self, w, **vargs): _end(w) w.set_error("Replace cancelled") def _find_next(m, move=False): s = m.before w = m.old_window c = w.logical_cursor() try: if m.is_literal: r = re.compile(searchutil.escape_literal(s)) else: r = re.compile(s) except: (m.p1, m.p2) = (None, None) return False if move: newc = searchutil.find_next(r, w, False, start=c.add(1, 0)) else: newc = searchutil.find_next(r, w, False, start=c.add(0, 0)) if newc: (m.p1, m.p2, m.match) = newc return True else: (m.p1, m.p2, m.match) = (None, None, None) return False def _get_before(m): if m.match is None: return m.before else: return m.match.group(0) def _get_after(m): if m.after is None: return None elif m.match is None: return m.after def _repl(match): (pre, num) = (match.group(1), int(match.group(2))) if num == 0 or m.match.lastindex and num <= m.match.lastindex: return pre + m.match.group(num) else: return match.group(0) return subgroup_re.sub(_repl, m.after) def _set_prompt(m): w = m.old_window if m.p1 is None: #w.application.mini_prompt = '%r was not found' % m.before w.application.mini_prompt = '[%r] %r was not found' % (m.p1, m.before) return (x, y) = m.p1.xy() count = 0 while y < len(w.buffer.lines): count += w.buffer.lines[y][x:].count(m.before) y += 1 x = 0 after = _get_after(m) before = _get_before(m) if count > 1: p = 'Replace %r with %r [ynadq] (%d occurances)?' % (before, after, count) elif count == 1: p = 'Replace %r with %r [ynadq] (1 occurance)?' % (before, after) elif count == 0: p = 'Replace %r with %r [ynadq] (0 occurances)?' % (before, after) #raise Exception("this can't happen") else: raise Exception("this REALLY can't happen") w.application.mini_prompt = p def _replace(m): m.old_window.buffer.delete(m.p1, m.p2) if m.after: after = _get_after(m) m.old_window.buffer.insert_string(m.p1, after) def _finish(m, w): if m.p1 is None: _end(w) w.set_error("Replace ended") else: _set_prompt(m) def _end(w): w.application.close_mini_buffer() w.application.clear_highlighted_ranges('search') w.buffer.method.old_cursor = None w.buffer.method.old_window = None assert not w.application.mini_active class Replace(Fundamental): name = 'Replace' actions = [ReplaceAll, ReplaceDone, ReplaceOne, SkipReplace, CancelReplace] def __init__(self, w): Fundamental.__init__(self, w) self.actions = {} self.bindings = {} self.add_bindings('replace-all', ('a', '!',)) self.add_bindings('replace-done', ('d',)) self.add_bindings('replace-one', ('y', 'SPACE',)) self.add_bindings('skip-replace', ('n', 'DELETE',)) self.add_bindings('cancel-replace', ('q', 'RETURN', 'C-]', 'C-n', 'C-p', 'C-a', 'C-e', 'C-f', 'C-b', 'C-g')) m = w.buffer.method found = _find_next(m, False) if not found: w.set_error('%r was not found' % m.before) raise minibuffer.MiniBufferError _set_prompt(m) install = Replace.install