2008-11-08 10:30:04 -05:00
|
|
|
import os, commands, re, tempfile
|
2008-03-16 16:08:37 -04:00
|
|
|
from subprocess import Popen, PIPE, STDOUT
|
|
|
|
|
2008-11-08 11:18:48 -05:00
|
|
|
import buffer, completer, default, dirutil, regex, util, window
|
2007-10-21 20:50:11 -04:00
|
|
|
from point import Point
|
2007-03-06 10:05:38 -05:00
|
|
|
|
2007-07-02 20:29:27 -04:00
|
|
|
class MethodError(Exception):
|
|
|
|
pass
|
|
|
|
|
2008-03-18 10:51:47 -04:00
|
|
|
def arg(n, t=type(''), dt=None, p=None, h='', dv=default.none, ld=False):
|
|
|
|
'''convenience function for arguments'''
|
2009-03-21 15:47:12 -04:00
|
|
|
return Argument(n, type=t, datatype=dt, prompt=p, help=h, default=dv, load_default=ld)
|
2008-03-14 17:17:04 -04:00
|
|
|
class Argument(object):
|
2008-03-18 10:51:47 -04:00
|
|
|
def __init__(self, name, type=type(""), datatype=None, prompt=None, help='',
|
2007-03-06 10:05:38 -05:00
|
|
|
default=default.none, load_default=False):
|
|
|
|
self.name = name
|
2007-06-17 22:14:07 -04:00
|
|
|
self.type = type
|
2007-03-06 10:05:38 -05:00
|
|
|
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:
|
2007-10-15 15:35:06 -04:00
|
|
|
return int(value, 0)
|
2007-03-06 10:05:38 -05:00
|
|
|
except:
|
|
|
|
raise Exception, "expected int; got %s" % (repr(value))
|
|
|
|
else:
|
|
|
|
return value
|
|
|
|
|
|
|
|
def ask_for_value(self, method, w, **vargs):
|
2007-06-17 10:55:36 -04:00
|
|
|
app = w.application
|
|
|
|
assert app.mini_buffer_is_open() is False, "Recursive minibuffer antics"
|
2007-03-06 10:05:38 -05:00
|
|
|
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)
|
2007-06-17 10:55:36 -04:00
|
|
|
app.close_mini_buffer()
|
2007-03-06 10:05:38 -05:00
|
|
|
method.execute(w, **vargs2)
|
2009-02-24 11:02:53 -05:00
|
|
|
tabber = completer.get_completer(self.datatype)
|
2007-03-06 10:05:38 -05:00
|
|
|
if d is not None:
|
|
|
|
p = self.prompt + "(%s) " % (d)
|
|
|
|
else:
|
|
|
|
p = self.prompt
|
2008-05-30 14:13:26 -04:00
|
|
|
app.open_mini_buffer(p, return_value, method=method, tabber=tabber,
|
|
|
|
startvalue=starting_value)
|
2007-03-06 10:05:38 -05:00
|
|
|
|
2008-03-14 17:17:04 -04:00
|
|
|
class Method(object):
|
2007-03-06 10:05:38 -05:00
|
|
|
_is_method = True
|
2008-03-17 03:28:07 -04:00
|
|
|
args = []
|
|
|
|
help = ""
|
2009-03-19 00:23:09 -04:00
|
|
|
metadata = {}
|
2007-03-06 10:05:38 -05:00
|
|
|
def __init__(self):
|
|
|
|
self.name = self._name()
|
2008-03-18 10:51:47 -04:00
|
|
|
if self.__doc__:
|
|
|
|
self.help = self.__doc__
|
2007-03-06 10:05:38 -05:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2007-07-02 20:29:27 -04:00
|
|
|
def _pre_execute(self, w, **vargs):
|
2007-03-06 10:05:38 -05:00
|
|
|
pass
|
|
|
|
|
|
|
|
def execute(self, w, **vargs):
|
2007-07-02 20:29:27 -04:00
|
|
|
try:
|
|
|
|
self._pre_execute(w, **vargs)
|
|
|
|
except MethodError, e:
|
2007-10-31 19:10:57 -04:00
|
|
|
w.set_error(str(e))
|
2007-07-02 20:29:27 -04:00
|
|
|
return
|
2007-03-06 10:05:38 -05:00
|
|
|
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)
|
2008-08-19 21:10:47 -04:00
|
|
|
w.buffer.undo_id += 1
|
2007-03-06 10:05:38 -05:00
|
|
|
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):
|
2007-06-05 00:49:24 -04:00
|
|
|
h = w.get_highlighter()
|
|
|
|
if h is None:
|
2007-10-31 19:10:57 -04:00
|
|
|
w.set_error("No lexer for buffer.")
|
2007-06-05 00:49:24 -04:00
|
|
|
else:
|
|
|
|
h.highlight(w.buffer.lines)
|
2007-10-31 19:10:57 -04:00
|
|
|
w.set_error("Buffer relexed.")
|
2008-03-17 03:16:15 -04:00
|
|
|
|
2007-03-06 10:05:38 -05:00
|
|
|
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
|
|
|
|
|
2007-07-18 23:06:21 -04:00
|
|
|
# you wanna quit right?
|
2007-03-06 10:05:38 -05:00
|
|
|
class Exit(Method):
|
|
|
|
'''Exit the program, unless there are unsaved changes'''
|
|
|
|
def _execute(self, w, **vargs):
|
2007-07-18 23:06:21 -04:00
|
|
|
a = w.application
|
|
|
|
assert a.mini_buffer_is_open() is False, "Recursive minibuffer antics"
|
|
|
|
|
|
|
|
changed = False
|
2007-03-06 10:05:38 -05:00
|
|
|
for b in w.application.bufferlist.buffers:
|
2007-07-18 23:06:21 -04:00
|
|
|
changed = b.changed()
|
|
|
|
if changed:
|
|
|
|
break
|
|
|
|
if not changed:
|
|
|
|
w.application.exit()
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
self._old_window = w
|
2007-07-19 22:36:36 -04:00
|
|
|
self._prompt = "There are buffers with unsaved changes; exit anyway? "
|
2007-07-18 23:06:21 -04:00
|
|
|
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"')
|
2007-03-06 10:05:38 -05:00
|
|
|
|
|
|
|
# insert text
|
|
|
|
class InsertString(Method):
|
|
|
|
_is_method = False
|
|
|
|
def __init__(self, s):
|
2007-10-12 22:58:17 -04:00
|
|
|
self.name = "insert-string-%s" % s
|
2007-03-06 10:05:38 -05:00
|
|
|
self.args = []
|
|
|
|
self.help = "Insert %r into the current buffer." % s
|
|
|
|
self.string = s
|
2007-06-13 11:44:09 -04:00
|
|
|
def _execute(self, w, **vargs):
|
2008-04-02 20:17:39 -04:00
|
|
|
try:
|
|
|
|
w.insert_string_at_cursor(self.string)
|
|
|
|
except buffer.ReadOnlyError:
|
|
|
|
w.set_error('Buffer is read-only')
|
2007-10-12 22:58:17 -04:00
|
|
|
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)
|
2008-04-01 14:35:09 -04:00
|
|
|
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)
|
2008-04-05 23:04:32 -04:00
|
|
|
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')
|
2007-03-06 10:05:38 -05:00
|
|
|
|
|
|
|
# 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()
|
2007-10-31 19:10:57 -04:00
|
|
|
w.set_error("Region killed by %s" % self.name)
|
2007-03-06 10:05:38 -05:00
|
|
|
class Copy(Method):
|
|
|
|
'''Copy the contents of the current line'''
|
|
|
|
def _execute(self, w, **vargs):
|
2008-11-08 10:30:04 -05:00
|
|
|
result = w.copy_line()
|
|
|
|
if result is None:
|
|
|
|
w.set_error("Empty kill region")
|
2007-03-06 10:05:38 -05:00
|
|
|
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)
|
2007-10-31 19:10:57 -04:00
|
|
|
w.set_error("Region copied")
|
2007-03-06 10:05:38 -05:00
|
|
|
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:
|
2007-10-31 19:10:57 -04:00
|
|
|
w.set_error("Kill ring is empty")
|
2007-03-06 10:05:38 -05:00
|
|
|
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] + "..."
|
2007-10-31 19:10:57 -04:00
|
|
|
w.set_error("Kill ring contains %r" % s)
|
2007-03-06 10:05:38 -05:00
|
|
|
else:
|
2007-10-31 19:10:57 -04:00
|
|
|
w.set_error("Kill ring is empty")
|
2007-03-06 10:05:38 -05:00
|
|
|
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] + "..."
|
2007-10-31 19:10:57 -04:00
|
|
|
w.set_error("Removed %r from Kill ring" % s)
|
2007-03-06 10:05:38 -05:00
|
|
|
else:
|
2007-10-31 19:10:57 -04:00
|
|
|
w.set_error("Kill ring is empty")
|
2007-03-06 10:05:38 -05:00
|
|
|
|
|
|
|
# delete
|
|
|
|
class DeleteLeft(Method):
|
|
|
|
'''Delete the character to the left of the cursor'''
|
|
|
|
def _execute(self, w, **vargs):
|
2007-08-06 13:38:13 -04:00
|
|
|
(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():
|
2008-11-11 00:15:47 -05:00
|
|
|
w.delete(Point(x - tabwidth, y), Point(x, y))
|
2007-03-06 10:05:38 -05:00
|
|
|
else:
|
|
|
|
w.left_delete()
|
|
|
|
class DeleteRight(Method):
|
|
|
|
'''Delete the character under the cursor'''
|
|
|
|
def _execute(self, w, **vargs):
|
|
|
|
cursor = w.logical_cursor()
|
2008-04-02 19:06:52 -04:00
|
|
|
line = w.buffer.lines[cursor.y]
|
|
|
|
lvl = w.mode.tabwidth
|
|
|
|
if len(line[cursor.x:]) >= lvl and line[:cursor.x + lvl].isspace():
|
2008-11-11 00:15:47 -05:00
|
|
|
w.delete(Point(cursor.x, cursor.y), Point(cursor.x + lvl, cursor.y))
|
2007-03-06 10:05:38 -05:00
|
|
|
else:
|
|
|
|
w.right_delete()
|
|
|
|
class DeleteLeftWord(Method):
|
|
|
|
'''Delete the from the cursor left to the end of the word'''
|
|
|
|
def _execute(self, w, **vargs):
|
2008-11-08 10:40:21 -05:00
|
|
|
w.delete_left_word()
|
2007-03-06 10:05:38 -05:00
|
|
|
class DeleteRightWord(Method):
|
|
|
|
'''Delete the from under cursor right to the end of the word'''
|
|
|
|
def _execute(self, w, **vargs):
|
2008-11-08 10:40:21 -05:00
|
|
|
w.delete_right_word()
|
2007-03-06 10:05:38 -05:00
|
|
|
class DeleteLeftWhitespace(Method):
|
|
|
|
'''Delete all contiguous of whitespace left of the cursor'''
|
|
|
|
def _execute(self, w, **vargs):
|
2007-06-14 08:41:55 -04:00
|
|
|
c = w.logical_cursor()
|
|
|
|
p = c
|
|
|
|
l = w.point_left(p)
|
|
|
|
if l is None:
|
|
|
|
return
|
2008-02-29 09:39:32 -05:00
|
|
|
while l is not None and w.point_char(l) in (' ', '\n'):
|
2007-06-14 08:41:55 -04:00
|
|
|
p = l
|
|
|
|
l = w.point_left(p)
|
|
|
|
if p < c:
|
2008-11-08 10:40:21 -05:00
|
|
|
w.delete(p, c)
|
2007-03-06 10:05:38 -05:00
|
|
|
class DeleteRightWhitespace(Method):
|
|
|
|
'''Delete all contiguous of whitespace under and right of the cursor'''
|
|
|
|
def _execute(self, w, **vargs):
|
2007-06-14 08:41:55 -04:00
|
|
|
c = w.logical_cursor()
|
|
|
|
p = c
|
2008-02-29 09:39:32 -05:00
|
|
|
while w.point_char(p) in (' ', '\n'):
|
|
|
|
r = w.point_right(p)
|
|
|
|
if r is None:
|
|
|
|
break
|
|
|
|
p = r
|
|
|
|
if p > c:
|
2008-11-08 10:40:21 -05:00
|
|
|
w.delete(c, p)
|
2008-02-29 09:39:32 -05:00
|
|
|
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:
|
2008-11-08 10:40:21 -05:00
|
|
|
w.delete(p, c)
|
2008-02-29 09:39:32 -05:00
|
|
|
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) == ' ':
|
2007-06-14 08:41:55 -04:00
|
|
|
r = w.point_right(p)
|
|
|
|
if r is None:
|
|
|
|
break
|
|
|
|
p = r
|
|
|
|
if p > c:
|
2008-11-08 10:40:21 -05:00
|
|
|
w.delete(c, p)
|
2007-03-06 10:05:38 -05:00
|
|
|
|
2008-11-20 16:27:52 -05:00
|
|
|
# errata
|
|
|
|
class LowercaseWord(Method):
|
|
|
|
'''Lowercase all characters in word'''
|
|
|
|
def _execute(self, w, **vargs):
|
|
|
|
(p1, p2) = w.get_word_bounds()
|
|
|
|
word = w.buffer.get_substring(p1, p2)
|
|
|
|
w.delete(p1, p2)
|
|
|
|
w.insert_string(p1, word.lower())
|
|
|
|
class UppercaseWord(Method):
|
|
|
|
'''Uppercase all characters in word'''
|
|
|
|
def _execute(self, w, **vargs):
|
|
|
|
(p1, p2) = w.get_word_bounds()
|
|
|
|
word = w.buffer.get_substring(p1, p2)
|
|
|
|
w.delete(p1, p2)
|
|
|
|
w.insert_string(p1, word.upper())
|
|
|
|
|
2007-03-06 10:05:38 -05:00
|
|
|
class MetaX(Method):
|
2009-03-27 23:40:09 -04:00
|
|
|
'''Call pmacs functions by name (with or without arguments)'''
|
2009-03-18 16:51:56 -04:00
|
|
|
args = [arg('method', dt="method", p="M-x ", h='Method to execute')]
|
|
|
|
name_re = re.compile(r'[a-z0-9_-]+')
|
|
|
|
|
|
|
|
py_empty_re = re.compile(r'^\( *\)$')
|
|
|
|
py_delim_re = re.compile(r', *')
|
|
|
|
py_end_re = re.compile(r' *\)')
|
|
|
|
|
|
|
|
pythonstyle = {
|
|
|
|
'arg_re': re.compile(r'("(?:[^\\"]|\\.)"|[^=),]+)(?= *,| *\))'),
|
|
|
|
'varg_re': re.compile(r'([a-z0-9_]+)=("(?:[^\\"]|\\.)"|[^=),]+)'),
|
|
|
|
}
|
|
|
|
shellstyle = {
|
|
|
|
'arg_re': re.compile(r'("(?:[^\\"]|\\.)"|[^= ]+)(?= +|$)'),
|
|
|
|
'varg_re': re.compile(r'([a-z0-9_]+)=("(?:[^\\"]|\\.)"|[^= ]+)'),
|
|
|
|
}
|
|
|
|
def _parse_arg(self, w, style, other, i):
|
|
|
|
m1 = style['arg_re'].match(other, i)
|
|
|
|
m2 = style['varg_re'].match(other, i)
|
|
|
|
if not (m1 or m2):
|
|
|
|
w.set_error("1couldn't parse %r:%d -> %r" % (other, i, other[i:]))
|
|
|
|
return (None, None, 0)
|
|
|
|
elif m1 and m2:
|
|
|
|
w.set_error("3couldn't parse %r:%d -> %r" % (other, i, other[i:]))
|
|
|
|
return (None, None, 0)
|
|
|
|
|
|
|
|
if m1:
|
|
|
|
name, value = None, m1.group(1)
|
|
|
|
if value.startswith('"'): value = eval(value)
|
|
|
|
return (None, value, m1.end())
|
|
|
|
elif m2:
|
|
|
|
name, value = m2.group(1), m2.group(2)
|
|
|
|
if value.startswith('"'): value = eval(value)
|
|
|
|
return (name, value, m2.end())
|
|
|
|
|
|
|
|
def _execute(self, w, **vargs):
|
|
|
|
s = vargs['method'].strip()
|
|
|
|
m = self.name_re.match(s)
|
|
|
|
assert m, "invalid cmd %r" % s
|
|
|
|
|
|
|
|
func = m.group(0)
|
|
|
|
args = []
|
|
|
|
vargs = {}
|
|
|
|
other = s[m.end():].strip()
|
|
|
|
if not other or self.py_empty_re.match(other):
|
|
|
|
# no arguments
|
|
|
|
pass
|
|
|
|
elif other.startswith('('):
|
|
|
|
# python type call
|
|
|
|
i = 1
|
|
|
|
while other[i] == ' ':
|
|
|
|
i += 1
|
|
|
|
while i < len(other):
|
|
|
|
name, value, i = self._parse_arg(w, self.pythonstyle, other, i)
|
|
|
|
if not value: return
|
|
|
|
elif name:
|
|
|
|
vargs[name] = value
|
|
|
|
else:
|
|
|
|
args.append(value)
|
|
|
|
if self.py_end_re.match(other, i): break
|
|
|
|
m = self.py_delim_re.match(other, i)
|
|
|
|
if not m:
|
|
|
|
w.set_error("2couldn't parse %r" % s[i:])
|
|
|
|
return
|
|
|
|
i = m.end()
|
|
|
|
else:
|
|
|
|
# shell type call
|
|
|
|
i = 0
|
|
|
|
while i < len(other):
|
|
|
|
if other[i] == ' ':
|
|
|
|
i += 1
|
|
|
|
continue
|
|
|
|
name, value, i = self._parse_arg(w, self.shellstyle, other, i)
|
|
|
|
if not value: return
|
|
|
|
elif name:
|
|
|
|
vargs[name] = value
|
|
|
|
else:
|
|
|
|
args.append(value)
|
|
|
|
|
2009-03-20 15:41:56 -04:00
|
|
|
meth = w.application.methods.get(func)
|
|
|
|
if meth is None:
|
|
|
|
w.set_error("method %r not found" % func)
|
|
|
|
return
|
|
|
|
try:
|
|
|
|
for (arg, value) in zip(meth.args, args): vargs[arg.name] = value
|
|
|
|
except:
|
|
|
|
w.set_error("4fail")
|
|
|
|
return
|
|
|
|
meth.execute(w, **vargs)
|
2007-03-06 10:05:38 -05:00
|
|
|
|
|
|
|
class ToggleMargins(Method):
|
|
|
|
'''Show or hide column margins'''
|
|
|
|
def _execute(self, w, **vargs):
|
2007-07-03 12:53:14 -04:00
|
|
|
w.margins_visible = not w.margins_visible
|
2007-03-06 10:05:38 -05:00
|
|
|
class CenterView(Method):
|
|
|
|
'''Move view to center on cursor'''
|
2007-06-14 08:41:55 -04:00
|
|
|
def _execute(self, w, **vargs):
|
2008-11-18 11:38:43 -05:00
|
|
|
w.center_view(force=True)
|
2007-03-06 10:05:38 -05:00
|
|
|
class SetMark(Method):
|
|
|
|
'''Set the mark to the current cursor location'''
|
2007-06-14 08:41:55 -04:00
|
|
|
def _execute(self, w, **vargs):
|
2009-03-19 00:23:09 -04:00
|
|
|
if w.application.last_action == self.name:
|
|
|
|
w.application.highlight_mark = True
|
|
|
|
w.set_error("Highlighting enabled: %r" % w.application.highlight_mark)
|
|
|
|
else:
|
|
|
|
w.set_mark()
|
2007-03-06 10:05:38 -05:00
|
|
|
class SwitchMark(Method):
|
|
|
|
'''Switch the mark and the cursor locations'''
|
2007-06-14 08:41:55 -04:00
|
|
|
def _execute(self, w, **vargs):
|
|
|
|
w.switch_mark()
|
2007-03-06 10:05:38 -05:00
|
|
|
|
|
|
|
# insertion methods
|
|
|
|
class InsertNewline(Method):
|
|
|
|
'''Insert newline into buffer at the cursor'''
|
2007-06-14 08:41:55 -04:00
|
|
|
def _execute(self, w, **vargs):
|
|
|
|
w.insert_string_at_cursor('\n')
|
2007-03-06 10:05:38 -05:00
|
|
|
class InsertSpace(Method):
|
|
|
|
'''Insert space into buffer at the cursor'''
|
2007-06-14 08:41:55 -04:00
|
|
|
def _execute(self, w, **vargs):
|
|
|
|
w.insert_string_at_cursor(' ')
|
2008-03-17 03:16:15 -04:00
|
|
|
|
|
|
|
class InsertSquotes(Method):
|
|
|
|
'''Insert a pair of single-quotes into the buffer'''
|
2007-06-20 17:26:33 -04:00
|
|
|
def _execute(self, w, **vargs):
|
2008-03-17 03:16:15 -04:00
|
|
|
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()
|
2007-06-20 17:26:33 -04:00
|
|
|
|
2007-03-06 10:05:38 -05:00
|
|
|
class InsertTab(Method):
|
|
|
|
'''Insert tab into buffer, or tabbify line, depending on mode'''
|
2007-06-14 08:41:55 -04:00
|
|
|
def _execute(self, w, **vargs):
|
|
|
|
cursor = w.logical_cursor()
|
2007-06-19 11:36:39 -04:00
|
|
|
if w.mode.tabber:
|
|
|
|
i = w.mode.tabber.get_level(cursor.y)
|
|
|
|
else:
|
|
|
|
i = None
|
|
|
|
|
2007-03-06 10:05:38 -05:00
|
|
|
if i is None:
|
2007-08-06 13:38:13 -04:00
|
|
|
w.insert_string_at_cursor(' ' * w.mode.tabwidth)
|
2007-03-06 10:05:38 -05:00
|
|
|
else:
|
2007-06-14 08:41:55 -04:00
|
|
|
j = w.buffer.count_leading_whitespace(cursor.y)
|
2007-03-06 10:05:38 -05:00
|
|
|
if i != j:
|
2007-06-14 08:41:55 -04:00
|
|
|
KillWhitespace().execute(w)
|
2007-06-19 14:45:51 -04:00
|
|
|
w.insert_string(Point(0, cursor.y), ' ' * i)
|
2007-03-06 10:05:38 -05:00
|
|
|
else:
|
2007-06-14 08:41:55 -04:00
|
|
|
w.goto(Point(j, cursor.y))
|
2008-03-17 03:16:15 -04:00
|
|
|
|
2007-03-06 10:05:38 -05:00
|
|
|
class KillWhitespace(Method):
|
|
|
|
'''Delete leading whitespace on current line'''
|
2007-06-14 08:41:55 -04:00
|
|
|
def _execute(self, w, **vargs):
|
|
|
|
cursor = w.logical_cursor()
|
|
|
|
i = w.buffer.count_leading_whitespace(cursor.y)
|
2007-03-06 10:05:38 -05:00
|
|
|
if i > 0:
|
2008-11-08 10:40:21 -05:00
|
|
|
w.delete(Point(0, cursor.y), Point(i, cursor.y))
|
2007-03-06 10:05:38 -05:00
|
|
|
|
|
|
|
# tabification
|
|
|
|
class TabBuffer(Method):
|
|
|
|
'''Tabbify every line in the current buffer'''
|
2007-06-14 08:41:55 -04:00
|
|
|
def _execute(self, w, **vargs):
|
|
|
|
y = w.logical_cursor().y
|
2007-03-06 10:05:38 -05:00
|
|
|
it = InsertTab()
|
2007-06-14 08:41:55 -04:00
|
|
|
for i in range(0, len(w.buffer.lines)):
|
|
|
|
w.goto_line(i)
|
|
|
|
it.execute(w)
|
|
|
|
w.goto_line(y)
|
2008-03-17 03:16:15 -04:00
|
|
|
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)
|
2007-03-06 10:05:38 -05:00
|
|
|
|
|
|
|
# commenting
|
|
|
|
class CommentRegion(Method):
|
|
|
|
'''Prepend a comment to every line in the current buffer'''
|
2007-06-14 08:41:55 -04:00
|
|
|
def _execute(self, w, **vargs):
|
|
|
|
cursor = w.logical_cursor()
|
|
|
|
if cursor < w.mark:
|
2007-03-06 10:05:38 -05:00
|
|
|
p1 = cursor
|
2007-06-14 08:41:55 -04:00
|
|
|
p2 = w.mark
|
|
|
|
elif w.mark < cursor:
|
|
|
|
p1 = w.mark
|
2007-03-06 10:05:38 -05:00
|
|
|
p2 = cursor
|
|
|
|
else:
|
2007-06-14 08:41:55 -04:00
|
|
|
w.input_line = "Empty kill region"
|
2007-03-06 10:05:38 -05:00
|
|
|
return
|
2009-02-13 15:46:05 -05:00
|
|
|
|
2009-02-15 12:06:35 -05:00
|
|
|
commentc = w.mode.commentc or '#'
|
|
|
|
|
2009-02-13 15:46:05 -05:00
|
|
|
x = w.buffer.detect_indent_level(p1.y, p2.y) or 0
|
2007-03-06 10:05:38 -05:00
|
|
|
for y in range(p1.y, p2.y):
|
2009-02-15 12:06:35 -05:00
|
|
|
c = commentc
|
2009-02-13 15:46:05 -05:00
|
|
|
if len(w.buffer.lines[y]) < x:
|
|
|
|
c += ' ' * (x - len(w.buffer.lines[y]))
|
|
|
|
w.buffer.insert_string(Point(x, y), c)
|
|
|
|
|
2007-03-06 10:05:38 -05:00
|
|
|
class UncommentRegion(Method):
|
|
|
|
'''Remove a comment from every line in the current buffer'''
|
|
|
|
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
|
2009-02-13 15:46:05 -05:00
|
|
|
|
2009-02-15 12:06:35 -05:00
|
|
|
commentc = w.mode.commentc or '#'
|
|
|
|
commentre = re.compile('^( *)((?:%s)+)' % commentc)
|
|
|
|
|
2007-03-06 10:05:38 -05:00
|
|
|
for y in range(p1.y, p2.y):
|
2009-02-13 15:46:05 -05:00
|
|
|
line = w.buffer.lines[y]
|
2009-02-15 12:06:35 -05:00
|
|
|
m = commentre.match(line)
|
2009-02-13 15:46:05 -05:00
|
|
|
if not m:
|
|
|
|
continue
|
|
|
|
s1, s2 = m.groups()
|
|
|
|
x1, x2 = len(s1), len(s1) + len(s2)
|
|
|
|
w.buffer.delete(Point(x1, y), Point(x2, y))
|
2007-03-06 10:05:38 -05:00
|
|
|
|
|
|
|
# wrapping/justifying/etc
|
|
|
|
class WrapLine(Method):
|
2009-03-27 23:40:09 -04:00
|
|
|
'''Wrap a line of text based on a predefined margin'''
|
2007-03-06 10:05:38 -05:00
|
|
|
limit = 80
|
2007-11-14 00:36:43 -05:00
|
|
|
space_re = re.compile(' +')
|
2007-10-26 14:36:42 -04:00
|
|
|
def _token_len(self, tokens):
|
|
|
|
l = 0
|
|
|
|
for t in tokens:
|
|
|
|
l += len(t)
|
|
|
|
return l
|
2008-11-10 11:45:41 -05:00
|
|
|
def _find_line_bounds(self, limit, tokens, x, y):
|
|
|
|
if len(tokens[0]) > limit:
|
2007-10-26 14:36:42 -04:00
|
|
|
i = 1
|
|
|
|
else:
|
|
|
|
i = 0
|
2007-10-30 16:25:14 -04:00
|
|
|
l = self._token_len(tokens[:i+1])
|
2008-11-10 11:45:41 -05:00
|
|
|
while i < len(tokens) and l <= limit:
|
2007-10-26 14:36:42 -04:00
|
|
|
i += 1
|
2007-10-30 16:25:14 -04:00
|
|
|
l = self._token_len(tokens[:i+1])
|
2007-10-26 14:36:42 -04:00
|
|
|
while i > 1 and tokens and tokens[i-1].isspace():
|
2007-10-30 16:25:14 -04:00
|
|
|
token = tokens.pop(i-1)
|
|
|
|
l -= len(token)
|
|
|
|
if x > l:
|
|
|
|
x -= len(token)
|
2007-10-26 14:36:42 -04:00
|
|
|
i -= 1
|
2007-10-30 16:25:14 -04:00
|
|
|
return i, x, y
|
|
|
|
def _clear_preceeding_spaces(self, tokens, x, y):
|
2007-11-14 00:36:43 -05:00
|
|
|
while tokens and self.space_re.match(tokens[0]):
|
2007-10-30 16:25:14 -04:00
|
|
|
if x > 0:
|
|
|
|
x = max(0, x - len(tokens[0]))
|
2007-10-26 14:36:42 -04:00
|
|
|
del tokens[0]
|
2007-10-30 16:25:14 -04:00
|
|
|
return x, y
|
2007-03-06 10:05:38 -05:00
|
|
|
|
2008-11-10 11:45:41 -05:00
|
|
|
def _wrap_line(self, limit, line, x, y):
|
2007-10-30 16:25:14 -04:00
|
|
|
tokens = re.findall('[^ ]+| +', line)
|
2008-11-10 11:45:41 -05:00
|
|
|
if self._token_len(tokens) <= limit:
|
2007-10-30 16:25:14 -04:00
|
|
|
return None, None, None
|
2007-10-26 14:36:42 -04:00
|
|
|
|
|
|
|
lines = []
|
2008-11-10 11:45:41 -05:00
|
|
|
while tokens and self._token_len(tokens) > limit:
|
|
|
|
i, x, y = self._find_line_bounds(limit, tokens, x, y)
|
2007-10-26 14:36:42 -04:00
|
|
|
s = ''.join(tokens[:i])
|
|
|
|
lines.append(s)
|
|
|
|
if x > len(s):
|
|
|
|
y += 1
|
|
|
|
x -= len(s)
|
|
|
|
del tokens[:i]
|
2007-10-30 16:25:14 -04:00
|
|
|
x, y = self._clear_preceeding_spaces(tokens, x, y)
|
2007-10-26 14:36:42 -04:00
|
|
|
if tokens:
|
2007-11-14 00:21:23 -05:00
|
|
|
lines.append(''.join(tokens) + ' ')
|
2007-10-26 14:36:42 -04:00
|
|
|
|
2007-10-30 16:25:14 -04:00
|
|
|
return lines, x, y
|
|
|
|
def _execute(self, w, **vargs):
|
2008-11-10 11:45:41 -05:00
|
|
|
limit = util.get_margin_limit(w, self.limit)
|
2007-10-30 16:25:14 -04:00
|
|
|
cursor = w.logical_cursor()
|
|
|
|
x, y = cursor.xy()
|
2008-11-10 11:45:41 -05:00
|
|
|
lines, x, y = self._wrap_line(limit, w.buffer.lines[y], x, y)
|
2007-10-30 16:25:14 -04:00
|
|
|
if lines is None:
|
|
|
|
return
|
2008-01-29 13:07:13 -05:00
|
|
|
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)
|
2007-10-26 14:36:42 -04:00
|
|
|
w.goto(Point(x, y))
|
2008-04-03 18:30:49 -04:00
|
|
|
|
2008-03-17 02:22:09 -04:00
|
|
|
class WrapParagraph(Method):
|
2009-03-27 23:40:09 -04:00
|
|
|
'''Wrap contiguous lines of text based on a predefined margin'''
|
2008-11-10 14:58:12 -05:00
|
|
|
limit = 80
|
|
|
|
valid_re = re.compile('^( *)([^ ].*)$')
|
|
|
|
empty_re = regex.whitespace
|
2007-03-06 10:05:38 -05:00
|
|
|
def _execute(self, w, **vargs):
|
2008-11-10 11:45:41 -05:00
|
|
|
limit = util.get_margin_limit(w, self.limit)
|
|
|
|
|
2008-02-29 09:39:32 -05:00
|
|
|
# we will store the start of our paragaph in p1, and also the original
|
|
|
|
# cursor position.
|
|
|
|
p1 = oldc = w.logical_cursor()
|
|
|
|
cur_offset = 0
|
|
|
|
|
2008-11-10 14:58:12 -05:00
|
|
|
m = self.valid_re.match(w.buffer.lines[p1.y])
|
2008-03-07 21:20:43 -05:00
|
|
|
if not m:
|
2008-04-03 18:30:49 -04:00
|
|
|
# the line was empty
|
2008-03-07 21:20:43 -05:00
|
|
|
return
|
|
|
|
elif m.group(1):
|
2008-04-03 18:30:49 -04:00
|
|
|
# the line had leading whitespace
|
2008-03-07 21:20:43 -05:00
|
|
|
return
|
|
|
|
|
2008-02-29 09:39:32 -05:00
|
|
|
# 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
|
2008-11-10 14:58:12 -05:00
|
|
|
p1 = Point(0, i)
|
2008-02-29 09:39:32 -05:00
|
|
|
|
|
|
|
# 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)
|
|
|
|
|
2008-11-10 14:58:12 -05:00
|
|
|
#raise Exception, '%r %r' % (limit, s)
|
|
|
|
|
2008-02-29 09:39:32 -05:00
|
|
|
# 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!
|
2008-11-10 11:45:41 -05:00
|
|
|
if len(s) < limit:
|
2008-02-29 09:39:32 -05:00
|
|
|
newlines.append(s)
|
2007-03-06 10:05:38 -05:00
|
|
|
break
|
2008-02-29 09:39:32 -05:00
|
|
|
|
|
|
|
# look for the rightmost space within our bounds
|
2008-11-10 11:45:41 -05:00
|
|
|
j = s.rfind(' ', 0, limit)
|
2008-02-29 09:39:32 -05:00
|
|
|
# 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
|
2008-03-05 20:35:06 -05:00
|
|
|
while k < len(newlines) - 1 and x > len(newlines[k]):
|
2008-02-29 09:39:32 -05:00
|
|
|
x = x - len(newlines[k]) - 1
|
|
|
|
y += 1
|
|
|
|
k += 1
|
2008-03-01 12:10:07 -05:00
|
|
|
|
2008-11-10 14:58:12 -05:00
|
|
|
#assert len(newlines), 'fooga: %r %r' % (limit, s)
|
|
|
|
|
2008-02-29 09:39:32 -05:00
|
|
|
# kill the old paragraph region, insert the new, and goto the new cursor
|
2008-11-08 10:40:21 -05:00
|
|
|
w.delete(p1, Point(len(w.buffer.lines[i-1]), i-1))
|
2008-02-29 09:39:32 -05:00
|
|
|
w.insert_lines(p1, newlines)
|
|
|
|
w.goto(Point(x, y))
|
2007-03-06 10:05:38 -05:00
|
|
|
|
2008-03-20 11:04:04 -04:00
|
|
|
class CountWords(Method):
|
|
|
|
'''Count the number of words in the document'''
|
|
|
|
def _execute(self, w, **vargs):
|
|
|
|
wcount = 0
|
|
|
|
pcount = 0
|
|
|
|
inp = False
|
2008-03-20 11:14:13 -04:00
|
|
|
name = w.buffer.name()
|
2008-03-20 11:04:04 -04:00
|
|
|
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
|
2008-03-20 11:14:13 -04:00
|
|
|
w.set_error("%d words (%d paragraphs) found in %r" % (wcount, pcount, name))
|
2008-03-20 11:04:04 -04:00
|
|
|
|
2007-03-06 10:05:38 -05:00
|
|
|
class JustifyRight(Method):
|
|
|
|
'''Justify text with the previous line right from the cursor by whitespace'''
|
2007-06-14 08:41:55 -04:00
|
|
|
def _execute(self, w, **vargs):
|
2008-02-29 09:39:32 -05:00
|
|
|
DeleteLeftSpace().execute(w)
|
2007-06-14 08:41:55 -04:00
|
|
|
cursor = w.logical_cursor()
|
|
|
|
prev_line = w.buffer.lines[cursor.y-1]
|
|
|
|
this_line = w.buffer.lines[cursor.y]
|
2007-03-06 10:05:38 -05:00
|
|
|
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)
|
2007-06-14 08:41:55 -04:00
|
|
|
w.insert_string_at_cursor(s)
|
2007-03-06 10:05:38 -05:00
|
|
|
class JustifyLeft(Method):
|
|
|
|
'''Justify text with the previous line left from the cursor by whitespace'''
|
2007-06-14 08:41:55 -04:00
|
|
|
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]
|
2007-03-06 10:05:38 -05:00
|
|
|
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
|
2007-06-17 10:55:36 -04:00
|
|
|
w.buffer.delete(Point(i, cursor.y), cursor)
|
2007-03-06 10:05:38 -05:00
|
|
|
|
|
|
|
# undo/redo
|
|
|
|
class Undo(Method):
|
|
|
|
'''Undo last action'''
|
2007-06-14 08:41:55 -04:00
|
|
|
def _execute(self, w, **vargs):
|
2007-03-06 10:05:38 -05:00
|
|
|
try:
|
2007-07-19 12:38:17 -04:00
|
|
|
w.undo()
|
2007-03-06 10:05:38 -05:00
|
|
|
except Exception, e:
|
2007-10-31 19:10:57 -04:00
|
|
|
w.set_error("%s" % (e))
|
2007-03-06 10:05:38 -05:00
|
|
|
class Redo(Method):
|
|
|
|
'''Redo last undone action'''
|
2007-06-14 08:41:55 -04:00
|
|
|
def _execute(self, w, **vargs):
|
2007-03-06 10:05:38 -05:00
|
|
|
try:
|
2007-07-19 12:38:17 -04:00
|
|
|
w.redo()
|
2007-03-06 10:05:38 -05:00
|
|
|
except Exception, e:
|
2007-10-31 19:10:57 -04:00
|
|
|
w.set_error("%s" % (e))
|
2007-03-06 10:05:38 -05:00
|
|
|
|
|
|
|
class UnindentBlock(Method):
|
2008-04-02 19:06:52 -04:00
|
|
|
'''Prepend a tab of space to each line in region'''
|
2007-03-06 10:05:38 -05:00
|
|
|
def _execute(self, w, **vargs):
|
2008-04-02 19:06:52 -04:00
|
|
|
lvl = w.mode.tabwidth
|
2007-03-06 10:05:38 -05:00
|
|
|
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(' '):
|
2008-04-02 19:06:52 -04:00
|
|
|
lines[i] = lines[i][lvl:]
|
2007-06-17 10:55:36 -04:00
|
|
|
w.buffer.delete(Point(0, p1.y), Point(0, p2.y))
|
|
|
|
w.buffer.insert_string(Point(0, p1.y), '\n'.join(lines) + '\n')
|
2007-03-06 10:05:38 -05:00
|
|
|
class IndentBlock(Method):
|
2008-04-02 19:06:52 -04:00
|
|
|
'''Prepend a tab of space to each line in region'''
|
2007-03-06 10:05:38 -05:00
|
|
|
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]
|
2007-08-06 13:38:13 -04:00
|
|
|
tstr = ' ' * w.mode.tabwidth
|
2007-03-06 10:05:38 -05:00
|
|
|
for i in range(0, len(lines)):
|
2007-08-06 13:38:13 -04:00
|
|
|
lines[i] = tstr + lines[i]
|
2007-06-17 10:55:36 -04:00
|
|
|
w.buffer.delete(Point(0, p1.y), Point(0, p2.y))
|
|
|
|
w.buffer.insert_string(Point(0, p1.y), '\n'.join(lines) + '\n')
|
2007-03-06 10:05:38 -05:00
|
|
|
|
2009-03-27 23:40:09 -04:00
|
|
|
class Diff(Method):
|
2007-03-06 10:05:38 -05:00
|
|
|
'''diff the buffer's contents with the given file'''
|
2009-03-27 23:40:09 -04:00
|
|
|
args = [arg("path1", t=type(""), p="Filename: ", dt='path', h="left path to diff"),
|
|
|
|
arg("path2", t=type(""), p="Filename: ", dt='path', h="right path to diff")]
|
|
|
|
def _get_cmd(self, w, **vargs):
|
|
|
|
return ("/usr/bin/diff", '-u', vargs['path1'], vargs['path2'])
|
|
|
|
def _pipe_write(self, pipe, w, **vargs):
|
|
|
|
pass
|
2007-03-06 10:05:38 -05:00
|
|
|
def _execute(self, w, **vargs):
|
2009-03-27 23:40:09 -04:00
|
|
|
cmd = self._get_cmd(w, **vargs)
|
2008-03-16 16:08:37 -04:00
|
|
|
pipe = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
2009-03-27 23:40:09 -04:00
|
|
|
self._pipe_write(pipe, w, **vargs)
|
2008-03-16 16:08:37 -04:00
|
|
|
outdata = pipe.stdout.read()
|
|
|
|
errdata = pipe.stderr.read()
|
2009-03-27 23:40:09 -04:00
|
|
|
status = pipe.wait()
|
2007-03-06 10:05:38 -05:00
|
|
|
if status == 0:
|
2009-03-27 23:40:09 -04:00
|
|
|
w.set_error("No difference found" + str(status))
|
2007-03-06 10:05:38 -05:00
|
|
|
elif status == 1:
|
|
|
|
w.application.data_buffer("*Diff*", outdata, switch_to=True, modename='diff')
|
2007-10-31 19:10:57 -04:00
|
|
|
w.set_error("Differences were found")
|
2007-03-06 10:05:38 -05:00
|
|
|
else:
|
|
|
|
w.application.data_buffer("*Diff*", errdata, switch_to=True)
|
2009-03-27 23:40:09 -04:00
|
|
|
w.set_error("There was an error: %d exited with status %s" % (pipe.pid, status))
|
|
|
|
|
|
|
|
class FileDiff(Diff):
|
|
|
|
'''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 _get_cmd(self, w, **vargs):
|
|
|
|
return ("/usr/bin/diff", '-u', '-', vargs['path'])
|
|
|
|
def _pipe_write(self, pipe, w, **vargs):
|
|
|
|
indata = w.buffer.make_string()
|
|
|
|
pipe.stdin.write(indata)
|
|
|
|
pipe.stdin.close()
|
2008-03-16 19:27:16 -04:00
|
|
|
|
2007-03-06 10:05:38 -05:00
|
|
|
class SetMode(Method):
|
|
|
|
'''Set the mode of the current buffer'''
|
2008-03-18 10:51:47 -04:00
|
|
|
args = [arg('mode', dt='mode', p="Enter new mode: ")]
|
2007-03-06 10:05:38 -05:00
|
|
|
def _execute(self, w, **vargs):
|
|
|
|
mode_name = vargs['mode']
|
|
|
|
m = w.application.modes[mode_name](w)
|
|
|
|
w.set_mode(m)
|
2007-10-31 19:10:57 -04:00
|
|
|
w.set_error('Set mode to %r' % (mode_name))
|
2007-03-06 10:05:38 -05:00
|
|
|
|
|
|
|
class Cancel(Method):
|
|
|
|
'''Cancel command in-progress, and return to the main buffer'''
|
|
|
|
def execute(self, w, **vargs):
|
|
|
|
w.application.close_mini_buffer()
|
2008-05-03 22:41:58 -04:00
|
|
|
if w.application.completion_window_is_open():
|
|
|
|
w.application.close_completion_buffer()
|
2007-10-31 19:10:57 -04:00
|
|
|
w.set_error('Cancel')
|
2007-03-06 10:05:38 -05:00
|
|
|
|
|
|
|
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():
|
2009-03-20 00:20:29 -04:00
|
|
|
#p = w.first
|
|
|
|
#w.goto(p)
|
|
|
|
w.center_view(force=True)
|
2007-03-06 10:05:38 -05:00
|
|
|
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()
|
2007-10-31 19:10:57 -04:00
|
|
|
w.set_error('Window has been unsplit back to one window!')
|
2007-03-06 10:05:38 -05:00
|
|
|
|
2009-03-27 23:40:09 -04:00
|
|
|
class CloseParen(Method):
|
|
|
|
'''Insert ), matching if applicable'''
|
|
|
|
mytag = ')'
|
2007-03-06 10:05:38 -05:00
|
|
|
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.
|
2007-06-17 09:49:52 -04:00
|
|
|
(x, y) = w.logical_cursor().xy()
|
2007-06-04 03:29:37 -04:00
|
|
|
w.insert_string_at_cursor(self.mytag)
|
2007-06-17 09:49:52 -04:00
|
|
|
app = w.application
|
|
|
|
buffer = w.buffer
|
2009-03-17 15:24:10 -04:00
|
|
|
highlighter = buffer.highlights[w.mode.name]
|
2007-06-17 09:49:52 -04:00
|
|
|
tokens = highlighter.tokens
|
2007-03-06 10:05:38 -05:00
|
|
|
|
2007-07-23 17:07:43 -04:00
|
|
|
# REFACTOR: we have methods in window to do this now
|
2007-03-06 10:05:38 -05:00
|
|
|
i = 0
|
2007-06-17 09:49:52 -04:00
|
|
|
while i < len(tokens[y]):
|
|
|
|
token = tokens[y][i]
|
|
|
|
if token.x == x and token.string == self.mytag:
|
2007-03-06 10:05:38 -05:00
|
|
|
break
|
2007-06-17 09:49:52 -04:00
|
|
|
elif token.x <= x and token.end_x() > x:
|
2007-03-06 10:05:38 -05:00
|
|
|
return
|
|
|
|
i += 1
|
2007-06-17 09:49:52 -04:00
|
|
|
if i >= len(tokens[y]):
|
|
|
|
return
|
|
|
|
|
|
|
|
tag_stack = []
|
|
|
|
while y >= 0:
|
|
|
|
while i >= 0 and i < len(tokens[y]):
|
|
|
|
token = tokens[y][i]
|
2007-07-23 17:07:43 -04:00
|
|
|
n = token.name
|
2007-06-17 09:49:52 -04:00
|
|
|
s = token.string
|
2007-07-23 17:07:43 -04:00
|
|
|
if n in w.mode.closetokens and s in w.mode.closetags:
|
2007-03-06 10:05:38 -05:00
|
|
|
tag_stack.append(s)
|
2007-07-23 17:07:43 -04:00
|
|
|
elif n in w.mode.opentokens and s in w.mode.opentags:
|
|
|
|
if tag_stack[-1] == w.mode.opentags[s]:
|
2007-06-17 09:49:52 -04:00
|
|
|
del tag_stack[-1]
|
|
|
|
else:
|
|
|
|
app.set_error("tag mismatch; got %r expected %r" %
|
2007-07-23 17:07:43 -04:00
|
|
|
(s, w.mode.closetags[tag_stack[-1]]))
|
2007-06-17 09:49:52 -04:00
|
|
|
return
|
2007-03-06 10:05:38 -05:00
|
|
|
if len(tag_stack) == 0:
|
2007-06-17 09:49:52 -04:00
|
|
|
p = Point(token.x, y)
|
2007-07-17 04:13:56 -04:00
|
|
|
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)
|
2007-06-17 09:49:52 -04:00
|
|
|
return
|
|
|
|
i -= 1
|
|
|
|
y -= 1
|
|
|
|
i = len(tokens[y]) - 1
|
2007-03-06 10:05:38 -05:00
|
|
|
|
2009-03-27 23:40:09 -04:00
|
|
|
class CloseBrace(CloseParen):
|
2009-03-13 00:36:20 -04:00
|
|
|
'''Insert }, matching if applicable'''
|
2007-03-06 10:05:38 -05:00
|
|
|
mytag = '}'
|
2009-03-27 23:40:09 -04:00
|
|
|
class CloseBracket(CloseParen):
|
2009-03-13 00:36:20 -04:00
|
|
|
'''Insert ], matching if applicable'''
|
2007-03-06 10:05:38 -05:00
|
|
|
mytag = ']'
|
2007-06-29 09:37:58 -04:00
|
|
|
|
2007-07-02 20:29:27 -04:00
|
|
|
class RegisterSave(Method):
|
2007-07-18 07:22:12 -04:00
|
|
|
'''Save the top item of the kill stack into the named register'''
|
2008-03-18 10:51:47 -04:00
|
|
|
MAX_TXT = 30
|
|
|
|
MAX_REG = 18
|
2009-03-27 23:40:09 -04:00
|
|
|
args = [arg('name', dt="register", p="Register name: ", h="Register name to use")]
|
2007-07-02 20:29:27 -04:00
|
|
|
def _pre_execute(self, w, **vargs):
|
|
|
|
if not w.has_kill():
|
2008-05-16 19:02:22 -04:00
|
|
|
raise MethodError("No text on the kill stack")
|
2007-07-02 20:29:27 -04:00
|
|
|
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):
|
2009-03-27 23:40:09 -04:00
|
|
|
'''Push the value of the named register onto the kill stack'''
|
2007-07-02 20:29:27 -04:00
|
|
|
MAX_TXT = 30
|
|
|
|
MAX_REG = 18
|
2009-03-27 23:40:09 -04:00
|
|
|
args = [arg('name', dt="register", p="Register name: ", h="Register name to use")]
|
2007-07-02 20:29:27 -04:00
|
|
|
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
|
2008-03-18 10:51:47 -04:00
|
|
|
app = w.application
|
2007-07-02 20:29:27 -04:00
|
|
|
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] + '...'
|
2008-03-18 10:51:47 -04:00
|
|
|
w.set_error('Restored %r from register %r' % (text, name))
|
2008-03-20 21:58:30 -04:00
|
|
|
|
|
|
|
class GetConfigVariable(Method):
|
2009-03-27 23:40:09 -04:00
|
|
|
'''View the value of a particular config variables'''
|
|
|
|
args = [arg('name', dt='config', p="Config variable: ", h='Config variable name')]
|
2008-03-20 21:58:30 -04:00
|
|
|
def _execute(self, w, **vargs):
|
|
|
|
name = vargs['name']
|
|
|
|
if name in w.application.config:
|
|
|
|
value = w.application.config[name]
|
2008-03-21 01:32:03 -04:00
|
|
|
w.set_error("param %r set to %r" % (name, value))
|
2008-03-20 21:58:30 -04:00
|
|
|
else:
|
2008-03-21 01:32:03 -04:00
|
|
|
w.set_error("param %r is not set" % (name,))
|
2008-03-20 21:58:30 -04:00
|
|
|
|
|
|
|
class ViewConfigVariables(Method):
|
2009-03-27 23:40:09 -04:00
|
|
|
'''View the value of all config variables'''
|
2008-03-20 21:58:30 -04:00
|
|
|
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):
|
2009-03-27 23:40:09 -04:00
|
|
|
'''Set a particular config variable to a value'''
|
|
|
|
args = [arg('name', dt='config', p="Variable name: ", h='Config variable name'),
|
|
|
|
arg('value', t=type(''), p="Variable value: ", h='Config variable value')]
|
2008-03-20 21:58:30 -04:00
|
|
|
def _execute(self, w, **vargs):
|
2008-03-21 01:32:03 -04:00
|
|
|
name = vargs['name']
|
2008-03-20 21:58:30 -04:00
|
|
|
found = name in w.application.config
|
2008-03-21 01:32:03 -04:00
|
|
|
try:
|
|
|
|
value = eval(vargs['value'])
|
|
|
|
except:
|
|
|
|
value = vargs['value']
|
2008-03-20 21:58:30 -04:00
|
|
|
w.application.config[name] = value
|
|
|
|
if found:
|
2008-03-21 01:32:03 -04:00
|
|
|
w.set_error("param %r set to %r" % (name, value))
|
2008-03-20 21:58:30 -04:00
|
|
|
else:
|
2008-03-21 01:32:03 -04:00
|
|
|
w.set_error("previously unset param %r set to %r" % (name, value))
|
2008-04-02 19:06:52 -04:00
|
|
|
|
2009-01-28 16:28:33 -05:00
|
|
|
class ToggleHeader(Method):
|
2009-03-27 23:40:09 -04:00
|
|
|
'''Toggle the visibility of the buffer header'''
|
2009-01-28 16:28:33 -05:00
|
|
|
def _execute(self, w, **vargs):
|
|
|
|
if w.mode.showing_header():
|
|
|
|
w.mode.disable_header()
|
|
|
|
w.set_error('Header hidden')
|
|
|
|
else:
|
|
|
|
w.mode.enable_header()
|
|
|
|
w.set_error('Header visible')
|
|
|
|
|
2009-03-27 23:40:09 -04:00
|
|
|
# TODO: rename to left-margin
|
2008-04-06 22:31:13 -04:00
|
|
|
class ToggleLineNumbers(Method):
|
2009-03-27 23:40:09 -04:00
|
|
|
'''Toggle the visibility of the left margin'''
|
2008-04-06 22:31:13 -04:00
|
|
|
def _execute(self, w, **vargs):
|
2009-01-28 16:28:33 -05:00
|
|
|
if w.mode.showing_line_numbers():
|
2008-04-06 22:31:13 -04:00
|
|
|
w.mode.disable_line_numbers()
|
|
|
|
w.set_error('Line numbers hidden')
|
|
|
|
else:
|
|
|
|
w.mode.enable_line_numbers()
|
|
|
|
w.set_error('Line numbers visible')
|
|
|
|
|
2008-04-02 19:06:52 -04:00
|
|
|
class SetTabWidth(Method):
|
2009-03-27 23:40:09 -04:00
|
|
|
'''Set the tab-width for the current buffer'''
|
2008-04-02 19:06:52 -04:00
|
|
|
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)
|
2008-04-02 19:24:52 -04:00
|
|
|
|
|
|
|
class SetModeTabWidth(Method):
|
2009-03-27 23:40:09 -04:00
|
|
|
'''Set the default tab-width for the current mode'''
|
2008-04-02 19:24:52 -04:00
|
|
|
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)
|