lots of fixes/improvements

--HG--
branch : pmacs2
This commit is contained in:
moculus 2007-06-22 16:38:35 +00:00
parent 733dba7274
commit 975b3665d9
4 changed files with 264 additions and 238 deletions

View File

@ -14,6 +14,7 @@ use strict;
use warnings; use warnings;
use DBI; use DBI;
use Carp;
use TBB::ID; use TBB::ID;

View File

@ -79,8 +79,6 @@ class PerlGrammar(Grammar):
PatternRule(name=r'method', pattern=r"(?<=->)[a-zA-Z_][a-zA-Z_0-9]*"), PatternRule(name=r'method', pattern=r"(?<=->)[a-zA-Z_][a-zA-Z_0-9]*"),
PatternRule(name=r'function', pattern=r"&\$*(?:[a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]*"), PatternRule(name=r'function', pattern=r"&\$*(?:[a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]*"),
PatternRule(name=r'builtin', pattern=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_])"), PatternRule(name=r'builtin', pattern=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_])"),
PatternRule(name=r'function', pattern=r"(?:[a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]*(?= *\()"),
PatternRule(name=r'class', pattern=r"(?:[a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]*(?=->)"),
# quote operator # quote operator
RegionRule(name=r'quoted', start=r'q[rqwx]? *\(', grammar=g, end=r'\)'), RegionRule(name=r'quoted', start=r'q[rqwx]? *\(', grammar=g, end=r'\)'),
@ -90,6 +88,9 @@ class PerlGrammar(Grammar):
RegionRule(name=r'quoted', start=r'q[rqwx]? *(?P<delim>[^ #])', grammar=g, end=r'%(delim)s'), RegionRule(name=r'quoted', start=r'q[rqwx]? *(?P<delim>[^ #])', grammar=g, end=r'%(delim)s'),
RegionRule(name=r'quoted', start=r'q[rqwx]?#', grammar=g, end=r'#'), RegionRule(name=r'quoted', start=r'q[rqwx]?#', grammar=g, end=r'#'),
PatternRule(name=r'function', pattern=r"(?:[a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]*(?= *\()"),
PatternRule(name=r'class', pattern=r"(?:[a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]*(?=->)"),
# nested regions # nested regions
#RegionRule(name=r'paren', start=r'\(', grammar=None, end=r'\)'), #RegionRule(name=r'paren', start=r'\(', grammar=None, end=r'\)'),
#RegionRule(name=r'brace', start=r'{', grammar=None, end=r'}'), #RegionRule(name=r'brace', start=r'{', grammar=None, end=r'}'),
@ -169,12 +170,13 @@ class Perl(mode2.Fundamental):
def __init__(self, w): def __init__(self, w):
mode2.Fundamental.__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(PerlCheckSyntax(), ('C-c s',))
self.add_action_and_bindings(PerlHashCleanup(), ('C-c h',)) self.add_action_and_bindings(PerlHashCleanup(), ('C-c h',))
#self.add_action_and_bindings(PerlHashCleanup2(), ('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(PerlViewModulePerldoc(), ('C-c v',))
self.add_action_and_bindings(PerlViewWordPerldoc(), ('C-c p',)) self.add_action_and_bindings(PerlViewWordPerldoc(), ('C-c p',))
self.add_action_and_bindings(PerlWrapLine(), ('M-q',)) #self.add_action_and_bindings(PerlWrapLine(), ('M-q',))
self.add_action_and_bindings(PerlGotoFunction(), ('C-c M-g',)) self.add_action_and_bindings(PerlGotoFunction(), ('C-c M-g',))
self.add_action_and_bindings(PerlWhichFunction(), ('C-c w',)) self.add_action_and_bindings(PerlWhichFunction(), ('C-c w',))
self.add_action_and_bindings(PerlListFunctions(), ('C-c W',)) self.add_action_and_bindings(PerlListFunctions(), ('C-c W',))
@ -280,6 +282,10 @@ class Perl(mode2.Fundamental):
'translate.null': color.build('magenta', 'default'), 'translate.null': color.build('magenta', 'default'),
} }
# perl-specific
self.functions = None
self.perllib = 'lib'
def name(self): def name(self):
return "Perl" return "Perl"
@ -290,12 +296,10 @@ class Perl(mode2.Fundamental):
m = regex.perl_function.match(b.lines[i]) m = regex.perl_function.match(b.lines[i])
if m: if m:
self.functions[m.group(1)] = i self.functions[m.group(1)] = i
def get_functions(self): def get_functions(self):
if self.functions is None: if self.functions is None:
self.build_function_map() self.build_function_map()
return self.functions return self.functions
def get_function_names(self): def get_function_names(self):
functions = self.get_functions() functions = self.get_functions()
pairs = [[functions[key], key] for key in functions] pairs = [[functions[key], key] for key in functions]
@ -303,75 +307,25 @@ class Perl(mode2.Fundamental):
names = [x[1] for x in pairs] names = [x[1] for x in pairs]
return names return names
class PerlWrapLine(method.Method): class PerlSetLib(method.Method):
'''Wrap lines, comments, POD''' '''Set the path(s) to find perl modules'''
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))
class PerlCheckSyntax(method.Method):
'''Check the syntax of a perl file'''
def _args(self): def _args(self):
return [method.Argument("lib", type=type(""), prompt="Location of lib: ", return [method.Argument("lib", type=type(""), prompt="Location of lib: ",
default=default.build_constant("."))] default=default.build_constant("."))]
def _execute(self, window, **vargs): def _execute(self, w, **vargs):
a = vargs['lib'] w.mode.perllib = vargs['lib']
cmd = "perl -c -I '%s' '%s'" % (a, window.buffer.path)
class PerlCheckSyntax(method.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) (status, output) = commands.getstatusoutput(cmd)
if status == 0: if status == 0:
window.application.set_error("Syntax OK") app.set_error("Syntax OK")
window.application.data_buffer("*Perl-Check-Syntax*", output, switch_to=False) app.data_buffer("*Perl-Check-Syntax*", output, switch_to=False)
else: else:
window.application.data_buffer("*Perl-Check-Syntax*", output) app.data_buffer("*Perl-Check-Syntax*", output)
class PerlViewModulePerldoc(method.Method): class PerlViewModulePerldoc(method.Method):
'''View documentation about this file using perldoc''' '''View documentation about this file using perldoc'''
@ -382,65 +336,46 @@ class PerlViewModulePerldoc(method.Method):
class PerlViewWordPerldoc(method.Method): class PerlViewWordPerldoc(method.Method):
'''View documentation about a package or function using perldoc''' '''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): def _execute(self, w, **vargs):
cursor = w.logical_cursor() word = w.get_word(wl=string.letters + string.digits + '_:')
line = w.buffer.lines[cursor.y]
word_chars = string.letters + string.digits + '_:' # make sure that the name is (mostly) valid
if word is None:
if line[cursor.x] not in word_chars: w.application.set_error('no word selected')
w.application.set_error('error: no word selected')
return return
elif ':' in word and '::' not in word:
start = cursor.x
while start > 0 and line[start - 1] in word_chars:
start -= 1
end = cursor.x + 1
while end < len(line) - 1 and line[end] in word_chars:
end += 1
word = line[start:end]
w.application.set_error('the current word is: %r' % word)
ok = False
data = ''
perl_word_re = re.compile('^[a-zA-Z_][a-zA-Z_0-9]*(?:::[a-zA-Z_][a-zA-Z0-9]*)*$')
if not perl_word_re.match(word):
w.application.set_error('invalid word: %r' % word) w.application.set_error('invalid word: %r' % word)
return return
if '::' in word: # first try it is a package
# we are probably dealing with a package parts = word.split('::')
parts = word.split('::') while len(parts) > 0:
while len(parts) > 0: newword = '::'.join(parts)
newword = '::'.join(parts) data = self._try(w, newword, asfunc=False)
cmd = "perldoc -t -T '%s'" % newword if data:
(status, data) = commands.getstatusoutput(cmd) self._show(w, data, newword)
if status == 0: return
word = newword parts.pop(-1)
ok = True
break
parts.pop(-1)
elif ':' in word:
w.application.set_error('invalid word2222: %r' % word)
return
else:
cmd = "perldoc -t -T -f '%s'" % word
(status, data) = commands.getstatusoutput(cmd)
if status == 0:
ok = True
else:
cmd = "perldoc -t -T -f '%s'" % word
(status, data) = commands.getstatusoutput(cmd)
ok = status == 0
if not ok: # then try it as a function
w.application.set_error('nothing found for %r' % word) data = self._try(w, word, asfunc=True)
if data:
self._show(w, data, parts[0])
else: else:
w.application.data_buffer("*Perldoc*", data, switch_to=True) w.application.set_error('nothing found for %r' % word)
w.application.set_error('displaying documentation for %r' % word)
class PerlGotoFunction(method.Method): class PerlGotoFunction(method.Method):
'''Jump to a function defined in this module''' '''Jump to a function defined in this module'''
@ -557,103 +492,57 @@ class PerlHashCleanup(method.Method):
window.kill(start_p, end_p) window.kill(start_p, end_p)
window.insert_string(start_p, data) window.insert_string(start_p, data)
class PerlHashCleanup2(method.Method): #class PerlWrapLine(method.Method):
'''Correctly align assignment blocks and literal hashes''' # '''Wrap lines, comments, POD'''
def process_line2(self, line_regions, sep=None, indent=None): # margin = 80
(pre_toks, sep_tok, post_toks) = ([], None, []) # comment_re = re.compile('^( *)(#+)( *)([^ ].*)$')
ok = False # def _execute(self, w, **vargs):
before = True # pcursor = w.physical_cursor()
for r in line_regions: # r = w.get_region(pcursor)
(start, end, attr, s, name) = r # if r is None:
if name == "": # return
continue #
elif before: # t = r[4]
if len(pre_toks) == 0: # if t == 'pod':
pre_toks.append(r) # assert False, 'POD: %s' % repr(r)
elif (name == "delimiter" and s == sep or # elif t == 'comment':
(sep is None and (s == "=" or s == "=>"))): # self._wrap_comment(w)
sep_tok = r # else:
before = False # return
else: #
pre_toks.append(r) # def _wrap_comment(self, w):
else: # l = w.logical_cursor()
post_toks.append(r) # m = self.comment_re.match(w.buffer.lines[l.y])
ok = True # if not m:
# assert False, 'no match oh geez'
if ok: #
return (True, sep_tok[3], (pre_toks, sep_tok, post_toks)) # pad = m.group(1) + m.group(2) + m.group(3)
else: # data = m.group(4) + ' '
return (False, "", ([], None, [])) #
# start = l.y
def _execute(self, w, **vargs): # end = l.y + 1
cursor = w.logical_cursor() #
b = w.buffer # while end < len(w.buffer.lines):
# m = self.comment_re.match(w.buffer.lines[end])
# so this is where we will store the groups that we find # if m:
groups_by_line = {} # data += m.group(4) + ' '
# end += 1
all_regions = w.mode.get_regions() # else:
line_regions = all_regions[cursor.y] # break
(ok, sep, group) = self.process_line2(line_regions) #
# words = [word for word in data.split() if word]
if not ok: #
raise Exception, "Not a perl hash line" # lines = [pad]
groups_by_line[cursor.y] = group # for word in words:
# if len(lines[-1]) == len(pad):
# find the beginning of this hash block # lines[-1] += word
start = cursor.y # elif len(lines[-1]) + 1 + len(word) <= self.margin:
while start >= 0: # lines[-1] += ' ' + word
(ok2, sep2, group2) = self.process_line2(all_regions[start - 1], sep) # else:
if not ok2: # lines.append(pad + word)
break #
start -= 1 # # remove the old text and add the new
groups_by_line[start] = group2 # start_p = Point(0, start)
# end_p = Point(len(w.buffer.lines[end-1]), end-1)
# find the end of this hash block # w.kill(start_p, end_p)
end = cursor.y # w.insert(start_p, '\n'.join(lines))
while end < len(b.lines) - 1:
(ok2, sep2, group2) = self.process_line2(all_regions[end + 1], sep)
if not ok2:
break
end += 1
groups_by_line[end] = group2
# find the minimum indented line
indent_w = None
for k in groups_by_line:
x = groups_by_line[k][0][0].start
if indent_w is None or x < indent_w:
indent_w = x
# find the max key length
key_w = None
for k in groups_by_line:
x = groups_by_line[k][0][-1].end - groups_by_line[k][0][0].start
if key_w is None or x > key_w:
key_w = x
# for each line, format it correctly
keys = groups_by_line.keys()
keys.sort()
data = ''
for i in keys:
line = ' ' * indent_w
l = groups_by_line[i][0][0].start
for t in groups_by_line[i][0]:
line += ' ' * max(0, t.start - l)
line += t.value
l = t.end
line += ' ' * max(0, key_w - l + groups_by_line[i][0][0].start)
line += ' ' + groups_by_line[i][1].value + ' '
l = groups_by_line[i][2][0].start
for t in groups_by_line[i][2]:
line += ' ' * max(0, t.start - l)
line += t.value
l = t.end
data += line + '\n'
# remove the old text and add the new
start_p = Point(0, start)
end_p = Point(0, end + 1)
w.kill(start_p, end_p)
w.insert(start_p, data)

View File

@ -120,8 +120,142 @@ class PythonGrammar(Grammar):
), ),
] ]
class PythonTabber(tab2.StackTabber): class PythonTabber(tab2.Tabber):
pass start_tags = {'(': ')',
'{': '}',
'[': ']'}
close_tags = {')': '(',
'}': '{',
']': '['}
def __init__(self, m):
tab2.Tabber.__init__(self, m)
def stack_append(self, item):
self.tab_stack.append(item)
def stack_pop(self):
self.tab_stack.pop(-1)
def base_indentation_level(self, y):
return y == 0
def calculate_tabs(self, start=0, goal=None):
lines = self.mode.window.buffer.lines
tokens = self.mode.highlighter.tokens
buffer = self.mode.window.buffer
if self.levels is None:
self.levels = [None] * (len(lines))
self.index = 0
self.y = start
self.base = 0
self.tab_stack = []
# we want to process every logical line in the file
while self.y < len(lines):
line = lines[self.y]
start_index = self.index
start_point = point.Point(0, self.y)
start_offset = buffer.get_point_offset(start_point)
end_point = point.Point(len(line), self.y)
end_offset = buffer.get_point_offset(end_point)
# we want to find all the tokens on the line we are currently processing
while self.index < len(tokens):
token = tokens[self.index]
if token.end > end_offset:
break
self.index += 1
self.handle_line(line,
start_offset, start_index,
end_offset, self.index)
self.levels[self.y] = self.line_depth
self.y += 1
if goal is not None and self.y > goal:
break
def get_line_depth(self):
if len(self.tab_stack) > 0:
return self.tab_stack[-1][1]
else:
return self.base
def handle_line(self, line, start_offset, start_index, end_offset, end_index):
self.line_depth = self.get_line_depth()
tokens = self.mode.highlighter.tokens
if start_index >= len(tokens):
return
if regex.whitespace.match(line):
return
if len(self.tab_stack) == 0 and tokens[start_index].start >= start_offset:
self.base = util.count_leading_whitespace(line)
for i in range(start_index, end_index):
token = tokens[i]
s = token.string
if s in self.start_tags:
if i < end_index - 1:
i = tokens[i+1].start - start_offset
elif len(self.tab_stack) > 0:
i = self.tab_stack[-1][1] + 4
else:
i = self.base + 4
self.stack_append((s, i))
elif s in self.close_tags:
assert len(self.tab_stack), "Unbalanced closing tag"
assert self.tab_stack[-1][0] == self.close_tags[s], "Unmatched closing tag"
self.stack_pop()
if i == start_index:
self.line_depth = self.get_line_depth()
if tokens[start_index].start < start_offset:
self.line_depth = -1
prebase = self.base
s = tokens[start_index].string
e = tokens[end_index-1].string
if s == "except" or s == "elif" or s == "else":
if self.y > 0 and self.line_depth == self.levels[self.y - 1]:
self.line_depth = max(0, self.line_depth - 4)
elif (s == "return" or s == "raise" or s == "yield" or s == "break" or
s == "pass" or s == 'continue'):
self.base = max(0, self.base - 4)
if e == "\\":
if len(self.tab_stack) and self.tab_stack[-1][0] == "\\":
pass
else:
self.stack_append(("\\", prebase + 4))
return
elif e == ":":
self.base += 4
elif len(self.tab_stack) and self.tab_stack[-1][0] == "\\":
self.stack_pop()
def get_indentation_level(self, y):
if self.levels is not None and self.levels[y] is not None:
result = self.levels[y]
else:
i = max(0, y - 1)
while i > 0:
if self.base_indentation_level(i):
break
i -= 1
self.calculate_tabs(i, y)
result = self.levels[y]
if result == -1:
return None
return result
class Python(mode2.Fundamental): class Python(mode2.Fundamental):
tabbercls = PythonTabber tabbercls = PythonTabber

View File

@ -2,7 +2,8 @@ import os.path, string
import regex import regex
from point2 import Point from point2 import Point
WORD_LETTERS = list(string.letters + string.digits) #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 # 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 # character it highlights. to this end, it needs to be able to highlight behind
@ -294,26 +295,27 @@ class Window(object):
p = self.find_right_word() p = self.find_right_word()
if p is not None: if p is not None:
self.goto(p) self.goto(p)
def get_word_bounds_at_point(self, p): def get_word_bounds_at_point(self, p, wl=WORD_LETTERS):
if len(self.buffer.lines[p.y]) == 0: if len(self.buffer.lines[p.y]) == 0:
return return None
elif p.x == 0: elif self.cursor_char() not in wl:
p1 = self.find_left_word(Point(p.x + 1, p.y)) return None
p2 = self.find_right_word() x1 = x2 = p.x
else: while x1 > 0 and self.xy_char(x1 - 1, p.y) in wl:
p1 = self.find_left_word() x1 -= 1
p2 = self.find_right_word(Point(p.x - 1, p.y)) while x2 < len(self.buffer.lines[p.y]) and self.xy_char(x2, p.y) in wl:
return (p1, p2) x2 += 1
def get_word_at_point(self, p): return (Point(x1, p.y), Point(x2, p.y))
bounds = self.get_word_bounds_at_point(p) def get_word_at_point(self, p, wl=WORD_LETTERS):
bounds = self.get_word_bounds_at_point(p, wl)
if bounds is None: if bounds is None:
return None return None
else: else:
return self.buffer.get_substring(bounds[0], bounds[1]) return self.buffer.get_substring(bounds[0], bounds[1])
def get_word_bounds(self): def get_word_bounds(self, wl=WORD_LETTERS):
return self.get_word_bounds_at_point(self.logical_cursor()) return self.get_word_bounds_at_point(self.logical_cursor(), wl)
def get_word(self): def get_word(self, wl=WORD_LETTERS):
return self.get_word_at_point(self.logical_cursor()) return self.get_word_at_point(self.logical_cursor(), wl)
# page up/down # page up/down
def _pshift_up(self, p, num): def _pshift_up(self, p, num):
@ -496,7 +498,7 @@ class Window(object):
# querying # querying
def cursor_char(self): def cursor_char(self):
self.point_char(self.logical_cursor()) return self.point_char(self.logical_cursor())
def point_char(self, p): def point_char(self, p):
return self.xy_char(p.x, p.y) return self.xy_char(p.x, p.y)
def xy_char(self, x, y): def xy_char(self, x, y):