import os, commands, re, tempfile from subprocess import Popen, PIPE, STDOUT import buffer, completer, default, dirutil, regex, util, window from point import Point class MethodError(Exception): pass def arg(n, t=type(''), dt=None, p=None, h='', dv=default.none, ld=False): '''convenience function for arguments''' return Argument(n, type=t, datatype=dt, prompt=p, help=h, default=dv, load_default=ld) class Argument(object): def __init__(self, name, type=type(""), datatype=None, prompt=None, help='', default=default.none, load_default=False): self.name = name self.type = type self.datatype = datatype if prompt is None: self.prompt = "%s: " % (name) else: self.prompt = prompt self.help = help self.load_default = load_default self.default = default def coerce_to_type(self, value): if self.type == type(0): try: return int(value, 0) except: raise Exception, "expected int; got %s" % (repr(value)) else: return value def ask_for_value(self, method, w, **vargs): app = w.application assert app.mini_buffer_is_open() is False, "Recursive minibuffer antics" vargs2 = vargs.copy() assert callable(self.default), "default value func must be callable" if self.load_default: d = None starting_value = self.default(w) else: d = self.default(w) starting_value = None def return_value(v): if d is not None and v == "": v = d vargs2[self.name] = self.coerce_to_type(v) app.close_mini_buffer() method.execute(w, **vargs2) tabber = completer.get(self.datatype) if d is not None: p = self.prompt + "(%s) " % (d) else: p = self.prompt app.open_mini_buffer(p, return_value, method=method, tabber=tabber, startvalue=starting_value) class Method(object): _is_method = True args = [] help = "" def __init__(self): self.name = self._name() if self.__doc__: self.help = self.__doc__ def _name(cls): s = cls.__name__ s2 = s[0].lower() for c in s[1:]: if c.isupper(): s2 += '-' + c.lower() elif c == '_': s2 += '-' else: s2 += c return s2 _name = classmethod(_name) def _pre_execute(self, w, **vargs): pass def execute(self, w, **vargs): try: self._pre_execute(w, **vargs) except MethodError, e: w.set_error(str(e)) return for arg in self.args: if arg.name not in vargs: self.old_window = w arg.ask_for_value(self, w, **vargs) return self._execute(w, **vargs) w.buffer.undo_id += 1 def _execute(self, w, **vargs): raise Exception, "Unimplemented Method: %s %r" % (self.name, vargs) class RelexBuffer(Method): '''Relex the buffer; this resets syntax highlighting''' def _execute(self, w, **vargs): h = w.get_highlighter() if h is None: w.set_error("No lexer for buffer.") else: h.highlight(w.buffer.lines) w.set_error("Buffer relexed.") class ToggleWindow(Method): '''Move between visible windows''' def _execute(self, w, **vargs): w.application.toggle_window() # complex text maniuplation class TransposeWords(Method): '''Switch the place of the two words nearest the cursor''' pass # you wanna quit right? class Exit(Method): '''Exit the program, unless there are unsaved changes''' def _execute(self, w, **vargs): a = w.application assert a.mini_buffer_is_open() is False, "Recursive minibuffer antics" changed = False for b in w.application.bufferlist.buffers: changed = b.changed() if changed: break if not changed: w.application.exit() return else: self._old_window = w self._prompt = "There are buffers with unsaved changes; exit anyway? " a.open_mini_buffer(self._prompt, self._callback) def _callback(self, v): a = self._old_window.application if v == 'yes': a.exit() a.close_mini_buffer() if v == 'no': return a.open_mini_buffer(self._prompt, self._callback) a.set_error('Please type "yes" or "no"') # insert text class InsertString(Method): _is_method = False def __init__(self, s): self.name = "insert-string-%s" % s self.args = [] self.help = "Insert %r into the current buffer." % s self.string = s def _execute(self, w, **vargs): try: w.insert_string_at_cursor(self.string) except buffer.ReadOnlyError: w.set_error('Buffer is read-only') class OverwriteChar(Method): _is_method = False def __init__(self, c): self.name = 'overwrite-char-%s' % c self.args = [] self.help = "Overwrite %r into the current buffer." % c self.char = c def _execute(self, w, **vargs): w.overwrite_char_at_cursor(self.char) class InsertText(Method): '''Insert literal text into the buffer''' args = [arg('text', t="string", p="Literal: ", h='Literal text to insert')] def _execute(self, w, **vargs): w.insert_string_at_cursor(vargs['text']) class InsertText2(Method): '''Insert escaped text into the buffer''' args = [arg('text', t="string", p="Text: ", h='Text to insert')] def _execute(self, w, **vargs): text = vargs['text'].replace('\\n', '\n') text = text.replace('\\t', ' ') text = text.replace('\\\\', '\\') w.insert_string_at_cursor(text) class InsertMultilineText(Method): '''Insert multiple lines into the buffer (M-RETURN to end; C-] to cancel)''' def _execute(self, w, **vargs): f = lambda s: w.insert_string_at_cursor(s) w.application.open_mini_buffer('Multi-Insert: ', f, self, None, 'insertmini') # killing/copying/etc. class Kill(Method): '''Kill the contents of the current line''' def _execute(self, w, **vargs): w.kill_line() class KillRegion(Method): '''Kill the region between the mark and the cursor''' def _execute(self, w, **vargs): w.kill_region() w.set_error("Region killed by %s" % self.name) class Copy(Method): '''Copy the contents of the current line''' def _execute(self, w, **vargs): result = w.copy_line() if result is None: w.set_error("Empty kill region") class CopyRegion(Method): '''Copy the region between the mark and the cursor''' def _execute(self, w, **vargs): w.copy_region() w.set_active_point(w.mark) w.set_error("Region copied") class Yank(Method): '''Paste the top item in the kill ring into the buffer''' def _execute(self, w, **vargs): if w.application.has_kill(): w.yank() else: w.set_error("Kill ring is empty") class ShowKill(Method): '''Display the top item in the kill ring''' def _execute(self, w, **vargs): if w.application.has_kill(): s = w.application.get_kill() x = w.application.x if len(s) > x - 40: s = s[:x - 40] + "..." w.set_error("Kill ring contains %r" % s) else: w.set_error("Kill ring is empty") class PopKill(Method): '''Pop the top item in the kill ring off''' def _execute(self, w, **vargs): if w.application.has_kill(): s = w.pop_kill() x = w.application.x if len(s) > x - 40: s = s[:x - 40] + "..." w.set_error("Removed %r from Kill ring" % s) else: w.set_error("Kill ring is empty") # delete class DeleteLeft(Method): '''Delete the character to the left of the cursor''' def _execute(self, w, **vargs): (x, y) = w.logical_cursor().xy() line = w.buffer.lines[y] tabwidth = w.mode.tabwidth if x >= tabwidth and x % tabwidth == 0 and line[0:x].isspace(): w.delete(Point(x - tabwidth, y), Point(x, y)) else: w.left_delete() class DeleteRight(Method): '''Delete the character under the cursor''' def _execute(self, w, **vargs): cursor = w.logical_cursor() line = w.buffer.lines[cursor.y] lvl = w.mode.tabwidth if len(line[cursor.x:]) >= lvl and line[:cursor.x + lvl].isspace(): w.delete(Point(cursor.x, cursor.y), Point(cursor.x + lvl, cursor.y)) else: w.right_delete() class DeleteLeftWord(Method): '''Delete the from the cursor left to the end of the word''' def _execute(self, w, **vargs): w.delete_left_word() class DeleteRightWord(Method): '''Delete the from under cursor right to the end of the word''' def _execute(self, w, **vargs): w.delete_right_word() class DeleteLeftWhitespace(Method): '''Delete all contiguous of whitespace left of the cursor''' def _execute(self, w, **vargs): c = w.logical_cursor() p = c l = w.point_left(p) if l is None: return while l is not None and w.point_char(l) in (' ', '\n'): p = l l = w.point_left(p) if p < c: w.delete(p, c) class DeleteRightWhitespace(Method): '''Delete all contiguous of whitespace under and right of the cursor''' def _execute(self, w, **vargs): c = w.logical_cursor() p = c while w.point_char(p) in (' ', '\n'): r = w.point_right(p) if r is None: break p = r if p > c: w.delete(c, p) class DeleteLeftSpace(Method): '''Delete all contiguous spaces left of the cursor''' def _execute(self, w, **vargs): c = w.logical_cursor() p = c l = w.point_left(p) if l is None: return while l is not None and w.point_char(l) == ' ': p = l l = w.point_left(p) if p < c: w.delete(p, c) class DeleteRightSpace(Method): '''Delete all contiguous spaces under and right of the cursor''' def _execute(self, w, **vargs): c = w.logical_cursor() p = c while w.point_char(p) == ' ': r = w.point_right(p) if r is None: break p = r if p > c: w.delete(c, p) class MetaX(Method): '''Invoke commands by name''' args = [arg('method', dt="method", p="M-x ", h='Method to execute')] name_re = re.compile(r'^ *([a-z0-9_-]+) *(?:\( *\))? *$') full_re = re.compile(r'^ *([a-z0-9_-]+) *\((.*)\) *$') arg_re = re.compile(r' *(-?[0-9\.]+|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\\"])*") *') varg_re = re.compile(r' *([a-zA-Z0-9_]+) *= *(-?[0-9\.]+|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\\"])*") *') def _execute(self, w, **vargs): m = self.name_re.match(vargs['method']) if m: name2 = m.group(1) self._sub_execute(w, name2, {}) return m = self.full_re.match(vargs['method']) if m: vargs2 = {} if '=' in m.group(2): name2, vargs_str = m.group(1), m.group(2) i = 0 m = self.varg_re.search(vargs_str, i) while m: i = m.end() vargs2[m.group(1)] = eval(m.group(2)) if i == len(vargs_str): break elif vargs_str[i] != ',': break else: i += 1 m = self.varg_re.search(vargs_str, i) if i == len(vargs_str): self._sub_execute(w, name2, vargs2) return else: name2, args_str = m.group(1), m.group(2) i = 0 m = self.arg_re.search(args_str, i) args = [] while m: i = m.end() args.append(eval(m.group(1))) if i == len(args_str): break elif args_str[i] != ',': break else: i += 1 m = self.arg_re.search(args_str, i) d = {} try: meth = w.application.methods[name2] for (arg, value) in zip(meth.args, args): vargs2[arg.name] = value except: pass if i == len(args_str): self._sub_execute(w, name2, vargs2) return w.set_error('could not parse argument %r' % vargs['method']) def _sub_execute(self, w, name, vargs): if name in w.application.methods: w.application.methods[name].execute(w, **vargs) else: w.set_error('no method named %r found' % name) class ToggleMargins(Method): '''Show or hide column margins''' def _execute(self, w, **vargs): w.margins_visible = not w.margins_visible class CenterView(Method): '''Move view to center on cursor''' def _execute(self, w, **vargs): w.center_view(force=True) class SetMark(Method): '''Set the mark to the current cursor location''' def _execute(self, w, **vargs): w.set_mark() class SwitchMark(Method): '''Switch the mark and the cursor locations''' def _execute(self, w, **vargs): w.switch_mark() # insertion methods class InsertNewline(Method): '''Insert newline into buffer at the cursor''' def _execute(self, w, **vargs): w.insert_string_at_cursor('\n') class InsertSpace(Method): '''Insert space into buffer at the cursor''' def _execute(self, w, **vargs): w.insert_string_at_cursor(' ') class InsertSquotes(Method): '''Insert a pair of single-quotes into the buffer''' def _execute(self, w, **vargs): w.insert_string_at_cursor("''") w.backward() class InsertDquotes(Method): '''Insert a pair of double-quotes into the buffer''' def _execute(self, w, **vargs): w.insert_string_at_cursor('""') w.backward() class InsertTab(Method): '''Insert tab into buffer, or tabbify line, depending on mode''' def _execute(self, w, **vargs): cursor = w.logical_cursor() if w.mode.tabber: i = w.mode.tabber.get_level(cursor.y) else: i = None if i is None: w.insert_string_at_cursor(' ' * w.mode.tabwidth) else: j = w.buffer.count_leading_whitespace(cursor.y) if i != j: KillWhitespace().execute(w) w.insert_string(Point(0, cursor.y), ' ' * i) else: w.goto(Point(j, cursor.y)) class KillWhitespace(Method): '''Delete leading whitespace on current line''' def _execute(self, w, **vargs): cursor = w.logical_cursor() i = w.buffer.count_leading_whitespace(cursor.y) if i > 0: w.delete(Point(0, cursor.y), Point(i, cursor.y)) # tabification class TabBuffer(Method): '''Tabbify every line in the current buffer''' def _execute(self, w, **vargs): y = w.logical_cursor().y it = InsertTab() for i in range(0, len(w.buffer.lines)): w.goto_line(i) it.execute(w) w.goto_line(y) class GetIndentionLevel(Method): '''Calculate the indention level for this line''' def _execute(self, w, **vargs): cursor = w.logical_cursor() if not w.mode.tabber: w.set_error('No tabber available') return else: i = w.mode.tabber.get_level(cursor.y) w.set_error('Indention level: %r' % i) # commenting class CommentRegion(Method): '''Prepend a comment to every line in the current buffer''' commentc = '#' def _execute(self, w, **vargs): cursor = w.logical_cursor() if cursor < w.mark: p1 = cursor p2 = w.mark elif w.mark < cursor: p1 = w.mark p2 = cursor else: w.input_line = "Empty kill region" return for y in range(p1.y, p2.y): w.buffer.insert_string(Point(0, y), self.commentc) class UncommentRegion(Method): '''Remove a comment from every line in the current buffer''' commentc = '#' def _execute(self, w, **vargs): cursor = w.logical_cursor() if cursor < w.mark: p1 = cursor p2 = w.mark elif w.mark < cursor: p1 = w.mark p2 = cursor else: w.input_line = "Empty kill region" return for y in range(p1.y, p2.y): if w.buffer.lines[y].startswith(self.commentc): w.buffer.delete(Point(0, y), Point(1, y)) # wrapping/justifying/etc class WrapLine(Method): limit = 80 space_re = re.compile(' +') def _token_len(self, tokens): l = 0 for t in tokens: l += len(t) return l def _find_line_bounds(self, limit, tokens, x, y): if len(tokens[0]) > limit: i = 1 else: i = 0 l = self._token_len(tokens[:i+1]) while i < len(tokens) and l <= limit: i += 1 l = self._token_len(tokens[:i+1]) while i > 1 and tokens and tokens[i-1].isspace(): token = tokens.pop(i-1) l -= len(token) if x > l: x -= len(token) i -= 1 return i, x, y def _clear_preceeding_spaces(self, tokens, x, y): while tokens and self.space_re.match(tokens[0]): if x > 0: x = max(0, x - len(tokens[0])) del tokens[0] return x, y def _wrap_line(self, limit, line, x, y): tokens = re.findall('[^ ]+| +', line) if self._token_len(tokens) <= limit: return None, None, None lines = [] while tokens and self._token_len(tokens) > limit: i, x, y = self._find_line_bounds(limit, tokens, x, y) s = ''.join(tokens[:i]) lines.append(s) if x > len(s): y += 1 x -= len(s) del tokens[:i] x, y = self._clear_preceeding_spaces(tokens, x, y) if tokens: lines.append(''.join(tokens) + ' ') return lines, x, y def _execute(self, w, **vargs): limit = util.get_margin_limit(w, self.limit) cursor = w.logical_cursor() x, y = cursor.xy() lines, x, y = self._wrap_line(limit, w.buffer.lines[y], x, y) if lines is None: return p1 = Point(0, cursor.y) p2 = Point(len(w.buffer.lines[cursor.y]), cursor.y) w.buffer.delete(p1, p2) p3 = Point(0, cursor.y) w.buffer.insert_lines(p3, lines) w.goto(Point(x, y)) class WrapParagraph(Method): limit = 80 valid_re = re.compile('^( *)([^ ].*)$') empty_re = regex.whitespace def _execute(self, w, **vargs): limit = util.get_margin_limit(w, self.limit) # we will store the start of our paragaph in p1, and also the original # cursor position. p1 = oldc = w.logical_cursor() cur_offset = 0 m = self.valid_re.match(w.buffer.lines[p1.y]) if not m: # the line was empty return elif m.group(1): # the line had leading whitespace return # see if we are starting in the middle of the paragraph; if so, then # let's find the actual begining, and update p1 accordingly. i = p1.y if i > 1 and w.buffer.lines[i] and not w.buffer.lines[i].startswith(' '): while i > 1 and w.buffer.lines[i - 1] and not w.buffer.lines[i - 1].startswith(' '): i -= 1 p1 = Point(0, i) # get the first line; strip it, and put it in our new lines list. s1 = w.buffer.lines[p1.y][p1.x:] s2 = s1.rstrip() if p1.y <= oldc.y: cur_offset += len(s1) - len(s2) lines = [s2] # ok, so now let's move forward and find the end of the paragraph. i = p1.y + 1 while i < len(w.buffer.lines) and w.buffer.lines[i] and not w.buffer.lines[i].startswith(' '): s1 = w.buffer.lines[i] s2 = s1.rstrip() if oldc.y == i: # once we've adjusted all our previous lines, adjust our # stored cursor to keep it's X and Y in sync (set Y to the line # the paragraph started on, increase X by the previous lines # plus added spaces minus removed whitespace. x = p1.x + oldc.x + sum([len(x) + 1 for x in lines]) - cur_offset oldc = Point(x, p1.y) elif i < oldc.y: cur_offset += len(s1) - len(s2) lines.append(s2) i += 1 # stringify our paragraph s = " ".join(lines) #raise Exception, '%r %r' % (limit, s) # ok, so now we need to find the line breaks newlines = [] while s: # if we have less than the limit left, add it and we're done! if len(s) < limit: newlines.append(s) break # look for the rightmost space within our bounds j = s.rfind(' ', 0, limit) # if we failed to find one, look for the leftmost space if j == -1: j = s.find(' ') # if we failed to find any, use the whole rest of the paragraph if j == -1: j = len(s) # add the next chunk we found and adjust the paragraph newlines.append(s[:j]) s = s[j + 1:] # translate our cursor according to the line breaks we just did. (x, y) = oldc.xy() k = 0 while k < len(newlines) - 1 and x > len(newlines[k]): x = x - len(newlines[k]) - 1 y += 1 k += 1 #assert len(newlines), 'fooga: %r %r' % (limit, s) # kill the old paragraph region, insert the new, and goto the new cursor w.delete(p1, Point(len(w.buffer.lines[i-1]), i-1)) w.insert_lines(p1, newlines) w.goto(Point(x, y)) class CountWords(Method): '''Count the number of words in the document''' def _execute(self, w, **vargs): wcount = 0 pcount = 0 inp = False name = w.buffer.name() for line in w.buffer.lines: c = len(line.split()) if c and not inp: inp = True pcount += 1 elif not c and inp: inp = False wcount += c w.set_error("%d words (%d paragraphs) found in %r" % (wcount, pcount, name)) class JustifyRight(Method): '''Justify text with the previous line right from the cursor by whitespace''' def _execute(self, w, **vargs): DeleteLeftSpace().execute(w) cursor = w.logical_cursor() prev_line = w.buffer.lines[cursor.y-1] this_line = w.buffer.lines[cursor.y] if cursor.y <= 0: return if cursor.x >= len(prev_line): return i = cursor.x while prev_line[i] != ' ': i += 1 if i >= len(prev_line): return while prev_line[i] == ' ': i += 1 if i >= len(prev_line): return s = ' ' * (i - cursor.x) w.insert_string_at_cursor(s) class JustifyLeft(Method): '''Justify text with the previous line left from the cursor by whitespace''' def _execute(self, w, **vargs): DeleteRightWhitespace().execute(w) cursor = w.logical_cursor() prev_line = w.buffer.lines[cursor.y-1] this_line = w.buffer.lines[cursor.y] if cursor.y <= 0: return if cursor.x <= 0: return i = cursor.x while i >= len(prev_line): i -= 1 if i <= 0: return if this_line[i] != ' ': return while prev_line[i] != ' ': i -= 1 if i <= 0: return if this_line[i] != ' ': return while prev_line[i] == ' ': i -= 1 if i >= len(prev_line): return if this_line[i] != ' ': return w.buffer.delete(Point(i, cursor.y), cursor) # undo/redo class Undo(Method): '''Undo last action''' def _execute(self, w, **vargs): try: w.undo() except Exception, e: w.set_error("%s" % (e)) class Redo(Method): '''Redo last undone action''' def _execute(self, w, **vargs): try: w.redo() except Exception, e: w.set_error("%s" % (e)) class UnindentBlock(Method): '''Prepend a tab of space to each line in region''' def _execute(self, w, **vargs): lvl = w.mode.tabwidth cursor = w.logical_cursor() if cursor < w.mark: p1 = cursor p2 = w.mark elif w.mark < cursor: p1 = w.mark p2 = cursor else: w.input_line = "Empty kill region" return lines = w.buffer.lines[p1.y:p2.y] for i in range(0, len(lines)): if lines[i].startswith(' '): lines[i] = lines[i][lvl:] w.buffer.delete(Point(0, p1.y), Point(0, p2.y)) w.buffer.insert_string(Point(0, p1.y), '\n'.join(lines) + '\n') class IndentBlock(Method): '''Prepend a tab of space to each line in region''' def _execute(self, w, **vargs): cursor = w.logical_cursor() if cursor < w.mark: p1 = cursor p2 = w.mark elif w.mark < cursor: p1 = w.mark p2 = cursor else: w.input_line = "Empty kill region" return lines = w.buffer.lines[p1.y:p2.y] tstr = ' ' * w.mode.tabwidth for i in range(0, len(lines)): lines[i] = tstr + lines[i] w.buffer.delete(Point(0, p1.y), Point(0, p2.y)) w.buffer.insert_string(Point(0, p1.y), '\n'.join(lines) + '\n') class FileDiff(Method): '''diff the buffer's contents with the given file''' args = [arg("path", t=type(""), p="Filename: ", dt='path', h="path to diff against current buffer's contents")] def _execute(self, w, **vargs): cmd = ("/usr/bin/diff", '-u', '-', vargs['path']) pipe = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE) pid = pipe.pid indata = w.buffer.make_string() pipe.stdin.write(indata) pipe.stdin.close() outdata = pipe.stdout.read() errdata = pipe.stderr.read() status = pipe.wait() >> 8 if status == 0: w.set_error("No difference found") elif status == 1: w.application.data_buffer("*Diff*", outdata, switch_to=True, modename='diff') w.set_error("Differences were found") else: w.application.data_buffer("*Diff*", errdata, switch_to=True) w.set_error("There was an error: %d exited with status %s" % (pid, status)) class SetMode(Method): '''Set the mode of the current buffer''' args = [arg('mode', dt='mode', p="Enter new mode: ")] def _execute(self, w, **vargs): mode_name = vargs['mode'] m = w.application.modes[mode_name](w) w.set_mode(m) w.set_error('Set mode to %r' % (mode_name)) class Cancel(Method): '''Cancel command in-progress, and return to the main buffer''' def execute(self, w, **vargs): w.application.close_mini_buffer() if w.application.completion_window_is_open(): w.application.close_completion_buffer() w.set_error('Cancel') class SplitWindow(Method): '''Split the main window horizontally into upper and lower windows''' def execute(self, w, **vargs): a = w.application a.add_slot() if not w.cursor_is_visible(): p = w.first w.goto(p) n = len(a.bufferlist.slots) a.set_error('Window has been split into %d windows!' % n) class UnsplitWindow(Method): '''Maximize the current window to fill the screen''' def execute(self, w, **vargs): w.application.single_slot() w.set_error('Window has been unsplit back to one window!') class CloseTag(Method): mytag = ')' def _execute(self, w, **vargs): # first, de-reference some variables and actually do the insertion # NOTE: we derence the cursor *before* inserting the character, so it is # expecected that the cursor variable should be the point the new # character is on. (x, y) = w.logical_cursor().xy() w.insert_string_at_cursor(self.mytag) app = w.application buffer = w.buffer highlighter = buffer.highlights[w.mode.name()] tokens = highlighter.tokens # REFACTOR: we have methods in window to do this now i = 0 while i < len(tokens[y]): token = tokens[y][i] if token.x == x and token.string == self.mytag: break elif token.x <= x and token.end_x() > x: return i += 1 if i >= len(tokens[y]): return tag_stack = [] while y >= 0: while i >= 0 and i < len(tokens[y]): token = tokens[y][i] n = token.name s = token.string if n in w.mode.closetokens and s in w.mode.closetags: tag_stack.append(s) elif n in w.mode.opentokens and s in w.mode.opentags: if tag_stack[-1] == w.mode.opentags[s]: del tag_stack[-1] else: app.set_error("tag mismatch; got %r expected %r" % (s, w.mode.closetags[tag_stack[-1]])) return if len(tag_stack) == 0: p = Point(token.x, y) s = w.buffer.lines[p.y][:p.x+1] if len(s) > 60: s = "..." + s[-60:] msg = 'matches %r' % s w.set_active_point(p, msg) return i -= 1 y -= 1 i = len(tokens[y]) - 1 class CloseParen(CloseTag): mytag = ')' class CloseBrace(CloseTag): mytag = '}' class CloseBracket(CloseTag): mytag = ']' class RegisterSave(Method): '''Save the top item of the kill stack into the named register''' MAX_TXT = 30 MAX_REG = 18 args = [arg('name', dt="register", p="Register name: ", h="Name of the register to use")] def _pre_execute(self, w, **vargs): if not w.has_kill(): raise MethodError("No text on the kill stack") def _execute(self, w, **vargs): name = vargs['name'] text = w.get_kill() w.application.registers[name] = text if len(name) > self.MAX_REG: name = name[:self.MAX_REG] + '...' if len(text) > self.MAX_TXT: text = text[:self.MAX_TXT] + '...' w.set_error('Saved %r into register %r' % (text, name)) class RegisterRestore(Method): '''Push the value saved in the named register onto the kill stack''' MAX_TXT = 30 MAX_REG = 18 args = [arg('name', dt="register", p="Register name: ", h="Name of the register to use")] def _execute(self, w, **vargs): name = vargs['name'] if name not in w.application.registers: w.set_error('Register %r does not exist' % name) return app = w.application text = app.registers[name] w.push_kill(text) if len(text) > self.MAX_TXT: text = text[0:self.MAX_TXT] + '...' if len(name) > self.MAX_REG: name = name[0:self.MAX_REG] + '...' w.set_error('Restored %r from register %r' % (text, name)) class GetConfigVariable(Method): args = [arg('name', dt='config', p="Variable name: ", h='Name of the configuration parameter')] def _execute(self, w, **vargs): name = vargs['name'] if name in w.application.config: value = w.application.config[name] w.set_error("param %r set to %r" % (name, value)) else: w.set_error("param %r is not set" % (name,)) class ViewConfigVariables(Method): def _execute(self, w, **vargs): lines = ["APPLICATION CONFIGURATION VARIABLES\n"] for name in w.application.config: lines.append(" %-20s %r\n" % (name, w.application.config[name])) data = ''.join(lines) w.application.data_buffer('*Config*', data, switch_to=True) class SetConfigVariable(Method): args = [arg('name', dt='config', p="Variable name: ", h='Name of the configuration parameter'), arg('value', t=type(''), p="Variable value: ", h='Configuration parameter value to use')] def _execute(self, w, **vargs): name = vargs['name'] found = name in w.application.config try: value = eval(vargs['value']) except: value = vargs['value'] w.application.config[name] = value if found: w.set_error("param %r set to %r" % (name, value)) else: w.set_error("previously unset param %r set to %r" % (name, value)) class ToggleLineNumbers(Method): def _execute(self, w, **vargs): if w.mode.show_line_numbers: w.mode.disable_line_numbers() w.set_error('Line numbers hidden') else: w.mode.enable_line_numbers() w.set_error('Line numbers visible') class SetTabWidth(Method): args = [arg('width', t=type(0), p="Tab Width: ", h='New tab width for buffer')] def _execute(self, w, **vargs): w.mode.tabwidth = vargs['width'] w.set_error('Tab width set to %d' % w.mode.tabwidth) class SetModeTabWidth(Method): args = [arg('mode', dt='mode', p="Mode: ", h=''), arg('width', t=type(0), p="Default Tab Width: ", h='New default tab width for mode')] def _execute(self, w, **vargs): app, mode = w.application, vargs['mode'] if mode not in app.modes: w.set_error('Mode %r not found' % mode) return app.modes[mode].tabwidth = vargs['width'] w.set_error('Default tab width set to %d' % app.modes[mode].tabwidth)