From 479e64d1e080dac3a9aa69157d1c88df65756f3d Mon Sep 17 00:00:00 2001 From: Erik Osheim Date: Mon, 19 Apr 2010 22:38:28 -0400 Subject: [PATCH 1/5] add support for tabs and $/ where possible --HG-- branch : pmacs2 --- mode/perl.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mode/perl.py b/mode/perl.py index ca82719..4bcea25 100644 --- a/mode/perl.py +++ b/mode/perl.py @@ -26,7 +26,7 @@ word1 = wchr1 + wchr2 + '*' word2 = '(?:' + word1 + "(?:'|::))*" + word1 pname = '[.a-zA-Z0-9_]+' -spaces = PatternRule('spaces', ' +') +spaces = PatternRule('spaces', '[\t ]+') eol = PatternRule('eol', r'\n') length = PatternRule('perl.length', r"\$#" + word2) @@ -86,6 +86,9 @@ def _make_string_rules(forbidden): else: rules.insert(0, PatternRule('data', "\\$(?=" + forbidden + ')')) + if forbidden != '/': + rules.append(PatternRule('perl.scalar', r'\$/')) + if forbidden == ')': return rules + [PatternRule('data', r"[^$\%@\(\)]+")] elif forbidden == '}': @@ -168,7 +171,7 @@ PerlGrammar.rules = [ PatternRule('perl.function', r"\$\$*" + word2 + "(?=-> *\()"), # special scalar; doesn't interpolate well - #PatternRule('perl.scalar', r'\$/'), + PatternRule('perl.scalar', r'\$/'), ] + scalar_rules + [ # match regexes; paired delimiters From 20c095b6c638346afcf9b8727597220b66fe14e7 Mon Sep 17 00:00:00 2001 From: Erik Osheim Date: Mon, 19 Apr 2010 22:58:27 -0400 Subject: [PATCH 2/5] slightly improve tab support (as well as adding an *Exception* buffer for app exception) --HG-- branch : pmacs2 --- application.py | 3 ++- method/__init__.py | 17 ++++++++++++++--- mode/__init__.py | 13 ++++++++++--- mode/c.py | 9 +++++---- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/application.py b/application.py index 940a94b..f05ece5 100755 --- a/application.py +++ b/application.py @@ -318,7 +318,8 @@ class Application(object): lines = list(candidates) data = '\n'.join(lines) - b = self.data_buffer("*Completions*", data, switch_to=False) + b = self.data_buffer("*Completions*", data, switch_to=False) + b._completion = s b._opened = opened b._previous = previous diff --git a/method/__init__.py b/method/__init__.py index ef564ad..5cf7153 100644 --- a/method/__init__.py +++ b/method/__init__.py @@ -490,14 +490,25 @@ class InsertTab(Method): # if no lvl, insert a literal tab if lvl is None: - w.insert_string_at_cursor(' ' * w.mode.tabwidth) + #w.insert_string_at_cursor(' ' * w.mode.tabwidth) + if w.buffer.usetabs: + # see HACK in buffer + w.insert_string_at_cursor('\t \t') + else: + w.insert_string_at_cursor(' ' * w.mode.tabwidth) return # insert the correct amount of whitespace - ws = w.buffer.count_leading_whitespace(y) + ws = w.buffer.count_leading_whitespace(y) if lvl != ws: w.delete(Point(0, y), Point(ws, y)) - w.insert_string(Point(0, y), ' ' * lvl) + if w.buffer.usetabs: + nt = lvl // w.mode.tabwidth + ns = lvl % w.mode.tabwidth + s = ('\t \t' * nt) + (' ' * ns) + else: + s = ' ' * lvl + w.insert_string(Point(0, y), s) x2 = max(x, lvl) if w.logical_cursor().x < x2: w.goto(Point(x2, y)) diff --git a/mode/__init__.py b/mode/__init__.py index aa5ea23..17d11c1 100644 --- a/mode/__init__.py +++ b/mode/__init__.py @@ -1,5 +1,9 @@ +import math +import os +import string +import sys +import traceback from util import defaultdict -import math, os, string import color, method from lex import Lexer from point import Point @@ -458,8 +462,11 @@ class Fundamental(Handler): except Exception, e: if DEBUG: raise - else: - self.window.set_error(str(e)) + exc_type, exc_value, exc_traceback = sys.exc_info() + data = ''.join(traceback.format_tb(exc_traceback)) + self.window.application.data_buffer("*Exception*", data, + switch_to=False) + self.window.set_error(str(e)) def region_added(self, p, newlines): if self.lexer is not None: diff --git a/mode/c.py b/mode/c.py index ee6fff1..92a99e4 100644 --- a/mode/c.py +++ b/mode/c.py @@ -17,9 +17,10 @@ class ErrorGrammar(Grammar): PatternRule('continuation', r'\\\n$'), ] -chr1 = '[a-zA-Z_]' -chr2 = '[a-zA-Z0-9_]' -word = chr1 + chr2 + '*' +chr1 = '[a-zA-Z_]' +chr2 = '[a-zA-Z0-9_]' +word = chr1 + chr2 + '*' +spaces = r'[\t ]+' class MacroGrammar(Grammar): rules = [ @@ -36,7 +37,7 @@ class MacroGrammar(Grammar): class CGrammar(Grammar): rules = [ - PatternRule('spaces', r' +'), + PatternRule('spaces', spaces), PatternMatchRule('x', r'(\()( *)(' + word + r')(\**)( *)(\))( *)(?=[a-zA-Z0-9_\(])', 'delimiter', 'spaces', 'c.type', 'c.operator', From e5e4e28dbf4f2be30ce6228d2e7f0aacc7e1ce4e Mon Sep 17 00:00:00 2001 From: Erik Osheim Date: Tue, 20 Apr 2010 01:18:25 -0400 Subject: [PATCH 3/5] ported functionality from method.cvs to method.vc and method.svn --HG-- branch : pmacs2 --- method/cvs.py | 40 ++++++++++------------------------------ method/svn.py | 20 ++++++++++++++++++-- method/vc.py | 37 +++++++++++++++++++++++++++++++++++++ mode/c.py | 2 +- 4 files changed, 66 insertions(+), 33 deletions(-) diff --git a/method/cvs.py b/method/cvs.py index e360e82..123d899 100644 --- a/method/cvs.py +++ b/method/cvs.py @@ -5,6 +5,7 @@ import buffer, default, dirutil, lex, regex, util, window from point import Point from method import Method, Argument, arg +from method.vc import VcBlame, VcRevView, VcDateView class CvsCommit(Method): '''diff the current file with the version in CVS''' @@ -273,48 +274,27 @@ class CvsBlame(Method): w.set_error("There was an error (%s)" % (status)) class CvsBlame2(CvsBlame): - '''show blame output for the current version in CVS''' + '''show blame output for the given version in CVS''' args = [arg("revision", t=type(""), p="Revision: ", h="revision number")] line_re = re.compile('^([0-9.]+) +\(*([a-zA-Z0-9_]+) +([-0-9A-Za-z]+)\): (.*)$') def _get_cmd(self, w, **vargs): path = self._get_path(w, **vargs) return ("/usr/bin/cvs", 'annotate', '-r', vargs['revision'], path) -class CvsRevView(Method): +class CvsRevView(VcRevView): '''show blame output for the current version in CVS''' - args = [arg("revision", t=type(""), p="Revision: ", h="revision number")] - def _get_path(self, w, **vargs): - cwd = os.getcwd() + os.path.sep - path = w.buffer.path - if path.startswith(cwd): - path = path[len(cwd):] - return path - + args = [arg("revision", t=type(""), p="Revision: ", h="revision number")] + namebase = 'CVS' + _is_method = True def _get_cmd(self, w, **vargs): path = self._get_path(w, **vargs) return ("/usr/bin/cvs", 'up', '-p', '-r', vargs['revision'], path) - def _get_name(self, w, **vargs): - return '*CVS:%s-%s' % (w.buffer.name(), vargs['revision']) - - def _execute(self, w, **vargs): - if not hasattr(w.buffer, 'path'): - w.set_error("Buffer has no corresponding file") - return - - cmd = self._get_cmd(w, **vargs) - name = self._get_name(w, **vargs) - mname = w.mode.name.lower() - status, out, err = util.communicate(cmd) - - w.application.data_buffer(name, out, switch_to=True, modename=mname) - -class CvsDateView(CvsRevView): +class CvsDateView(VcDateView): '''show blame output for the current version in CVS''' - args = [arg("date", t=type(""), p="Date: ", h="date specifier")] + args = [arg("date", t=type(""), p="Date: ", h="date specifier")] + namebase = 'CVS' + _is_method = True def _get_cmd(self, w, **vargs): path = self._get_path(w, **vargs) return ("/usr/bin/cvs", 'up', '-p', '-D', vargs['date'], path) - - def _get_name(self, w, **vargs): - return '*CVS:%s-%s' % (w.buffer.name(), vargs['date']) diff --git a/method/svn.py b/method/svn.py index b2ec8f5..da10943 100644 --- a/method/svn.py +++ b/method/svn.py @@ -4,9 +4,9 @@ from subprocess import Popen, PIPE, STDOUT import buffer, default, dirutil, lex, regex, util, window from point import Point import buffer.colors -from method.vc import VcBlame +from method.vc import VcBlame, VcRevView -from method import Method, Argument +from method import Method, Argument, arg if os.system('which svn >/dev/null 2>/dev/null') == 0: has_svn = True @@ -275,3 +275,19 @@ class SvnBlame(VcBlame): def _open_pipe(self, w, **vargs): cmd = ("svn", 'blame', '-v', w.buffer.path) return Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE) + +class SvnBlame2(SvnBlame): + '''show file contents in SVN at revision''' + args = [arg("revision", t=type(""), p="Revision: ", h="revision number")] + def _open_pipe(self, w, **vargs): + cmd = ("svn", 'blame', '-v', '-r', vargs['revision'], w.buffer.path) + return Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE) + +class SvnRevView(VcRevView): + '''show file contents in SVN at date''' + args = [arg("revision", t=type(""), p="Revision: ", h="revision number")] + namebase = 'SVN' + _is_method = True + def _get_cmd(self, w, **vargs): + path = self._get_path(w, **vargs) + return ("svn", 'cat', '-r', vargs['revision'], path) diff --git a/method/vc.py b/method/vc.py index c2ca06a..b6482b5 100644 --- a/method/vc.py +++ b/method/vc.py @@ -1,3 +1,4 @@ +import os from method import Method import buffer.colors import util @@ -68,3 +69,39 @@ class VcBlame(Method): data = ''.join(self._build_lines(groups, gsizes, w, **vargs)) w.application.color_data_buffer("*Blame*", data, switch_to=True) + +class VcRevView(Method): + '''show file contents at revision''' + _is_method = False + namebase = 'VC' + def _get_path(self, w, **vargs): + cwd = os.getcwd() + os.path.sep + path = w.buffer.path + if path.startswith(cwd): + path = path[len(cwd):] + return path + + def _get_cmd(self, w, **vargs): + path = self._get_path(w, **vargs) + raise Exception("unimplemented") + + def _get_name(self, w, **vargs): + return '*%s:%s-%s' % (self.namebase, w.buffer.name(), vargs['revision']) + + def _execute(self, w, **vargs): + if not hasattr(w.buffer, 'path'): + w.set_error("Buffer has no corresponding file") + return + + cmd = self._get_cmd(w, **vargs) + name = self._get_name(w, **vargs) + mname = w.mode.name.lower() + status, out, err = util.communicate(cmd) + + w.application.data_buffer(name, out, switch_to=True, modename=mname) + +class VcDateView(VcRevView): + '''show file contents at date''' + args = [arg("date", t=type(""), p="Date: ", h="date specifier")] + def _get_name(self, w, **vargs): + return '*%s:%s-%s' % (self.namebase, w.buffer.name(), vargs['date']) diff --git a/mode/c.py b/mode/c.py index 92a99e4..fd767f7 100644 --- a/mode/c.py +++ b/mode/c.py @@ -213,7 +213,7 @@ class C(Fundamental): closetokens = ('delimiter',) closetags = {')': '(', ']': '[', '}': '{'} actions = [CCheckSyntax, CMake] - format = "%(flag)s %(bname)s (%(mname)s) %(indent)s %(cursor)s %(perc)s [%(func)s]" + format = "%(flag)s %(bname)s (%(mname)s) %(indent)s %(cursor)s %(perc)s [%(func)s] %(vc-info)s" commentc = '//' colors = { From 55a578a5078bc9f57a8b8768bce1d56378e37892 Mon Sep 17 00:00:00 2001 From: Erik Osheim Date: Tue, 20 Apr 2010 01:38:23 -0400 Subject: [PATCH 4/5] fixed vc bug --HG-- branch : pmacs2 --- method/vc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/method/vc.py b/method/vc.py index b6482b5..8f97a18 100644 --- a/method/vc.py +++ b/method/vc.py @@ -1,5 +1,5 @@ import os -from method import Method +from method import Method, arg import buffer.colors import util import lex From 3fbd26f5d45f253a9e53dc893147a7d902da635a Mon Sep 17 00:00:00 2001 From: Erik Osheim Date: Tue, 20 Apr 2010 01:38:32 -0400 Subject: [PATCH 5/5] fixed comment wrapping in perl --HG-- branch : pmacs2 --- mode/perl.py | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/mode/perl.py b/mode/perl.py index 4bcea25..76b35cd 100644 --- a/mode/perl.py +++ b/mode/perl.py @@ -573,11 +573,6 @@ class PerlWrapParagraph(WrapParagraph): margin = 80 comment_re = re.compile('( *)(#+)( *)(.*)') - def _is_newline(self, t): - return t.name == 'eol' - def _is_space(self, t): - return t.name == 'spaces' - def _detect_line_type(self, w, y): h = w.buffer.highlights[w.mode.name] ltype = None @@ -585,20 +580,13 @@ class PerlWrapParagraph(WrapParagraph): fqname = t.fqname() if fqname == 'spaces' or fqname == 'eol': pass - elif fqname.startswith('comment'): - if ltype and ltype != 'comment': - ltype = None - break - ltype = self.LT_COMMENT - elif fqname.startswith('pod'): - if ltype and ltype != 'pod': - ltype = None - break - ltype = self.LT_POD + elif fqname == 'perl.comment': + return self.LT_COMMENT + elif fqname.startswith('perl.pod'): + return self.LT_POD else: - ltype = None - break - return ltype + return None + return None def _fix_comments(self, c, w): y1 = c.y @@ -613,7 +601,7 @@ class PerlWrapParagraph(WrapParagraph): m = self.comment_re.match(lines[0]) assert m prepend = m.group(1) + m.group(2) - rmargin = self.margin - len(prepend) + rmargin = self.margin - len(prepend) - 1 dpad = m.group(3) segments = [] @@ -648,9 +636,6 @@ class PerlWrapParagraph(WrapParagraph): w.buffer.insert_lines(p1, lines2) w.set_error("wrapped comment lines %d-%d" % (y1 + 1, y2 + 1)) - def _fix_pod(self, c, w): - w.set_error("pod wrapping not yet supported") - def _execute(self, w, **vargs): c = w.logical_cursor() ltype = self._detect_line_type(w, c.y)