diff --git a/highlight.py b/highlight.py deleted file mode 100644 index e53c85b..0000000 --- a/highlight.py +++ /dev/null @@ -1,429 +0,0 @@ -import point - -# to be clear: - -# tokens are generated by the lexer from the buffer, and correspond to lexical -# information about a logical portion of the buffer. -# regions are derived from a combination of the lexical tokens (which correspond -# to the logical buffer) and the physical line endings (i.e. dependent on screen -# width, etc.) -class Highlighter: - '''class used by modes to manage syntax highlighting''' - def __init__(self, m): - self.mode = m - self.tokens = None - self.regions = None - - def invalidate_tokens(self): - self.tokens = None - self.invalidate_regions() - - def invalidate_regions(self): - self.regions = None - - def invalidate_token_range(self, start_offset, end_offset, m, n, diff): - # fix all the tokens to update their offsets, and clean out - # a token which spans the change - offset = start_offset - i = 0 - last_index_before = None - first_index_after = None - while i < len(self.tokens): - t = self.tokens[i] - t.debug = False - if t.end <= start_offset: - last_index_before = i - i += 1 - elif t.start >= end_offset: - if first_index_after is None: - first_index_after = i - t.start += diff - t.end += diff - i += 1 - else: - if offset == start_offset: - offset = self.tokens[i].start - del self.tokens[i] - - # delete m tokens further forward - for i in range(0, m): - if first_index_after is None: - break - elif first_index_after > len(self.tokens): - del self.tokens[first_index_after] - elif first_index_after == len(self.tokens): - del self.tokens[first_index_after] - first_index_after = None - - # delete n tokens further back - for i in range(0, n): - if last_index_before is None: - break - elif last_index_before > 0: - del self.tokens[last_index_before] - last_index_before -= 1 - elif last_index_before == 0: - del self.tokens[0] - last_index_before = None - break - - return (last_index_before, first_index_after) - - def reparse_region(self, last_index_before, first_index_after): - i = last_index_before - if i is None: - i = 0 - tokens_before = False - start_offset = 0 - else: - tokens_before = True - start_offset = self.tokens[i].start - - j = first_index_after - if j is None or j >= len(self.tokens): - j = -1 - tokens_after = False - end_offset = None - else: - tokens_after = True - end_offset = self.tokens[j].end - - # FIXME - # new things the strategy should do include: - # 1. not generating the huge "data" string - # 2. really generating the "roll-back" with - # data not just by rolling back the index - # of the lexer - # 3. pass in only as much data as you need - # to do the minimal check, and for the - # "after the change" checking, use append - # to strategically keep the string 1-2 - # tokens ahead of where it needs to be - #data = self.mode.window.buffer.make_string() - #self.mode.lexer.lex(data, start_offset) - if self.tokens: - buf_index = max(self.tokens[i].start - 100, 0) - else: - buf_index = 0 - if end_offset is None: - data = self.mode.window.buffer.make_string(start=buf_index, end=None) - else: - data = self.mode.window.buffer.make_string(start=buf_index, - end=end_offset + 100) - self.mode.lexer.lex(data, start_offset - buf_index, buf_index) - saved_t = False - - while True: - if saved_t is True: - # we want to retry t agagin - saved_t = False - else: - try: - t = self.mode.lexer.next() - if t is None: - continue - except: - # we have no more tokens, so delete whatever was left and - # then return - if i < len(self.tokens): - del self.tokens[i:] - self.mode.lexer.lex() - return - - if i >= len(self.tokens): - # we don't have any old tokens this far out, so just keep - t.debug = True - self.tokens.append(t) - i += 1 - elif t.end <= self.tokens[i].start: - # we shouldn't get here if we are before the change - assert not tokens_before - # the token is before our tokens, so we can just add it - t.debug = True - self.tokens.insert(i, t) - i += 1 - elif t.start == self.tokens[i].start and \ - t.end == self.tokens[i].end and \ - t.name == self.tokens[i].name: - # the token is identical to ours, so we can either - # stop if we are after the change, or confirm the - # start point if we are before - if tokens_before: - tokens_before = False - i += 1 - else: - self.tokens[i].debug = True - self.mode.lexer.lex() - return - else: - if i < len(self.tokens): - del self.tokens[i] - if tokens_before and i < 0: - raise Exception, "oh no!" - # we need to keep sliding our window back - i -= 1 - start_offset = self.tokens[i].start - self.mode.lexer.lex(data, start_offset) - elif tokens_before: - # ok, now we aren't sliding our window back - # and can proceed normally - tokens_before = False - saved_t = True - else: - # the new token conflicts with the old one, so delete - # the old one and try again - saved_t = True - - raise Exception, "we should never get here (dolphin 2)" - - def _region_changed_slow(self): - self.invalidate_tokens() - self.get_regions() - return - - def _region_added_dumb(self, p, xdiff, ydiff, s): - self.invalidate_regions() - - # calculate the start and end offsets of the change, and the - # difference to the length of the whole data string - start_offset = self.mode.window.buffer.get_point_offset(p) - end_offset = start_offset - assert (xdiff > 0 and ydiff >= 0) or ydiff > 0 - - if ydiff > 0: - p2 = point.Point(p.x + xdiff, p.y + ydiff) - elif ydiff == 0: - p2 = point.Point(p.x + xdiff, p.y) - new_offset = self.mode.window.buffer.get_point_offset(p2) - diff = new_offset - start_offset - assert diff > 0 - - # move the tokens start and end points so that the additions - # (while not being correct) won't break the existing - # highlighting - for t in self.tokens: - t.debug = False - if t.end <= start_offset: - pass - elif t.start >= end_offset: - t.start += diff - t.end += diff - else: - t.end += diff - - def _region_added_complex(self, p, xdiff, ydiff, s): - self.invalidate_regions() - - # calculate the start and end offsets of the change, and the - # difference to the length of the whole data string - start_offset = self.mode.window.buffer.get_point_offset(p) - end_offset = start_offset - assert ydiff >= 0 - if ydiff > 0: - p2 = point.Point(p.x + xdiff, p.y + ydiff) - elif ydiff == 0: - p2 = point.Point(p.x + xdiff, p.y) - new_offset = self.mode.window.buffer.get_point_offset(p2) - diff = new_offset - start_offset - - (i, j) = self.invalidate_token_range(start_offset, end_offset, 1, 1, diff) - #(i, j) = self.invalidate_token_range(start_offset, end_offset, 1, 2, diff) - self.reparse_region(i, j) - - def region_added(self, p, xdiff, ydiff, s): - if s == ' ' or s == ' ': - self._region_added_dumb(p, xdiff, ydiff, s) - else: - self._region_added_complex(p, xdiff, ydiff, s) - - def _region_removed_dumb(self, p1, p2, s): - self.invalidate_regions() - - # calculate the start and end offsets of the change, and the - # difference to the length of the whole data string - #diff = r - diff = len(s) - start_offset = self.mode.window.buffer.get_point_offset(p1) - end_offset = start_offset + diff - - # move the tokens start and end points so that the additions - # (while not being correct) won't break the existing - # highlighting - i = 0 - while i < len(self.tokens): - t = self.tokens[i] - t.debug = False - - # if our token contains a trailing newline, certain - # deletions may not match unless we pretend that the end - # is one character earlier - if t.string.endswith('\n'): - t_end = t.end - 1 - else: - t_end = t.end - - if t_end <= start_offset: - pass - elif t.start >= start_offset and t_end <= end_offset: - del self.tokens[i] - continue - elif t_end >= start_offset and t_end <= end_offset: - t.end = start_offset - elif t.start >= start_offset and t.start <= end_offset: - t.start = end_offset - else: - t.start -= diff - t.end -= diff - if t.start == t.end: - del self.tokens[i] - continue - else: - assert t.start < t.end - i += 1 - - def _region_removed_complex(self, p1, p2, s): - self.invalidate_regions() - - # calculate the start and end offsets of the change, and the - # difference to the length of the whole data string - diff = len(s) - start_offset = self.mode.window.buffer.get_point_offset(p1) - end_offset = start_offset + diff - - (i, j) = self.invalidate_token_range(start_offset, end_offset, 1, 1, -diff) - #(i, j) = self.invalidate_token_range(start_offset, end_offset, 1, 2, -diff) - self.reparse_region(i, j) - - def region_removed(self, p1, p2, s): - self._region_removed_complex(p1, p2, s) - - def get_tokens(self): - if self.tokens is None: - self.lex_buffer() - return self.tokens - - def lex_buffer(self): - '''lexes the buffer according to the grammar''' - if (not hasattr(self.mode, "grammar") or self.mode.grammar is None or - not hasattr(self.mode, "lexer") or self.mode.lexer is None): - self.tokens = [] - return - - self.mode.lexer.lex(self.mode.window.buffer.make_string()) - - self.tokens = [] - for token in self.mode.lexer: - if token is not None: - self.tokens.append(token) - - def get_regions(self): - def endloop(line, pindex, plines): - '''helper method for get_regions''' - self.regions.append([]) - o = offset + len(line) + 1 - if (pindex < len(plines) and - self.mode.window._physical_lines_cont[pindex]): - # in this case we don't skip the newline - o -= 1 - p = pindex + 1 - return o, p - - self.get_tokens() - - if self.regions is None: - plines = self.mode.window.get_physical_lines() - - tindex = 0 # token index - offset = 0 # string offset - pindex = 0 # physical index - - self.regions = [[]] - - # looping over the physical lines - while pindex < len(plines): - last = 0 - line = plines[pindex] - - # figure out if we have a current token, and if so, which one - if tindex < len(self.tokens): - t = self.tokens[tindex] - else: - t = None - - # if the current line doesn't contain a token, then - # make a default color token for that line and - # continue - if type(t) == type(""): - raise Exception, repr(t) - if t is None or t.start >= offset + len(line): - r = Region(0, len(line), self.mode.default_color, line, '', None) - self.regions[-1].append(r) - offset, pindex = endloop(line, pindex, plines) - continue - - # looping over the tokens on a physical line - while t is not None and t.start < offset + len(line): - if t.start > offset + last: - assert last <= t.start - offset, \ - "iegjeigje (%d <= %d)" % (last, t.start - offset) - # there is uncolored space before/between the token(s) - r = Region(last, t.start - offset, - self.mode.default_color, - line[last:t.start - offset], '', None) - self.regions[-1].append(r) - last = t.start - offset - - color = self.mode.colors.get(t.name, self.mode.default_color) - if t.debug: - # this is useful for seeing which places get relexed - #color = self.mode.colors.get('bizzaro', self.mode.default_color) - pass - - # in the case of a multiline token, looping over - # the lines it spans and incrementing as in the upper - # loop... - while t.end > offset + len(line): - assert last <= len(line), \ - "jjjjccccc (%d <= %d)" % (last, len(line)) - r = Region(last, len(line), color, line[last:], t.name, t) - self.regions[-1].append(r) - last = 0 - offset, pindex = endloop(line, pindex, plines) - if pindex >= len(plines): - # huh??? - raise Exception, "fuck me" - return self.regions - else: - line = plines[pindex] - - assert last <= t.end - offset, \ - "bbjjgjg (%d <= %d - %d)" % (last, t.end, offset) - r = Region(last, t.end - offset, color, line[last:t.end-offset], t.name, t) - self.regions[-1].append(r) - last = t.end - offset - - tindex += 1 - if tindex < len(self.tokens): - t = self.tokens[tindex] - else: - t = None - - last = self.regions[-1][-1][1] - offset, pindex = endloop(line, pindex, plines) - - return self.regions - -class Region: - index_to_attr = ['start', 'end', 'attr', 'value', 'name'] - def __init__(self, start, end, attr, value, name, token=None): - self.start = start - self.end = end - self.attr = attr - self.value = value - self.name = name - self.token = token - def __getitem__(self, i): - return getattr(self, self.index_to_attr[i]) - def __repr__(self): - return '' % (self.start, self.end, self.attr, - self.value, self.name) \ No newline at end of file diff --git a/window.py b/window.py deleted file mode 100644 index f562b40..0000000 --- a/window.py +++ /dev/null @@ -1,569 +0,0 @@ -import os.path, string - -import buffer, point, regex - -WORD_LETTERS = list(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 the last character on a line. thus, the x -# coordinate of the (logical) cursor can equal the length of lines[y], -# even though lines[y][x] throws an index error. both buffer and -# window need to be aware of this possibility for points. - -class Window(object): - def __init__(self, b, a, height=24, width=80, slot='main', mode_name=None): - self.buffer = b - self.application = a - self.buffer.add_window(self, slot) - - self.first = point.Point(0, 0, "logical") - self.last = point.Point(0, 0, "logical") - self.cursor = point.Point(0, 0, "logical") - self.mark = None - self.active_point = None - - #self.physical_movement = False - - self.height = height - self.width = width - - self._logical_offsets = None - self._physical_lines = None - self._physical_lines_cont = None - - self.input_line = "" - - if mode_name is not None: - pass - elif hasattr(self.buffer, 'modename') and self.buffer.modename is not None: - mode_name = self.buffer.modename - elif self.buffer.name() == "*Minibuffer*": - mode_name = 'mini' - elif self.buffer.name() == "*Console*": - #mode_name = "console" - mode_name = "fundamental" - elif hasattr(self.buffer, 'path'): - path = self.buffer.path - basename = os.path.basename(path) - #ext = os.path.splitext(path)[1].lower() - ext = self._get_path_ext(path) - if path in self.application.mode_paths: - mode_name = self.application.mode_paths[path] - elif basename in self.application.mode_basenames: - mode_name = self.application.mode_basenames[basename] - elif ext in self.application.mode_extensions: - mode_name = self.application.mode_extensions[ext] - elif len(self.buffer.lines) > 0 and \ - self.buffer.lines[0].startswith('#!'): - line = self.buffer.lines[0] - for word in self.application.mode_detection: - if word in line: - mode_name = self.application.mode_detection[word] - - if mode_name is None: - mode_name = "fundamental" - - m = self.application.modes[mode_name](self) - self.set_mode(m) - - def _get_path_ext(self, path): - name = os.path.basename(path).lower() - tokens = name.split('.') - if len(tokens) > 2 and tokens[-1] in ('gz', 'in', 'zip'): - return '.%s.%s' % (tokens[-2], tokens[-1]) - else: - return os.path.splitext(path)[1].lower() - - def set_mode(self, m): - self.mode = m - self.redraw() - - def get_cursor_offset(self): - cursor = self.logical_cursor() - return self.buffer.get_point_offset(cursor) - - # the message is printed when the point is not visible, and the proper - # variable is set - def set_active_point(self, p, use_msg_when_hidden=True, - msg='marking on line %(y)d, character %(x)d'): - self.active_point = p - if not self.point_is_visible(p): - self.application.set_error(msg % {'x': p.x, 'y': p.y}) - - # cursors - # - # there are three: - # the actual cursor (not good for most things) - # the logical cursor (good for logical actions on buffer) - # the physical cursor (good for drawing) - def logical_cursor(self): - y = self.cursor.y - if self.cursor.x <= len(self.buffer.lines[y]): - return self.cursor - else: - return point.Point(len(self.buffer.lines[y]), y, "logical") - def logical_point(self, p): - self.get_physical_lines() - x = 0 - y = 0 - for i in range(0, p.y): - if self._physical_lines_cont[i]: - x += self.width - else: - x = 0 - y += 1 - x += p.x - return point.Point(x, y, "logical") - def physical_cursor(self): - p = self.logical_cursor() - #return self.physical_point(p) - self.get_physical_lines() - y = 0 - for i in self._logical_offsets[0:p.y]: - y += i - y += p.x / self.width - x = p.x % self.width - # this allows the cursor to be in the right margin, rather than on the - # next line... i.e. not the behavior you want for actual text. - if p.x == len(self.buffer.lines[p.y]) and y > 0 and p.x > 0 and x == 0: - #if y > 0 and p.x > 0 and x == 0: - x = self.width - y -= 1 - return point.Point(x, y, "physical") - def physical_point(self, p): - self.get_physical_lines() - y = 0 - for i in self._logical_offsets[0:p.y]: - y += i - y += p.x / self.width - x = p.x % self.width - return point.Point(x, y, "physical") - - # debug - def get_debug_repr(self): - return "" - - def get_physical_lines(self): - if self._physical_lines is None: - self._physical_lines = [] - self._physical_lines_cont = [] - self._logical_offsets = [] - for l in self.buffer.lines: - pl = [] - while len(l) > self.width: - pl.append(l[:self.width]) - l = l[self.width:] - pl.append(l) - self._logical_offsets.append(len(pl)) - self._physical_lines.extend(pl) - for i in range(0, len(pl)-1): - self._physical_lines_cont.append(True) - self._physical_lines_cont.append(False) - return self._physical_lines - - # redrawing - def set_size(self, width, height): - self.width = width - self.height = height - self.redraw() - self._invalidate_physical_lines() - self.mode.invalidate() - def _invalidate_physical_lines(self): - self._physical_lines = None - - def _region_added(self, p, xdiff, ydiff, str=None): - cursor = self.logical_cursor() - self._invalidate_physical_lines() - if cursor.y > p.y: - self.cursor = cursor.offset(0, ydiff) - elif self.cursor >= p: - self.cursor = cursor.offset(xdiff, ydiff) - else: - pass - self.redraw() # added 2006-5-28 - if not self.cursor_is_visible(): - self.center_view() - self.mode.region_added(p, xdiff, ydiff, str) - - def _region_removed(self, p1, p2, str): - pdelta = p1 - p2 - xdiff, ydiff = pdelta.x, pdelta.y - self._invalidate_physical_lines() - if self.cursor.y > p2.y: - self.cursor = self.cursor.offset(0, ydiff) - elif self.cursor > p2: - self.cursor = self.cursor.offset(xdiff, ydiff) - elif self.cursor >= p1: - self.cursor = p1.offset(0, 0) - else: - pass - if not self.cursor_is_visible(): - self.center_view() - self.mode.region_removed(p1, p2, str) - - def visible_offset(self): - pfirst = self.physical_point(self.first) - return pfirst.y - def visible_cursor(self): - i = self.visible_offset() - return self.physical_cursor().offset(0, -i) - def visible_lines(self): - i = self.visible_offset() - lines = self.get_physical_lines() - return lines[i:i+self.height] - def continued_visible_line(self, i): - return self._physical_lines_cont[i + self.visible_offset()] - def redraw(self): - plines = self.get_physical_lines() - pfirst = self.physical_point(self.first) - py = min(pfirst.y + self.height - 1, len(plines) - 1) - px = min(self.width, len(plines[py])) - plast = point.Point(px, py, "physical") - self.last = self.logical_point(plast) - if self.last < self.first: - raise Exception, "BUGGJGJG:\n%s" % (self.dump()) - self._validate_first_last() - def point_is_visible(self, p): - return self.first <= p and p <= self.last - def cursor_is_visible(self): - cursor = self.logical_cursor() - return self.point_is_visible(cursor) - def first_is_visible(self): - first_point = self.buffer.get_buffer_start() - return self.point_is_visible(first_point) - def last_is_visible(self): - last_point = self.buffer.get_buffer_end() - return self.point_is_visible(last_point) - - def center_view(self): - pcursor = self.physical_cursor() - x = 0 - if self.height == 1: - # we special case this to avoid rounding problems - y = max(0, pcursor.y) - else: - offset = self.height - (self.height / 2) - y = max(0, pcursor.y - offset) - pfirst = point.Point(x, y, "physical") - self.first = self.logical_point(pfirst) - self.redraw() - def relocate_cursor(self): - if not self.cursor_is_visible(): - i = self.visible_offset() - pp = point.Point(0, i, "physical") - lp = self.logical_point(pp) - self.goto(lp) - - # point validation - def _validate_cursor(self): - self.buffer._validate_point(self.logical_cursor()) - def _validate_mark(self): - self.buffer._validate_point(self.mark) - def _validate_first_last(self): - assert self.first <= self.logical_cursor(), "one" - assert (self.first.x % self.width) == 0, "two: %d %% %d != 0 (%d)" % (self.first.x, self.width, self.first.x % self.width) - assert self.first <= self.last, "four" - - # moving in buffer - def forward(self): - cursor = self.logical_cursor() - if cursor.x < len(self.buffer.lines[cursor.y]): - self.cursor.x = cursor.x + 1 - elif cursor.y < len(self.buffer.lines) - 1: - self.cursor.y = cursor.y + 1 - self.cursor.x = 0 - if not self.cursor_is_visible(): - self.center_view() - def backward(self): - cursor = self.logical_cursor() - if cursor.x > 0: - self.cursor.x = cursor.x - 1 - elif self.cursor.y > 0: - self.cursor.y = cursor.y - 1 - self.cursor.x = len(self.buffer.lines[self.cursor.y]) - if not self.cursor_is_visible(): - self.center_view() - def end_of_line(self): - self.cursor.x = len(self.buffer.lines[self.cursor.y]) - if not self.cursor_is_visible(): - self.center_view() - def start_of_line(self): - self.cursor.x = 0 - if not self.cursor_is_visible(): - self.center_view() - def previous_line(self): - if self.cursor.y > 0: - self.cursor.y -= 1 - if not self.cursor_is_visible(): - self.center_view() - def next_line(self): - if self.cursor.y < len(self.buffer.lines) - 1: - self.cursor.y += 1 - if not self.cursor_is_visible(): - self.center_view() - - def pshift(self, p, i): - y = max(0, p.y + i) - y = min(y, len(self._physical_lines) - 1) - x = min(len(self._physical_lines[y]), p.x) - return self.logical_point(point.Point(x, y, "physical")) - - # word handling - def find_left_word(self, p=None): - if p is None: - p = self.logical_cursor().offset(0, 0) - start = self.buffer.get_buffer_start() - if p == start: - return - elif p.x == 0: - p.y -= 1 - p.x = len(self.buffer.lines[p.y]) - else: - p.x -= 1 - while p >= start and self.point_char(p) not in WORD_LETTERS: - if p.x == 0: - p.y -= 1 - p.x = len(self.buffer.lines[p.y]) - else: - p.x -= 1 - found_word = False - while p >= start and self.point_char(p) in WORD_LETTERS: - found_word = True - if p.x == 0: - p.y -= 1 - p.x = len(self.buffer.lines[p.y]) - else: - p.x -= 1 - if not found_word: - pass - elif p.x == len(self.buffer.lines[p.y]): - p.x = 0 - p.y += 1 - else: - p.x += 1 - return p - def find_right_word(self, p=None): - if p is None: - p = self.logical_cursor().offset(0, 0) - end = self.buffer.get_buffer_end() - while p < end and self.point_char(p) not in WORD_LETTERS: - if p.x == len(self.buffer.lines[p.y]): - p.x = 0 - p.y += 1 - else: - p.x += 1 - while p < end and self.point_char(p) in WORD_LETTERS: - if p.x == len(self.buffer.lines[p.y]): - p.x = 0 - p.y += 1 - else: - p.x += 1 - return p - def left_word(self): - p = self.find_left_word() - if p is not None: - self.goto(p) - def right_word(self): - p = self.find_right_word() - if p is not None: - self.goto(p) - - # page up/down - def page_up(self): - first_point = self.buffer.get_buffer_start() - if self.point_is_visible(first_point): - self.goto_beginning() - return - self.cursor = self.pshift(self.physical_cursor(), 3 - self.height) - if self.first > first_point: - self.first = self.pshift(self.physical_point(self.first), 3 - self.height) - self.redraw() - def page_down(self): - last_point = self.buffer.get_buffer_end() - if self.point_is_visible(last_point): - self.goto_end() - return - self.cursor = self.pshift(self.physical_cursor(), self.height - 3) - if self.last < last_point: - self.first = self.pshift(self.physical_point(self.first), self.height - 3) - self.redraw() - - # jumping in buffer - def goto(self, p): - self.buffer._validate_point(p) - self.cursor.x = p.x - self.cursor.y = p.y - if not self.cursor_is_visible(): - self.center_view() - def goto_line(self, y): - if y < 0: - y = len(self.buffer.lines) + y + 1 - self.buffer._validate_y(y) - self.cursor.y = y - self.cursor.x = 0 - if not self.cursor_is_visible(): - self.center_view() - def forward_lines(self, n): - assert n > 0, "illegal number of lines: %d" % n - m = 0 - p = self.logical_cursor().copy() - while m < n and p.y < len(self.buffer.lines): - p.y += 1 - m += 1 - self.goto(p) - def forward_chars(self, n): - m = 0 - p = self.logical_cursor().copy() - while p < self.last and m < n: - if p.x == len(self.buffer.lines[p.y]): - p.y += 1 - p.x = 0 - m += 1 - else: - p.x += 1 - m += 1 - self.goto(p) - def goto_char(self, n): - self.goto(point.Point(0, 0)) - self.forward_chars(n) - def goto_beginning(self): - self.cursor = self.buffer.get_buffer_start() - self.first = self.buffer.get_buffer_start() - self.redraw() - def goto_end(self): - self.cursor = self.buffer.get_buffer_end() - if not self.cursor_is_visible(): - pcursor = self.physical_cursor() - pfirst = pcursor.offset(0, 3 - self.height) - pfirst.x = 0 - self.first = self.logical_point(pfirst) - self.redraw() - - # mark manipulation - def set_mark_point(self, p): - self.mark = p.offset(0, 0) - def set_mark(self): - cursor = self.logical_cursor() - self.set_mark_point(cursor) - self.application.set_error("Mark set") - def goto_mark(self): - self.goto(self.mark) - def switch_mark(self): - if self.mark: - p = self.mark - cursor = self.logical_cursor() - self.set_mark_point(cursor) - self.goto(p) - - # deletion - def left_delete(self): - cursor = self.logical_cursor() - if cursor.x > 0: - self.buffer.delete_character(cursor.offset(-1, 0, "logical")) - elif cursor.y > 0: - self.buffer.delete_character(point.Point(len(self.buffer.lines[cursor.y-1]), - cursor.y - 1, - "logical")) - else: - pass - def right_delete(self): - cursor = self.logical_cursor() - if cursor < self.last: - self.buffer.delete_character(cursor) - else: - pass - - # killing - def kill_line(self): - return self.copy_line(kill=True) - def kill_region(self): - return self.copy_region(kill=True) - def kill_left_word(self): - p1 = self.find_left_word() - p2 = self.logical_cursor() - if p1 == p2: - return - return self.kill(p1, p2) - def kill_right_word(self): - p1 = self.logical_cursor() - p2 = self.find_right_word() - if p1 == p2: - return - return self.kill(p1, p2) - def copy_line(self, kill=False): - cursor = self.logical_cursor() - if (cursor.x < len(self.buffer.lines[cursor.y]) and - not regex.whitespace.match(self.buffer.lines[cursor.y][cursor.x:])): - limit = point.Point(len(self.buffer.lines[cursor.y]), cursor.y, "logical") - elif cursor.y < len(self.buffer.lines) - 1: - limit = point.Point(0, cursor.y + 1, "logical") - else: - return - if kill: - return self.kill(cursor, limit) - else: - return self.copy(cursor, limit) - def copy_region(self, kill=False): - cursor = self.logical_cursor() - if cursor < self.mark: - p1 = cursor - p2 = self.mark - elif self.mark < cursor: - p1 = self.mark - p2 = cursor - else: - self.input_line = "Empty kill region" - return - if kill: - return self.kill(p1, p2) - else: - return self.copy(p1, p2) - def kill(self, p1, p2): - killed = self.buffer.get_substring(p1, p2) - self.buffer.delete_string(p1, p2) - self.application.push_kill(killed) - return killed - def copy(self, p1, p2): - copied = self.buffer.get_substring(p1, p2) - self.application.push_kill(copied) - return copied - - # insertion - def insert_string(self, s): - cursor = self.logical_cursor() - self.insert(cursor, s) - def insert(self, p, s): - c = s.count('\n') - if c > 0: - y = p.y + c - x = len(s) - (c + 1) - 1 - else: - y = p.y - x = p.x + len(s) - self.buffer.insert_string(p, s) - def yank(self): - s = self.application.get_kill() - self.insert_string(s) - def pop_kill(self): - return self.application.pop_kill() - - # querying - def highlighted_char(self): - cursor = self.logical_cursor() - self.point_char(cursor) - def point_char(self, p): - if p.x == len(self.buffer.lines[p.y]): - return "\n" - else: - return self.buffer.lines[p.y][p.x] - - - # region finding (p is a physical point) - def get_region(self, p): - regions = self.mode.get_regions() - assert len(regions[p.y]) > 0, "no regions found; strange" - for r in regions[p.y]: - if r.start <= p.x and r.end >= p.x + 1: - return r - return None