pmacs3/mode_perl.py

575 lines
25 KiB
Python

import re, sets, string, sys
import color, commands, default, method, mode2, regex, tab2
from point2 import Point
from lex3 import Grammar, PatternRule, ContextPatternRule, RegionRule, DualRegionRule
from method import Argument, Method
class PodGrammar(Grammar):
rules = [
RegionRule(r'entry', r'(?<=^=head[1-4]) +.*$', Grammar, '^\n$'),
RegionRule(r'entry', r'(?<=^=over) +.*$', Grammar, '^\n$'),
RegionRule(r'entry', r'(?<=^=item) +.*$', Grammar, '^\n$'),
RegionRule(r'entry', r'(?:(?<=^=begin)|(?<=^=end)) +.*$', Grammar, '^\n$'),
RegionRule(r'entry', r'(?<=^=encoding) +.*$', Grammar, '^\n$'),
]
class StringGrammar(Grammar):
rules = [
PatternRule(r'octal', r'\\[0-7]{3}'),
PatternRule(r'escaped', r'\\.'),
PatternRule(r'deref', r"\$+[A-Za-z0-9_](?:[A-Za-z0-9_]|::)*(?:->{\$?(?:[a-zA-Z_][a-zA-Z_0-9]*|'(?:\\.|[^'\\])*'|\"(\\.|[^\\\"])*\")}|->\[\$?[0-9a-zA-Z_]+\])+"),
PatternRule(r'length', r"\$#[A-Za-z0-9_](?:[A-Za-z0-9_]|::)*"),
ContextPatternRule(r'scalar', r"\$[^A-Za-z0-9 %(delim)s](?![A-Za-z0-9_])", r"\$[^A-Za-z0-9 ](?![A-Za-z0-9_])"),
PatternRule(r'scalar', r"\$\$*[A-Za-z0-9_](?:[A-Za-z0-9_]|::)*"),
PatternRule(r'cast', r"[\$\@\%\&]{.*?}"),
PatternRule(r'array', r"@\$*[A-Za-z_](?:[A-Za-z0-9_]|::)*"),
]
class PerlGrammar(Grammar):
rules = [
RegionRule(r'heredoc', r"<<(?P<heredoc>[a-zA-Z0-9_]+) *;", StringGrammar, r'^%(heredoc)s$'),
RegionRule(r'heredoc', r'<< *"(?P<heredoc>[a-zA-Z0-9_]+)" *;', StringGrammar, r'^%(heredoc)s$'),
RegionRule(r'heredoc', r"<< *'(?P<heredoc>[a-zA-Z0-9_]+)' *;", Grammar, r'^%(heredoc)s$'),
RegionRule(r'evaldoc', r"<< *`(?P<heredoc>[a-zA-Z0-9_]+)` *;", StringGrammar, r'^%(heredoc)s$'),
RegionRule(r'endblock', r"^__END__|__DATA__ *$", Grammar, r''),
RegionRule(r'pod', r'^=[a-zA-Z0-9_]+', PodGrammar, r'^=cut'),
PatternRule(r'comment', r'#.*$'),
RegionRule(r'string', r'"', StringGrammar, r'"'),
RegionRule(r'string', r"'", Grammar, r"'"),
RegionRule(r'evalstring', r"`", StringGrammar, r"`"),
PatternRule(r'number', r'0?\.[0-9]+|[0-9]+(?:\.[0-9]+)?'),
PatternRule(r'keyword', r"(?<!->)(?:STDIN|STDERR|STDOUT|continue|do|else|elsif|eval|foreach|for|if|last|my|next|our|package|require|return|sub|undef|unless|until|use|while)(?![a-zA-Z0-9_])"),
PatternRule(r'hash_key', r'(?<={)[A-Za-z0-9_]+(?=})'),
PatternRule(r'hash_key', r'[A-Za-z0-9_]+(?= *=>)'),
PatternRule(r'length', r"\$#[A-Za-z0-9_](?:[A-Za-z0-9_]|::)*"),
PatternRule(r'cast', r'[\$\@\%\^\&](?= *{)'),
PatternRule(r'scalar', r"\$[][><ab/'\"_@\?#\$!%^|&*()](?![A-Za-z0-9_])"),
PatternRule(r'array', r"@_"),
PatternRule(r'function', r"\$\$*[A-Za-z0-9_](?:[A-Za-z0-9_]|::)*(?=-> *\()"),
PatternRule(r'scalar', r"\$\$*[A-Za-z0-9_](?:[A-Za-z0-9_]|::)*"),
PatternRule(r'array', r"@\$*[A-Za-z_](?:[A-Za-z0-9_]|::)*"),
PatternRule(r'hash', r"%\$*[A-Za-z_](?:[A-Za-z0-9_]|::)*"),
PatternRule(r'deref', r"[@%\$&\*](?={)"),
# match regexes
RegionRule(r'match', r'(?:(?<==~)|(?<=!~)|(?<=\()|(?<=split)) *(?P<delim>/)', StringGrammar, r'/[a-z]*'),
RegionRule(r'match', r'm *(?P<delim>[^ #a-zA-Z0-9_])', StringGrammar, r'%(delim)s[a-z]*'),
RegionRule(r'match', r'm(?P<delim>#)', StringGrammar, r'#[a-z]*'),
# replace regexes
DualRegionRule(r'replace', r's *(?P<delim>[^ a-zA-Z0-9_])', StringGrammar, r'%(delim)s', StringGrammar, r'%(delim)s[a-z]*'),
DualRegionRule(r'replace', r's(?P<delim>#)', StringGrammar, r'#', StringGrammar, r'#[a-z]*'),
# translate operator
DualRegionRule(r'translate', r'(?:y|tr) *(?P<delim>[^ a-zA-Z0-9_])', Grammar, r'%(delim)s', Grammar, r'%(delim)s[a-z]*'),
DualRegionRule(r'translate', r'(?:y|tr)#', Grammar, r'#', Grammar, r'#[a-z]*'),
# some more basic stuff
PatternRule(r'package', r"(?<=package )(?:[a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]*"),
PatternRule(r'sub', r"(?<=sub )[a-zA-Z_][a-zA-Z_0-9]*"),
PatternRule(r'use', r"(?<=use )(?:[a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]*"),
PatternRule(r'require', r"(?<=require )(?:[a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]*"),
PatternRule(r'label', r'[a-zA-Z_][a-zA-Z0-9_]*:(?!:)'),
PatternRule(r'method', r"(?<=->)[a-zA-Z_][a-zA-Z_0-9]*"),
PatternRule(r'function', r"&\$*(?:[a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]*"),
PatternRule(r'builtin', r"(?<!->)&?(?:write|warn|wantarray|waitpid|wait|vec|values|utime|use|untie|unshift|unpack|unlink|undef|umask|ucfirst|uc|truncate|times|time|tied|tie|telldir|tell|syswrite|system|sysseek|sysread|sysopen|syscall|symlink|substr|sub|study|stat|srand|sqrt|sprintf|split|splice|sort|socketpair|socket|sleep|sin|shutdown|shmwrite|shmread|shmget|shmctl|shift|setsockopt|setservent|setpwent|setprotoent|setpriority|setpgrp|setnetent|sethostent|setgrent|send|semop|semget|semctl|select|seekdir|seek|scalar|rmdir|rindex|rewinddir|reverse|return|reset|require|rename|ref|redo|recv|readpipe|readlink|readline|readdir|read|rand|quotemeta|push|prototype|printf|print|pos|pop|pipe|package|pack|our|ord|opendir|open|oct|no|next|my|msgsnd|msgrcv|msgget|msgctl|mkdir|map|lstat|log|lock|localtime|local|listen|link|length|lcfirst|lc|last|kill|keys|join|ioctl|int|index|import|hex|grep|goto|gmtime|glob|getsockopt|getsockname|getservent|getservbyport|getservbyname|getpwuid|getpwnam|getpwent|getprotoent|getprotobynumber|getprotobyname|getpriority|getppid|getpgrp|getpeername|getnetent|getnetbyname|getnetbyaddr|getlogin|gethostent|gethostbyname|gethostbyaddr|getgrnam|getgrgid|getgrent|getc|formline|format|fork|flock|fileno|fcntl|exp|exit|exists|exec|eval|eof|endservent|endpwent|endprotoent|endnetent|endhostent|endgrent|each|dump|do|die|delete|defined|dbmopen|dbmclose|crypt|cos|continue|connect|closedir|close|chroot|chr|chown|chop|chomp|chmod|chdir|caller|bless|binmode|bind|atan2|alarm|accept|abs)(?![a-zA-Z0-9_])"),
# quote operator
RegionRule(r'quoted', r'q[rqwx]? *\(', Grammar, r'\)'),
RegionRule(r'quoted', r'q[rqwx]? *{', Grammar, r'}'),
RegionRule(r'quoted', r'q[rqwx]? *<', Grammar, r'>'),
RegionRule(r'quoted', r'q[rqwx]? *\[', Grammar, r'\]'),
RegionRule(r'quoted', r'q[rqwx]? *(?P<delim>[^ #])', Grammar, r'%(delim)s'),
RegionRule(r'quoted', r'q[rqwx]?#', Grammar, r'#'),
PatternRule(r'function', r"(?:[a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]*(?= *\()"),
PatternRule(r'class', r"(?:[a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]*(?=->)"),
# some basic stuff
PatternRule(r'delimiter', r"[,;=\?(){}\[\]]|->|=>|(?<!:):(?!=:)"),
PatternRule(r'operator', r"\+=|-=|\*=|/=|//=|%=|&=\|\^=|>>=|<<=|\*\*="),
PatternRule(r'operator', r"\+\+|\+|<=>|<>|<<|<=|<|-|>>|>=|>|\*\*|\*|&&|&|\|\||\||/|\^|==|//|~|=~|!~|!=|%|!|\.|x(?![a-zA-Z_])"),
PatternRule(r'noperator', r"(?:xor|or|not|ne|lt|le|gt|ge|eq|cmp|and)(?![a-zA-Z_])"),
PatternRule(r'bareword', r'(?:[a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]*'),
PatternRule(r"eol", r"\n$"),
]
class PerlTabber(tab2.StackTabber):
def is_base(self, y):
if y == 0:
return True
highlighter = self.mode.window.buffer.highlights[self.mode.name()]
if not highlighter.tokens[y]:
return False
t = highlighter.tokens[y][0]
return t.name == 'keyword' and t.string == 'sub'
def _handle_open_token(self, currlvl, y, i):
currlvl = tab2.StackTabber._handle_open_token(self, currlvl, y, i)
return currlvl
def _handle_close_token(self, currlvl, y, i):
self._opt_pop('cont')
currlvl = tab2.StackTabber._handle_close_token(self, currlvl, y, i)
token = self.get_token(y, i)
if self.is_rightmost_token(y, i):
if token.string == '}':
self._opt_pop('cont')
else:
self._opt_append('cont', currlvl + 4)
return currlvl
def _handle_other_token(self, currlvl, y, i):
token = self.get_token(y, i)
fqname = token.fqname()
if fqname == 'delimiter' and token.string == ';':
self._opt_pop('cont')
elif fqname == 'heredoc.start':
self._opt_append('heredoc', None)
elif fqname == 'heredoc.end':
self._opt_pop('heredoc')
self._opt_pop('cont')
elif fqname == 'evaldoc.start':
self._opt_append('evaldoc', None)
elif fqname == 'evaldoc.end':
self._opt_pop('evaldoc')
self._opt_pop('cont')
elif fqname == 'pod.start':
self._opt_append('pod', None)
elif fqname == 'pod.end':
self._opt_pop('pod')
currlvl = 0
elif fqname == 'string.start':
self._opt_append('string', None)
elif fqname == 'string.end':
self._opt_pop('string')
if self.is_rightmost_token(y, i):
self._opt_append('cont', currlvl + 4)
if self.is_rightmost_token(y, i):
if(not fqname.startswith('pod') and
not fqname.startswith('heredoc') and
not fqname.startswith('string') and
not fqname.startswith('endblock') and
not fqname == 'comment' and
not fqname == 'null' and
token.string not in ('}', ';', '(', '{', '[', ',')):
self._opt_append('cont', currlvl + 4)
return currlvl
class Perl(mode2.Fundamental):
tabbercls = PerlTabber
grammar = PerlGrammar
opentokens = ('delimiter',)
opentags = {'(': ')', '[': ']', '{': '}'}
closetokens = ('delimiter',)
closetags = {')': '(', ']': '[', '}': '{'}
def __init__(self, w):
mode2.Fundamental.__init__(self, w)
self.add_action_and_bindings(PerlSetLib(), ('C-c l',))
self.add_action_and_bindings(PerlCheckSyntax(), ('C-c s',))
self.add_action_and_bindings(PerlHashCleanup(), ('C-c h',))
#self.add_action_and_bindings(PerlHashCleanup2(), ('C-c h',))
self.add_action_and_bindings(PerlViewModulePerldoc(), ('C-c v',))
self.add_action_and_bindings(PerlViewWordPerldoc(), ('C-c p',))
self.add_action_and_bindings(PerlWrapLine(), ('M-q',))
self.add_action_and_bindings(PerlGotoFunction(), ('C-c M-g',))
self.add_action_and_bindings(PerlWhichFunction(), ('C-c w',))
self.add_action_and_bindings(PerlListFunctions(), ('C-c W',))
# visual tag matching
self.add_bindings('close-paren', (')'))
self.add_bindings('close-bracket', (']'))
self.add_bindings('close-brace', ('}'))
self.colors = {
# basic stuff
'escaped': color.build('magenta', 'default'),
'null': color.build('default', 'default'),
'delimiter': color.build('default', 'default'),
'sub': color.build('cyan', 'default'),
'number': color.build('default', 'default'),
'operator': color.build('default', 'default'),
'noperator': color.build('magenta', 'default'),
'endblock': color.build('red', 'default'),
'keyword': color.build('magenta', 'default'),
'cast': color.build('yellow', 'default'),
'scalar': color.build('yellow', 'default'),
'array': color.build('yellow', 'default'),
'deref': color.build('yellow', 'default'),
'hash': color.build('yellow', 'default'),
'hash_key': color.build('green', 'default'),
'comment': color.build('red', 'default'),
'function': color.build('cyan', 'default'),
'builtin': color.build('magenta', 'default'),
'method': color.build('cyan', 'default'),
'bareword': color.build('default', 'default'),
'label': color.build('cyan', 'default'),
'package': color.build('cyan', 'default'),
'class': color.build('cyan', 'default'),
'use': color.build('cyan', 'default'),
'require': color.build('cyan', 'default'),
'method': color.build('cyan', 'default'),
# heredoc/evaldoc
'heredoc.start': color.build('green', 'default'),
'heredoc.null': color.build('green', 'default'),
'heredoc.end': color.build('green', 'default'),
'evaldoc.start': color.build('cyan', 'default'),
'evaldoc.null': color.build('cyan', 'default'),
'evaldoc.end': color.build('cyan', 'default'),
# pod
'pod.start': color.build('red', 'default'),
'pod.null': color.build('red', 'default'),
'pod.entry.start': color.build('magenta', 'default'),
'pod.entry.null': color.build('magenta', 'default'),
'pod.entry.end': color.build('magenta', 'default'),
'pod.end': color.build('red', 'default'),
# strings
'string.start': color.build('green', 'default'),
'string.null': color.build('green', 'default'),
'string.escaped': color.build('magenta', 'default'),
'string.deref': color.build('yellow', 'default'),
'string.end': color.build('green', 'default'),
# `` strings
'evalstring.start': color.build('cyan', 'default'),
'evalstring.null': color.build('cyan', 'default'),
'evalstring.escaped': color.build('magenta', 'default'),
'evalstring.deref': color.build('yellow', 'default'),
'evalstring.end': color.build('cyan', 'default'),
# quoted region
'quoted': color.build('cyan', 'default'),
'quoted.start': color.build('cyan', 'default'),
'quoted.null': color.build('cyan', 'default'),
'quoted.end': color.build('cyan', 'default'),
# match regex
'match.start': color.build('cyan', 'default'),
'match.end': color.build('cyan', 'default'),
'match.null': color.build('cyan', 'default'),
# replace regex
'replace.start': color.build('cyan', 'default'),
'replace.middle': color.build('cyan', 'default'),
'replace.end': color.build('cyan', 'default'),
'replace.null': color.build('cyan', 'default'),
'replace.escaped': color.build('magenta', 'default'),
'replace.deref': color.build('yellow', 'default'),
'replace.length': color.build('yellow', 'default'),
'replace.scalar': color.build('yellow', 'default'),
'replace.hash': color.build('yellow', 'default'),
'replace.cast': color.build('yellow', 'default'),
# translate regex
'translate.start': color.build('magenta', 'default'),
'translate.middle': color.build('magenta', 'default'),
'translate.end': color.build('magenta', 'default'),
'translate.null': color.build('magenta', 'default'),
}
# perl-specific
self.functions = None
self.perllib = 'lib'
def name(self):
return "Perl"
def build_function_map(self):
b = self.window.buffer
self.functions = {}
for i in range(0, len(b.lines)):
m = regex.perl_function.match(b.lines[i])
if m:
self.functions[m.group(1)] = i
def get_functions(self):
if self.functions is None:
self.build_function_map()
return self.functions
def get_function_names(self):
functions = self.get_functions()
pairs = [[functions[key], key] for key in functions]
pairs.sort()
names = [x[1] for x in pairs]
return names
class PerlSetLib(Method):
'''Set the path(s) to find perl modules'''
args = [Argument("lib", type=type(""), prompt="Location of lib: ",
default=default.build_constant("."))]
def _execute(self, w, **vargs):
w.mode.perllib = vargs['lib']
class PerlCheckSyntax(Method):
'''Check the syntax of a perl file'''
def _execute(self, w, **vargs):
app = w.application
cmd = "perl -c -I '%s' '%s'" % (w.mode.perllib, w.buffer.path)
(status, output) = commands.getstatusoutput(cmd)
if status == 0:
app.set_error("Syntax OK")
app.data_buffer("*Perl-Check-Syntax*", output, switch_to=False)
else:
app.data_buffer("*Perl-Check-Syntax*", output)
class PerlViewModulePerldoc(Method):
'''View documentation about this file using perldoc'''
def _execute(self, w, **vargs):
cmd = "perldoc -t -T '%s'" % w.buffer.path
(status, output) = commands.getstatusoutput(cmd)
w.application.data_buffer("*Perldoc*", output, switch_to=True)
class PerlViewWordPerldoc(Method):
'''View documentation about a package or function using perldoc'''
def _try(self, w, word, asfunc=False):
if asfunc:
cmd = "PERL5LIB=%r perldoc -t -T -f '%s'" % (w.mode.perllib, word)
else:
cmd = "PERL5LIB=%r perldoc -t -T '%s'" % (w.mode.perllib, word)
(status, data) = commands.getstatusoutput(cmd)
if status == 0:
return data
else:
return None
def _show(self, w, data, word):
w.application.data_buffer("*Perldoc*", data, switch_to=True)
w.application.set_error('displaying documentation for %r' % word)
def _execute(self, w, **vargs):
token = w.get_token()
#word = w.get_word(wl=string.letters + string.digits + '_:')
word = token.string
# make sure that the name is (mostly) valid
if word is None:
w.application.set_error('no word selected')
return
elif ':' in word and '::' not in word:
w.application.set_error('invalid word: %r' % word)
return
# first try it is a package
parts = word.split('::')
while len(parts) > 0:
newword = '::'.join(parts)
data = self._try(w, newword, asfunc=False)
if data:
self._show(w, data, newword)
return
parts.pop(-1)
# then try it as a function
data = self._try(w, word, asfunc=True)
if data:
self._show(w, data, word)
else:
w.application.set_error('nothing found for %r' % word)
class PerlGotoFunction(Method):
'''Jump to a function defined in this module'''
args = [Argument("name", type(""), "perlfunction", "Goto Function: ")]
def _execute(self, w, **vargs):
name = vargs['name']
functions = w.mode.get_functions()
if name in functions:
w.goto(Point(0, functions[name]))
else:
w.application.set_error("Function %r was not found" % name)
class PerlListFunctions(Method):
'''Show the user all functions defined in this module'''
def _execute(self, w, **vargs):
names = w.mode.get_function_names()
output = "\n".join(names) + "\n"
w.application.data_buffer("*Perl-List-Functions*", output, switch_to=True)
class PerlWhichFunction(Method):
'''Show the user what function they are in'''
def _execute(self, w, **vargs):
cursor = w.logical_cursor()
i = cursor.y
name = None
while i >= 0 and name is None:
line = w.buffer.lines[i]
m = regex.perl_function.match(line)
if m:
name = m.group(1)
else:
i -= 1
if name is None:
w.application.set_error("None");
else:
w.application.set_error("line %d: %s" % (i, name))
class PerlHashCleanup(Method):
'''Correctly align assignment blocks and literal hashes'''
def _execute(self, window, **vargs):
cursor = window.logical_cursor()
b = window.buffer
# so this is where we will store the groups that we find
groups_by_line = {}
# the regex we will try
regexes = [regex.perl_hash_cleanup,
regex.perl_assign_cleanup]
# if we aren't in a hash, inform the user and exit
line = b.lines[cursor.y]
myregex = None
for r in regexes:
if r.match(line):
myregex = r
if myregex is None:
raise Exception, "Not a perl hash line"
groups_by_line[cursor.y] = myregex.match(line).groups()
# find the beginning of this hash block
start = 0
i = cursor.y - 1
while i >= 0:
line = b.lines[i]
m = myregex.match(line)
if not m:
start = i + 1
break
else:
groups_by_line[i] = m.groups()
i -= 1
# find the end of this hash block
end = len(b.lines) - 1
i = cursor.y + 1
while i < len(b.lines):
line = b.lines[i]
m = myregex.match(line)
if not m:
end = i - 1
break
else:
groups_by_line[i] = m.groups()
i += 1
# assume that the least indented line is correct
indent_w = min([len(groups_by_line[k][0]) for k in groups_by_line])
# find the longest hash key to base all the other padding on
key_w = max([len(groups_by_line[k][1]) for k in groups_by_line])
# for each line, format it correctly
keys = groups_by_line.keys()
keys.sort()
data = ''
for i in keys:
indent_pad = ' ' * indent_w
key = groups_by_line[i][1]
sep = groups_by_line[i][3]
value = groups_by_line[i][5]
key_pad = ' ' * (key_w - len(key))
data += indent_pad + key + key_pad + ' ' + sep + ' ' + value + '\n'
# remove the old text and add the new
start_p = Point(0, start)
end_p = Point(0, end + 1)
window.kill(start_p, end_p)
window.insert_string(start_p, data)
class PerlWrapLine(Method):
'''Wrap Comments and POD'''
margin = 80
comment_re = re.compile('(#+)( *)(.*)')
def _is_newline(self, t):
return t.name == 'eol'
def _is_space(self, t):
return t.name == 'null' and regex.space.match(t.string)
def _detect_line_type(self, w, y):
c = w.logical_cursor()
highlighter = w.buffer.highlights[w.mode.name()]
ltype = None
for t in highlighter.tokens[c.y]:
if self._is_space(t):
pass
elif t.name == 'comment':
if ltype:
return None
else:
ltype = 'comment'
elif t.name == 'eol':
return ltype
else:
return None
def _execute(self, w, **vargs):
c = w.logical_cursor()
ltype = self._detect_line_type(w, c.y)
if ltype == 'comment':
return self._fix_comments(c, w)
elif ltype == 'pod':
return self._fix_pod(c, w)
else:
w.set_error("did not detect comment or pod lines")
return
def _fix_comments(self, c, w):
w.set_error("comment!")
def _fix_pod(self, c, w):
pass
#class PerlWrapLine(Method):
# '''Wrap lines, comments, POD'''
# margin = 80
# comment_re = re.compile('^( *)(#+)( *)([^ ].*)$')
# def _execute(self, w, **vargs):
# pcursor = w.physical_cursor()
# r = w.get_region(pcursor)
# if r is None:
# return
#
# t = r[4]
# if t == 'pod':
# assert False, 'POD: %s' % repr(r)
# elif t == 'comment':
# self._wrap_comment(w)
# else:
# return
#
# def _wrap_comment(self, w):
# l = w.logical_cursor()
# m = self.comment_re.match(w.buffer.lines[l.y])
# if not m:
# assert False, 'no match oh geez'
#
# pad = m.group(1) + m.group(2) + m.group(3)
# data = m.group(4) + ' '
#
# start = l.y
# end = l.y + 1
#
# while end < len(w.buffer.lines):
# m = self.comment_re.match(w.buffer.lines[end])
# if m:
# data += m.group(4) + ' '
# end += 1
# else:
# break
#
# words = [word for word in data.split() if word]
#
# lines = [pad]
# for word in words:
# if len(lines[-1]) == len(pad):
# lines[-1] += word
# elif len(lines[-1]) + 1 + len(word) <= self.margin:
# lines[-1] += ' ' + word
# else:
# lines.append(pad + word)
#
# # remove the old text and add the new
# start_p = Point(0, start)
# end_p = Point(len(w.buffer.lines[end-1]), end-1)
# w.kill(start_p, end_p)
# w.insert(start_p, '\n'.join(lines))