diff --git a/application.py b/application.py index 97e8574..0226d39 100755 --- a/application.py +++ b/application.py @@ -655,10 +655,10 @@ class Application(object): perc = "%2d%%" % (first.y*100 / len(b.lines)) # XYZ: we should actually use more of the 'state' variables - #format = "%s %-18s (%s)--L%d--C%d--%s" - #status = format % (modflag, name, w.mode.name(), cursor.y+1, cursor.x+1, perc) - format = "%s %-18s (%s)--L%d--C%d--%s %s %s %s" - status = format % (modflag, name, w.mode.name(), cursor.y+1, cursor.x+1, perc, w.first, cursor, w.last) + format = "%s %-18s (%s)--L%d--C%d--%s" + status = format % (modflag, name, w.mode.name(), cursor.y+1, cursor.x+1, perc) + #format = "%s %-18s (%s)--L%d--C%d--%s %s %s %s" + #status = format % (modflag, name, w.mode.name(), cursor.y+1, cursor.x+1, perc, w.first, cursor, w.last) status = status[:slot.width + 1] status += "-" * (slot.width - len(status) + 1) diff --git a/mode_python.py b/mode_python.py index a338fa2..078213c 100644 --- a/mode_python.py +++ b/mode_python.py @@ -81,7 +81,6 @@ class PythonTabber(tab2.StackTabber): # if we were continuing, let's pop that previous continuation token # and note that we're continuing if self.markers and self.markers[-1].name == 'cont': - raise Exception, repr(self.markers) self.continued = True self._pop() # if we haven't reached the target-line yet, we can detect how many diff --git a/mode_replace.py b/mode_replace.py index 1a13a72..bf113eb 100644 --- a/mode_replace.py +++ b/mode_replace.py @@ -1,6 +1,6 @@ import sets, string -import color, method, minibuffer, mode2 +import color, method, minibuffer, mode2, search from point2 import Point class Replace(mode2.Fundamental): @@ -11,51 +11,39 @@ class Replace(mode2.Fundamental): self.actions = {} self.bindings = {} - default_actions = ( - (ReplaceAll(), ('a', '!',)), - (ReplaceOne(), ('y', 'SPACE',)), - (SkipReplace(), ('n', 'DELETE',)), - (CancelReplace(), ('q', 'RETURN', 'C-]', 'C-n', 'C-p', 'C-a', 'C-e', - 'C-f', 'C-b')), - ) - - # add the replace actions - for pair in default_actions: - (action, sequences) = pair - assert type(sequences) == type(()), repr(pair) - self.add_action_and_bindings(action, sequences) + self.add_action_and_bindings(ReplaceAll(), ('a', '!',)) + self.add_action_and_bindings(ReplaceOne(), ('y', 'SPACE',)) + self.add_action_and_bindings(SkipReplace(), ('n', 'DELETE',)) + self.add_action_and_bindings(CancelReplace(), ('q', 'RETURN', 'C-]', 'C-n', 'C-p', 'C-a', 'C-e', 'C-f', 'C-b')) - _find_next(w, False) - if w.buffer.method.p1 is None: - w.application.set_error('%r was not found') + m = w.buffer.method + found = _find_next(m, move=False) + if not found: + w.application.set_error('%r was not found' % m.before) raise minibuffer.MiniBufferError - _set_prompt(w.buffer.method, w.buffer.method.old_window) - + _set_prompt(m) def name(self): return "Replace" class ReplaceOne(method.Method): def execute(self, w, **vargs): m = w.buffer.method - old_window = m.old_window - _replace(m, old_window) - _find_next(w, True) - _finish(m, w, old_window) + _replace(m) + _find_next(m, True) + _finish(m, w) class SkipReplace(method.Method): def execute(self, w, **vargs): m = w.buffer.method - old_window = m.old_window - _find_next(w, True) - _finish(m, w, old_window) + _find_next(m, True) + _finish(m, w) class ReplaceAll(method.Method): def execute(self, w, **vargs): m = w.buffer.method - old_window = m.old_window while m.p1 is not None: - _replace(m, old_window) - _find_next(w, True) + _replace(m) + _find_next(m, True) _end(w) w.application.set_error("Replace ended") @@ -64,7 +52,19 @@ class CancelReplace(method.Method): _end(w) w.application.set_error("Replace cancelled") -def _set_prompt(m, w): +def _find_next(m, move=False): + s = m.before + w = m.old_window + newc = search._find_next(s, w, move) + if newc: + (m.p1, m.p2) = newc + return True + else: + (m.p1, m.p2) = (None, None) + return False + +def _set_prompt(m): + w = m.old_window if m.p1 is None: w.application.mini_prompt = '%r was not found' % m.before return @@ -80,54 +80,17 @@ def _set_prompt(m, w): p = 'Replace %r with %r [ynaq] (1 occurance)?' % (m.before, m.after) w.application.mini_prompt = p -def _replace(m, old_window): - old_window.buffer.delete(m.p1, m.p2) +def _replace(m): + m.old_window.buffer.delete(m.p1, m.p2) if m.after: - old_window.buffer.insert_string(m.p1, m.after) + m.old_window.buffer.insert_string(m.p1, m.after) -def _find_next(w, move=False): - m = w.buffer.method - old_window = m.old_window - b = old_window.buffer - s = m.before - c = old_window.logical_cursor() - (x, y) = (c.x, c.y) - - if move: - x += 1 - l = b.lines[y][x:] - - # for each line available - while y < len(b.lines): - if s in l: - # success - x = x + l.index(s) - x2 = x + len(s) - m.p1 = Point(x, y) - m.p2 = Point(x2, y) - old_window.goto(m.p1) - old_window.application.clear_highlighted_ranges() - old_window.application.add_highlighted_range(old_window, m.p1, m.p2) - #old_window.application.highlighted_range = [old_window, m.p1, m.p2] - _set_prompt(m, old_window) - return - elif y >= len(b.lines) - 1: - # failure - break - else: - # keep trying - y += 1 - l = b.lines[y] - x = 0 - m.p1 = None - m.p2 = None - -def _finish(m, w, old_window): +def _finish(m, w): if m.p1 is None: _end(w) w.application.set_error("Replace ended") else: - _set_prompt(m, old_window) + _set_prompt(m) def _end(w): w.application.close_mini_buffer() diff --git a/mode_search.py b/mode_search.py index 4f170d0..775a7db 100644 --- a/mode_search.py +++ b/mode_search.py @@ -1,8 +1,11 @@ import sets, string -import color, method, minibuffer, mode2 +import color, method, minibuffer, mode2, search from point2 import Point +selected_color = 'magenta' +unselected_color = 'yellow' + class Search(mode2.Fundamental): '''This is the default mode''' def __init__(self, w): @@ -35,8 +38,9 @@ class SearchNext(method.Method): 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) + s = w.buffer.make_string() + w2 = w.buffer.method.old_window + search.find_next(s, w2, move=True) class SearchPrevious(method.Method): def execute(self, w, **vargs): @@ -44,8 +48,9 @@ class SearchPrevious(method.Method): if not w.buffer.make_string(): return else: - old_w = w.buffer.method.old_window - _find_previous(old_w, w, move=True) + s = w.buffer.make_string() + w2 = w.buffer.method.old_window + search.find_previous(s, w2, move=True) class EndSearch(method.Method): def execute(self, w, **vargs): @@ -75,10 +80,13 @@ def _post_delete(w): 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) + return + s = w.buffer.make_string() + w2 = w.buffer.method.old_window + if w.buffer.method.direction == 'next': + search.find_next(s, w2, move=False) else: - _find_previous(old_w, w, move=False) + search.find_previous(s, w2, move=False) class InsertSearchString(method.Method): def __init__(self, s): @@ -92,11 +100,12 @@ class InsertSearchString(method.Method): if not s: return else: - old_w = w.buffer.method.old_window + s = w.buffer.make_string() + w2 = w.buffer.method.old_window if w.buffer.method.direction == 'next': - _find_next(old_w, w, move=False) + search.find_next(s, w2, move=False) else: - _find_previous(old_w, w, move=False) + search.find_previous(s, w2, move=False) def _end(w): w.application.close_mini_buffer() @@ -104,113 +113,3 @@ def _end(w): 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) diff --git a/point2.py b/point2.py index c97c7b3..18e48a2 100644 --- a/point2.py +++ b/point2.py @@ -1,4 +1,5 @@ class Point(tuple): + '''Represents an (x,y) coordinate''' def __new__(cls, x, y): return tuple.__new__(cls, (y, x)) def __getattr__(self, name): @@ -14,13 +15,18 @@ class Point(tuple): return '(%d,%d)' % (self[1], self[0]) def xy(self): + '''Returns a tuple (x,y)''' return (self[1], self[0]) - def add(self, x, y): - assert x >= 0, y >= 0 - return Point(self[1] + x, self[0] + y) - def vadd(self, x, y): - assert x >= 0, y >= 0 - if y > 0: - return Point(x, self[0] + y) + def yx(self): + '''Returns a tuple (x,y)''' + return tuple(self) + def add(self, xdelta, ydelta): + '''Returns a new point, applying xdelta and ydelta''' + return Point(self[1] + xdelta, self[0] + ydelta) + def vadd(self, xdelta, ydelta): + '''Returns a new point. If ydelta > 0, xdelta is absolute; otherwise, xdelta is relative''' + assert xdelta >= 0 and ydelta >= 0, str((xdelta, ydelta)) + if ydelta != 0: + return Point(xdelta, self[0] + ydelta) else: - return Point(self[1] + x, self[0]) + return Point(self[1] + xdelta, self[0]) diff --git a/search.py b/search.py new file mode 100644 index 0000000..3c0c354 --- /dev/null +++ b/search.py @@ -0,0 +1,63 @@ +from point2 import Point + +bg_color = 'black' +selected_color = 'magenta' +unselected_color = 'yellow' + +def find_ranges(s, w): + (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), bg_color, unselected_color]) + except ValueError: + break + x = 0 + y += 1 + return ranges + +def find(s, w, move=False, direction='next'): + app = w.application + c = w.logical_cursor() + newc = None + ranges = find_ranges(s, w) + indices = range(0, len(ranges)) + (x, y) = c.xy() + 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 + (direction != 'next' and ranges[i][1] < limit)): + ranges[i][3] = selected_color + newc = (ranges[i][0], ranges[i][1]) + break + if ranges and not newc: + return None + app.clear_highlighted_ranges() + if newc: + w.goto(newc[0]) + for (p1, p2, fg, bg) in ranges: + if p1 < w.first: + continue + elif p2 > w.last: + break + app.add_highlighted_range(w, p1, p2, fg, bg) + return newc + +def find_previous(s, w, move=False): + return find(s, w, move, 'previous') + +def find_next(s, w, move=False): + return find(s, w, move, 'next') diff --git a/window2.py b/window2.py index 37e317c..220ff91 100644 --- a/window2.py +++ b/window2.py @@ -3,7 +3,6 @@ import regex from point2 import Point WORD_LETTERS = list(string.letters + string.digits) -#WORD_LETTERS = string.letters + string.digits + "_" # note about the cursor: the cursor position will insert in front of the # character it highlights. to this end, it needs to be able to highlight behind @@ -350,6 +349,9 @@ class Window(object): else: x += self.width counter += 1 + if y == len(self.buffer.lines): + y -= 1 + x = len(self.buffer.lines[y]) return Point(orig_x, y) def page_up(self): first_point = self.buffer.get_buffer_start() @@ -418,8 +420,10 @@ class Window(object): (x, y) = (0, 0) break counter += 1 - self.first = Point(x - (x % self.width), y) - self.redraw() + + if not self.cursor_is_visible(): + self.first = Point(x - (x % self.width), y) + self.redraw() # mark manipulation def set_mark_point(self, p):