more method clean-up; bug fixes for shell junk

--HG--
branch : pmacs2
This commit is contained in:
moculus 2008-03-17 07:16:15 +00:00
parent dcf393d135
commit d5c005a692
9 changed files with 687 additions and 643 deletions

View File

@ -118,7 +118,10 @@ class Application(object):
# initialize our methods
self.methods = {}
for name in ('method', 'method.svn', 'method.cvs'):
names = ('method', 'method.svn', 'method.cvs', 'method.search',
'method.buffers', 'method.move', 'method.shell',
'method.introspect', 'method.help')
for name in names:
exec("import %s" % name)
mod = eval(name)
for mname in dir(mod):

View File

@ -105,213 +105,6 @@ class Method(object):
def _execute(self, w, **vargs):
raise Exception, "Unimplemented Method: %s %r" % (self.name, vargs)
class AboutPmacs(Method):
'''print some information about pmacs'''
def _execute(self, w, **vargs):
a = w.application
if not a.has_buffer_name('*About*'):
b = buffer.AboutBuffer()
a.add_buffer(b)
window.Window(b, a)
b = a.bufferlist.get_buffer_by_name('*About*')
if a.window().buffer is not b:
a.switch_buffer(b)
class GotoChar(Method):
'''Jump to the specified character'''
args = [Argument("charno", type=type(0), prompt="Goto char: ")]
def _execute(self, w, **vargs):
w.goto_char(vargs["charno"])
class ForwardChars(Method):
'''Move forward the specified number of characters'''
args = [Argument("charno", type=type(0), prompt="Forward chars: ")]
def _execute(self, w, **vargs):
w.forward_chars(vargs["charno"])
class GotoLine(Method):
'''Jump to the specified line number'''
args = [Argument("lineno", type=type(0), prompt="Goto line: ")]
def _execute(self, w, **vargs):
n = vargs["lineno"]
if n < 0:
n = len(w.buffer.lines) + n + 1
if n > len(w.buffer.lines):
n = len(w.buffer.lines)
elif n < 1:
n = 1
w.goto_line(n)
class ForwardLines(Method):
'''Move forward the specified number of characters'''
args = [Argument("lineno", type=type(0), prompt="Forward lines: ")]
def _execute(self, w, **vargs):
w.forward_lines(vargs["lineno"])
# search and replace
class Search(Method):
'''Interactive search; finds next occurance of text in buffer'''
is_literal = True
direction = 'next'
prompt = 'I-Search: '
def execute(self, w, **vargs):
self.old_cursor = w.logical_cursor()
self.old_window = w
w.application.open_mini_buffer(self.prompt, lambda x: None, self, None, 'search')
class ReverseSearch(Search):
'''Interactive search; finds previous occurance of text in buffer'''
direction = 'previous'
class RegexSearch(Search):
'''Interactive search; finds next occurance of regex in buffer'''
is_literal = False
prompt = 'I-RegexSearch: '
class RegexReverseSearch(RegexSearch):
'''Interactive search; finds prevoius occurance of regex in buffer'''
direction = 'previous'
class Replace(Method):
'''Replace occurances of string X with string Y'''
is_literal = True
args = [Argument('before', prompt="Replace String: ",
default=default.last_replace_before, load_default=True),
Argument('after', prompt="Replace With: ",
default=default.last_replace_after, load_default=True)]
def _execute(self, w, **vargs):
a = w.application
a.last_replace_before = self.before = vargs['before']
a.last_replace_after = self.after = vargs['after']
self.old_window = w
a.open_mini_buffer('I-Replace: ', lambda x: None, self, None, 'replace')
class RegexReplace(Method):
'''Replace occurances of string X with string Y'''
is_literal = False
args = [Argument('before', prompt="Replace Regex: ",
default=default.last_replace_before, load_default=True),
Argument('after', prompt="Replace With: ",
default=default.last_replace_after, load_default=True)]
def _execute(self, w, **vargs):
w.application.last_replace_before = self.before = vargs['before']
w.application.last_replace_after = self.after = vargs['after']
self.old_window = w
f = lambda x: None
w.application.open_mini_buffer('I-RegexReplace: ', f, self, None, 'replace')
# navigating between buffers
class OpenFile(Method):
'''Open file in a new buffer, or go to file's open buffer'''
args = [Argument('filename', datatype="path", prompt="Open File: ",
default=default.path_dirname, load_default=True)]
def _execute(self, w, **vargs):
b = w.application.open_path(vargs['filename'])
SwitchBuffer().execute(w, buffername=b.name())
class OpenAesFile(Method):
'''Open AES encrypted file in a new buffer, or go to file's open buffer'''
args = [Argument('filename', datatype="path", prompt="Open AES File: "),
Argument('password', prompt="Use AES Password: ")]
def _execute(self, w, **vargs):
b = w.application.open_path(vargs['filename'], 'aes', vargs['password'])
SwitchBuffer().execute(w, buffername=b.name())
return
class ViewBufferParent(Method):
def _execute(self, w, **vargs):
b = w.buffer
if not hasattr(b, 'path'):
w.set_error('Buffer has no path')
elif b.path == '/':
w.set_error("Root directory has no parent")
else:
path = os.path.dirname(b.path)
w.application.methods['open-file'].execute(w, filename=path)
class SwitchBuffer(Method):
'''Switch to a different'''
args = [Argument('buffername', datatype="buffer", prompt="Switch To Buffer: ",
default=default.last_buffer)]
def _pre_execute(self, w, **vargs):
a = w.application
if len(a.bufferlist.buffers) < 1:
raise Exception, "No other buffers"
def _execute(self, w, **vargs):
name = vargs['buffername']
buf = None
if w.application.has_buffer_name(name):
b = w.application.bufferlist.get_buffer_by_name(name)
w.application.switch_buffer(b)
else:
w.set_error("buffer %r was not found" % name)
class KillBuffer(Method):
'''Close the current buffer'''
force=False
args = [Argument('buffername', datatype="buffer", prompt="Kill Buffer: ",
default=default.current_buffer)]
def _execute(self, w, **vargs):
name = vargs['buffername']
a = w.application
assert name in a.bufferlist.buffer_names, "Buffer %r does not exist" % name
assert name != '*Scratch*', "Can't kill scratch buffer"
self._to_kill = a.bufferlist.buffer_names[name]
self._old_window = w
if self.force or not self._to_kill.changed():
self._doit()
else:
self._prompt = "Buffer has unsaved changes; kill anyway? "
a.open_mini_buffer(self._prompt, self._callback)
def _doit(self):
a = self._old_window.application
b = self._to_kill
if a.bufferlist.is_buffer_visible(b):
a.bufferlist.set_slot(a.active_slot, a.bufferlist.hidden_buffers[0])
a.bufferlist.remove_buffer(b)
b.close()
def _callback(self, v):
a = self._old_window.application
if v == 'yes':
self._doit()
a.close_mini_buffer()
elif v == 'no':
a.close_mini_buffer()
else:
a.close_mini_buffer()
a.set_error('Please type "yes" or "no"')
class ForceKillBuffer(KillBuffer):
force=True
args = [Argument('buffername', datatype="buffer", prompt="Force Kill Buffer: ",
default=default.current_buffer)]
class ListBuffers(Method):
'''List all open buffers in a new buffer'''
def _execute(self, w, **vargs):
bl = w.application.bufferlist
bnames = [b.name() for b in bl.buffers]
bnames.sort()
data = '\n'.join(bnames)
w.application.data_buffer("*Buffers*", data, switch_to=True)
class SaveBufferAs(Method):
'''Save the contents of a buffer to the specified path'''
args = [Argument('path', datatype="path", prompt="Write file: ",
default=default.current_working_dir, load_default=True)]
def _execute(self, w, **vargs):
curr_buffer = w.buffer
curr_buffer_name = curr_buffer.name()
data = curr_buffer.make_string()
path = os.path.realpath(os.path.expanduser(vargs['path']))
w.set_error("got %r (%d)" % (path, len(data)))
if w.application.has_buffer_name(path):
w.set_error("buffer for %r is already open" % path)
return
w.application.file_buffer(path, data, switch_to=True)
if curr_buffer_name != '*Scratch*':
w.application.methods['kill-buffer'].execute(w, buffername=curr_buffer_name)
else:
curr_buffer.set_data('')
w.set_error('Wrote %r' % path)
class SaveBuffer(Method):
'''Save the contents of a buffer'''
def _execute(self, w, **vargs):
if w.buffer.changed():
w.buffer.save()
w.set_error("Wrote %s" % (w.buffer.path))
else:
w.set_error("(No changes need to be saved)")
class RelexBuffer(Method):
'''Relex the buffer; this resets syntax highlighting'''
def _execute(self, w, **vargs):
@ -321,6 +114,7 @@ class RelexBuffer(Method):
else:
h.highlight(w.buffer.lines)
w.set_error("Buffer relexed.")
class ToggleWindow(Method):
'''Move between visible windows'''
def _execute(self, w, **vargs):
@ -511,57 +305,6 @@ class DeleteRightSpace(Method):
if p > c:
w.kill(c, p)
# random stuff
class DumpRegions(Method):
'''debug region highlighting'''
def _execute(self, w, **vargs):
lines = []
for (w, p1, p2) in w.application.highlighted_ranges:
lines.append("%r %s %s" % (w, p1, p2))
output = "\n".join(lines)
w.application.data_buffer("region-dump", output, switch_to=True)
class DumpMarkers(Method):
'''Dump all tab markers (tab debugging)'''
def _execute(self, w, **vargs):
lines = []
if w.mode.tabber:
keys = w.mode.tabber.lines.keys()
keys.sort()
for i in keys:
line = w.mode.tabber.lines[i]
lines.append("LINE %d: %r" % (i, line))
lines.append(" %s" % repr(w.mode.tabber.record[i]))
else:
lines.append("no tokens")
output = "\n".join(lines)
w.application.data_buffer("marker-dump", output, switch_to=True)
class DumpTokens(Method):
'''Dump all lexical tokens (syntax highlighting debugging)'''
def _execute(self, w, **vargs):
modename = w.mode.name()
lines = []
if modename in w.buffer.highlights:
tokens = w.buffer.highlights[modename].tokens
for i in range(0, len(tokens)):
lines.append("LINE %d" % i)
group = tokens[i]
for token in group:
fqname = token.fqname()
p1 = Point(token.x, token.y)
if token.parent is None:
pcoord = ''
else:
pcoord = '[%d, %d]' % (token.parent.x, token.parent.y)
if fqname in w.mode.ghist and p1 in w.mode.ghist[fqname]:
g = '[' + w.mode.ghist[fqname][p1].name() + ']'
else:
g = ''
fields = (str(p1), pcoord, token.fqname(), g, token.string)
lines.append(' %-10s %-10s %-20s %-10s %r' % fields)
else:
lines.append("no tokens")
output = "\n".join(lines)
w.application.data_buffer("token-dump", output, switch_to=True)
class MetaX(Method):
'''Invoke commands by name'''
args = [Argument('method', datatype="method", prompt="M-x ")]
@ -598,16 +341,25 @@ class InsertSpace(Method):
'''Insert space into buffer at the cursor'''
def _execute(self, w, **vargs):
w.insert_string_at_cursor(' ')
class GetIndentionLevel(Method):
'''Calculate the indention level for this line'''
class InsertSquotes(Method):
'''Insert a pair of single-quotes into the buffer'''
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)
w.insert_string_at_cursor("''")
w.backward()
class InsertDquotes(Method):
'''Insert a pair of double-quotes into the buffer'''
def _execute(self, w, **vargs):
w.insert_string_at_cursor('""')
w.backward()
class InsertEscapedSquote(Method):
'''Insert an escaped single-quote'''
def _execute(self, w, **vargs):
w.insert_string_at_cursor("\\'")
class InsertEscapedDquote(Method):
'''Insert an escaped double-quote'''
def _execute(self, w, **vargs):
w.insert_string_at_cursor('\\"')
class InsertTab(Method):
'''Insert tab into buffer, or tabbify line, depending on mode'''
@ -627,6 +379,7 @@ class InsertTab(Method):
w.insert_string(Point(0, cursor.y), ' ' * i)
else:
w.goto(Point(j, cursor.y))
class KillWhitespace(Method):
'''Delete leading whitespace on current line'''
def _execute(self, w, **vargs):
@ -645,6 +398,16 @@ class TabBuffer(Method):
w.goto_line(i)
it.execute(w)
w.goto_line(y)
class GetIndentionLevel(Method):
'''Calculate the indention level for this line'''
def _execute(self, w, **vargs):
cursor = w.logical_cursor()
if not w.mode.tabber:
w.set_error('No tabber available')
return
else:
i = w.mode.tabber.get_level(cursor.y)
w.set_error('Indention level: %r' % i)
# commenting
class CommentRegion(Method):
@ -899,79 +662,6 @@ class Redo(Method):
except Exception, e:
w.set_error("%s" % (e))
# w navigation methods
class StartOfLine(Method):
'''Move the cursor to the start of the current line'''
def _execute(self, w, **vargs):
w.start_of_line()
class EndOfLine(Method):
'''Move the cursor to the end of the current line'''
def _execute(self, w, **vargs):
w.end_of_line()
class Forward(Method):
'''Move the cursor right one character'''
def _execute(self, w, **vargs):
w.forward()
class Backward(Method):
'''Move the cursor left one character'''
def _execute(self, w, **vargs):
w.backward()
class NextLine(Method):
'''Move the cursor down one line'''
def _execute(self, w, **vargs):
w.next_line()
class PreviousLine(Method):
'''Move the cursor up one line'''
def _execute(self, w, **vargs):
w.previous_line()
class PageUp(Method):
'''Move the cursor up one page'''
def _execute(self, w, **vargs):
w.page_up()
class PageDown(Method):
'''Move the cursor down one page'''
def _execute(self, w, **vargs):
w.page_down()
class GotoBeginning(Method):
'''Move the cursor to the beginning of the buffer'''
def _execute(self, w, **vargs):
w.goto_beginning()
class GotoEnd(Method):
'''Move the cursor to the end of the buffer'''
def _execute(self, w, **vargs):
w.goto_end()
class RightWord(Method):
'''Move the cursor to the start of the word to the right'''
def _execute(self, w, **vargs):
w.right_word()
class LeftWord(Method):
'''Move the cursor to the start of the word to the left'''
def _execute(self, w, **vargs):
w.left_word()
class NextSection(Method):
'''Move the cursor to the next section'''
def _execute(self, w, **vargs):
cursor = w.logical_cursor()
i = cursor.y + 1
seen_null_line = False
while i < len(w.buffer.lines):
if seen_null_line:
w.goto_line(i)
break
seen_null_line = regex.whitespace.match(w.buffer.lines[i])
i += 1
class PreviousSection(Method):
'''Move the cursor to the previous section'''
def _execute(self, w, **vargs):
cursor = w.logical_cursor()
i = cursor.y - 1
seen_null_line = False
while i >= 0:
if seen_null_line:
w.goto_line(i)
break
seen_null_line = regex.whitespace.match(w.buffer.lines[i])
i -= 1
class UnindentBlock(Method):
'''Prepend 4 spaces to each line in region'''
def _execute(self, w, **vargs):
@ -1011,32 +701,6 @@ class IndentBlock(Method):
w.buffer.delete(Point(0, p1.y), Point(0, p2.y))
w.buffer.insert_string(Point(0, p1.y), '\n'.join(lines) + '\n')
class OpenConsole(Method):
'''Evaluate python expressions (for advanced use and debugging only)'''
def execute(self, w, **vargs):
a = w.application
if not a.has_buffer_name('*Console*'):
b = buffer.ConsoleBuffer()
a.add_buffer(b)
window.Window(b, a)
b = a.bufferlist.get_buffer_by_name('*Console*')
if a.window().buffer is not b:
a.switch_buffer(b)
f = lambda x: None
w.application.open_mini_buffer('>>> ', f, self, None, 'consolemini')
class ShellCmd(Method):
'''Run a command in a shell and put the output in a new buffer'''
args = [Argument("cmd", type=type(""), prompt="$ ", datatype='shell')]
def _execute(self, w, **vargs):
cmd = "PBUF='%s'; %s" % (w.buffer.name(), vargs['cmd'])
(status, data) = commands.getstatusoutput(cmd)
if status == 0:
mesg = 'ok'
else:
mesg = 'error'
data += "\nprocess exited with status %d (%s)" % (status, mesg)
w.application.data_buffer("*Shell*", data, switch_to=True)
class FileDiff(Method):
'''diff the buffer's contents with the given file'''
args = [Argument("path", type=type(""), prompt="Filename: ", datatype='path')]
@ -1062,109 +726,6 @@ class FileDiff(Method):
w.application.data_buffer("*Diff*", errdata, switch_to=True)
w.set_error("There was an error: %d exited with status %s" % (pid, status))
class ShowBindingsBuffer(Method):
'''Dump all keybindings for current mode into a new buffer'''
def _execute(self, w, **vargs):
lines = []
mode_name = w.mode.name()
lines.append('Key bindings for mode %r:' % (mode_name))
lines.append('')
names_to_sequences = {}
seq_len = len('BINDINGS')
name_len = len('ACTION')
for seq in w.mode.bindings:
name = w.mode.bindings[seq]
if name.startswith('insert-string-'):
# we aren't going to show all the generic keypress actions
continue
# determine this for formatting
seq_len = max(seq_len, len(seq))
name_len = max(name_len, len(name))
# set up our new data structure
names_to_sequences.setdefault(name, [])
names_to_sequences[name].append(seq)
# generate the format string (note the 'meta formatting')
format_str = '%%-%ds %%-%ds %%s' % (seq_len, name_len)
lines.append(format_str % ('BINDINGS', 'ACTIONS', 'HELP'))
names = names_to_sequences.keys()
names.sort()
for name in names:
sequences = names_to_sequences[name]
sequences.sort()
seq = sequences[0]
help = w.application.methods[name].help
if help is None:
help = ''
lines.append(format_str % (seq, name, help))
for seq2 in sequences[1:]:
lines.append(format_str % (seq2, '', ''))
data = '\n'.join(lines)
w.application.data_buffer("*Bindings-Help*", data, switch_to=True)
class CmdHelpBuffer(Method):
'''Get help with the specified command'''
args = [Argument('method', datatype="method", prompt="Help for command: ")]
def _execute(self, w, **vargs):
lines = []
name = vargs['method']
if name not in w.application.methods:
err = "No command called %r in mode %r" % (name, w.mode.name)
raise Exception, err
m = w.application.methods[name]
lines.append('HELP FOR %r' % name)
lines.append('')
# sequences
sequences = []
for seq in w.mode.bindings:
if w.mode.bindings[seq] == name:
sequences.append(seq)
sequences.sort()
lines.append('Keys bound to this command:')
for seq in sequences:
lines.append(' %s' % (seq))
lines.append('')
# arguments
if m.args:
lines.append('Arguments for this command:')
for arg in m.args:
if arg.datatype is None:
if arg.type == type(""):
t = 'str'
elif arg.type == type(0):
t = 'int'
elif arg.type == type(0.0):
t = 'float'
else:
t = 'str'
else:
t = arg.datatype
if arg.help:
lines.append(' %s %r: %s' % (t, arg.name, arg.help))
else:
lines.append(' %s %r' % (t, arg.name))
lines.append('')
# help text
lines.append('Help text for this command:')
h = m.help
if not h:
h = 'No help available'
lines.append(' %s' % h)
data = '\n'.join(lines)
w.application.data_buffer("*Command-Help*", data, switch_to=True)
class SetMode(Method):
'''Set the mode of the current buffer'''
args = [Argument('mode', datatype='mode', prompt="Enter new mode: ")]
@ -1174,16 +735,6 @@ class SetMode(Method):
w.set_mode(m)
w.set_error('Set mode to %r' % (mode_name))
class WhichCommand(Method):
'''Display which command is run for a given key-sequence'''
def _execute(self, w, **vargs):
self.old_window = w
w.application.open_mini_buffer('Enter a key sequence to be explained: ',
lambda x: None,
self,
None,
'which')
class Cancel(Method):
'''Cancel command in-progress, and return to the main buffer'''
def execute(self, w, **vargs):
@ -1207,29 +758,6 @@ class UnsplitWindow(Method):
w.application.single_slot()
w.set_error('Window has been unsplit back to one window!')
class SomethingCrazy(Method):
def _execute(self, w, **vargs):
pass
class InsertSquotes(Method):
'''Insert a pair of single-quotes into the buffer'''
def _execute(self, w, **vargs):
w.insert_string_at_cursor("''")
w.backward()
class InsertDquotes(Method):
'''Insert a pair of double-quotes into the buffer'''
def _execute(self, w, **vargs):
w.insert_string_at_cursor('""')
w.backward()
class InsertEscapedSquote(Method):
'''Insert an escaped single-quote'''
def _execute(self, w, **vargs):
w.insert_string_at_cursor("\\'")
class InsertEscapedDquote(Method):
'''Insert an escaped double-quote'''
def _execute(self, w, **vargs):
w.insert_string_at_cursor('\\"')
class CloseTag(Method):
mytag = ')'
def _execute(self, w, **vargs):
@ -1290,15 +818,6 @@ class CloseBrace(CloseTag):
class CloseBracket(CloseTag):
mytag = ']'
class GetToken(Method):
'''View type and data of the "current" token'''
def _execute(self, w, **vargs):
token = w.get_token()
if token is None:
w.set_error('No Token')
else:
w.set_error('Token: %r (%s)' % (token.string, token.fqname()))
class RegisterSave(Method):
MAX_TXT = 30
MAX_REG = 20
@ -1334,129 +853,3 @@ class RegisterRestore(Method):
if len(name) > self.MAX_REG:
name = name[0:self.MAX_REG] + '...'
w.set_error('Restored %r from register %r' % (text2, name2))
class Pipe(Method):
'''Pipe the buffer's contents through the command, and display the output in a new buffer'''
args = [Argument('cmd', datatype="str", prompt="Command: ")]
def _parse(self, w, **vargs):
m = regex.shell_command.match(vargs['cmd'])
if m:
prog = m.group(0)
return (prog, vargs['cmd'])
else:
return (None, None)
def _execute(self, w, **vargs):
(prog, cmd) = self._parse(w, **vargs)
if prog is None:
return
pipe = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
pid = pipe.pid
indata = w.buffer.make_string()
pipe.stdin.write(indata)
pipe.stdin.close()
outdata = pipe.stdout.read()
status = pipe.wait() >> 8
bufname = '*%s*' % self.name.title()
w.application.data_buffer(bufname, outdata, switch_to=True)
w.set_error("%s exited with status %d" % (prog, status))
class Grep(Pipe):
'''Grep the buffer's contents for instances of a pattern, and display them in a new buffer'''
args = [Argument('pattern', datatype="str", prompt="Pattern: ")]
def _parse(self, w, **vargs):
return ('grep', ('/usr/bin/grep', '-E', '-n', vargs['pattern']))
class Exec(Method):
args = [Argument('cmd', datatype="str", prompt="Exec: ")]
def _doit(self, w, path, cmd):
try:
cmd = cmd % path
except:
w.set_error("Malformed command: %r" % cmd)
return
(status, output) = commands.getstatusoutput(cmd)
bufname = '*%s*' % self.name.title()
w.application.data_buffer(bufname, output, switch_to=True)
w.set_error("Shell exited with %d" % status)
def _execute(self, w, **vargs):
if w.buffer.btype == 'dir':
name = dirutil.resolve_name(w)
path = dirutil.resolve_path(w)
self._doit(w, path, vargs['cmd'])
dirutil.find_name(w, name)
elif hasattr(w.buffer, 'path'):
path = w.buffer.path
self._doit(w, path, vargs['cmd'])
else:
w.set_error("Don't know how to exec: %r" % w.buffer)
return
class TokenComplete(Method):
'''Complete token names based on other tokens in the buffer'''
name_overrides = {}
def _min_completion(self, w, t):
h = w.get_highlighter()
minlen = None
if t.name in self.name_overrides:
ok = name_overrides[t.name]
else:
ok = (t.name,)
strings = {}
for line in h.tokens:
for t2 in line:
if t2 is t:
continue
elif False and t2.name not in ok:
continue
elif t2.string.startswith(t.string):
strings[t2.string] = 1
if minlen is None:
minlen = len(t2.string)
else:
minlen = min(minlen, len(t2.string))
strings = strings.keys()
if not strings:
return ([], t.string)
i = len(t.string)
while i < minlen:
c = strings[0][i]
for s in strings:
if s[i] != c:
return (strings, strings[0][:i])
i += 1
return (strings, strings[0][:minlen])
def _execute(self, w, **vargs):
t = w.get_token2()
if t is None:
w.set_error("No token to complete!")
return
elif regex.reserved_token_names.match(t.name):
w.set_error("Will not complete reserved token")
return
(candidates, result) = self._min_completion(w, t)
if candidates:
p1 = Point(t.x, t.y)
p2 = Point(t.end_x(), t.y)
w.buffer.delete(p1, p2)
w.insert_string(p1, result)
if not candidates:
w.set_error("No completion: %r" % result)
elif len(candidates) == 1:
w.set_error("Unique completion: %r" % result)
elif result in candidates:
w.set_error("Ambiguous completion: %r" % candidates)
else:
w.set_error("Partial completion: %r" % candidates)

125
method/buffers.py Normal file
View File

@ -0,0 +1,125 @@
import os, commands, re, sets, tempfile
from subprocess import Popen, PIPE, STDOUT
import buffer, default, dirutil, regex, util, window
from point import Point
from method import DATATYPES, Method, Argument
class OpenFile(Method):
'''Open file in a new buffer, or go to file's open buffer'''
args = [Argument('filename', datatype="path", prompt="Open File: ",
default=default.path_dirname, load_default=True)]
def _execute(self, w, **vargs):
b = w.application.open_path(vargs['filename'])
SwitchBuffer().execute(w, buffername=b.name())
class OpenAesFile(Method):
'''Open AES encrypted file in a new buffer, or go to file's open buffer'''
args = [Argument('filename', datatype="path", prompt="Open AES File: "),
Argument('password', prompt="Use AES Password: ")]
def _execute(self, w, **vargs):
b = w.application.open_path(vargs['filename'], 'aes', vargs['password'])
SwitchBuffer().execute(w, buffername=b.name())
return
class ViewBufferParent(Method):
def _execute(self, w, **vargs):
b = w.buffer
if not hasattr(b, 'path'):
w.set_error('Buffer has no path')
elif b.path == '/':
w.set_error("Root directory has no parent")
else:
path = os.path.dirname(b.path)
w.application.methods['open-file'].execute(w, filename=path)
class SwitchBuffer(Method):
'''Switch to a different'''
args = [Argument('buffername', datatype="buffer", prompt="Switch To Buffer: ",
default=default.last_buffer)]
def _pre_execute(self, w, **vargs):
a = w.application
if len(a.bufferlist.buffers) < 1:
raise Exception, "No other buffers"
def _execute(self, w, **vargs):
name = vargs['buffername']
buf = None
if w.application.has_buffer_name(name):
b = w.application.bufferlist.get_buffer_by_name(name)
w.application.switch_buffer(b)
else:
w.set_error("buffer %r was not found" % name)
class KillBuffer(Method):
'''Close the current buffer'''
force=False
args = [Argument('buffername', datatype="buffer", prompt="Kill Buffer: ",
default=default.current_buffer)]
def _execute(self, w, **vargs):
name = vargs['buffername']
a = w.application
assert name in a.bufferlist.buffer_names, "Buffer %r does not exist" % name
assert name != '*Scratch*', "Can't kill scratch buffer"
self._to_kill = a.bufferlist.buffer_names[name]
self._old_window = w
if self.force or not self._to_kill.changed():
self._doit()
else:
self._prompt = "Buffer has unsaved changes; kill anyway? "
a.open_mini_buffer(self._prompt, self._callback)
def _doit(self):
a = self._old_window.application
b = self._to_kill
if a.bufferlist.is_buffer_visible(b):
a.bufferlist.set_slot(a.active_slot, a.bufferlist.hidden_buffers[0])
a.bufferlist.remove_buffer(b)
b.close()
def _callback(self, v):
a = self._old_window.application
if v == 'yes':
self._doit()
a.close_mini_buffer()
elif v == 'no':
a.close_mini_buffer()
else:
a.close_mini_buffer()
a.set_error('Please type "yes" or "no"')
class ForceKillBuffer(KillBuffer):
force=True
args = [Argument('buffername', datatype="buffer", prompt="Force Kill Buffer: ",
default=default.current_buffer)]
class ListBuffers(Method):
'''List all open buffers in a new buffer'''
def _execute(self, w, **vargs):
bl = w.application.bufferlist
bnames = [b.name() for b in bl.buffers]
bnames.sort()
data = '\n'.join(bnames)
w.application.data_buffer("*Buffers*", data, switch_to=True)
class SaveBufferAs(Method):
'''Save the contents of a buffer to the specified path'''
args = [Argument('path', datatype="path", prompt="Write file: ",
default=default.current_working_dir, load_default=True)]
def _execute(self, w, **vargs):
curr_buffer = w.buffer
curr_buffer_name = curr_buffer.name()
data = curr_buffer.make_string()
path = os.path.realpath(os.path.expanduser(vargs['path']))
w.set_error("got %r (%d)" % (path, len(data)))
if w.application.has_buffer_name(path):
w.set_error("buffer for %r is already open" % path)
return
w.application.file_buffer(path, data, switch_to=True)
if curr_buffer_name != '*Scratch*':
w.application.methods['kill-buffer'].execute(w, buffername=curr_buffer_name)
else:
curr_buffer.set_data('')
w.set_error('Wrote %r' % path)
class SaveBuffer(Method):
'''Save the contents of a buffer'''
def _execute(self, w, **vargs):
if w.buffer.changed():
w.buffer.save()
w.set_error("Wrote %s" % (w.buffer.path))
else:
w.set_error("(No changes need to be saved)")

132
method/help.py Normal file
View File

@ -0,0 +1,132 @@
import os, commands, re, sets, tempfile
from subprocess import Popen, PIPE, STDOUT
import buffer, default, dirutil, regex, util, window
from point import Point
from method import DATATYPES, Method, Argument
class ShowBindingsBuffer(Method):
'''Dump all keybindings for current mode into a new buffer'''
def _execute(self, w, **vargs):
lines = []
mode_name = w.mode.name()
lines.append('Key bindings for mode %r:' % (mode_name))
lines.append('')
names_to_sequences = {}
seq_len = len('BINDINGS')
name_len = len('ACTION')
for seq in w.mode.bindings:
name = w.mode.bindings[seq]
if name.startswith('insert-string-'):
# we aren't going to show all the generic keypress actions
continue
# determine this for formatting
seq_len = max(seq_len, len(seq))
name_len = max(name_len, len(name))
# set up our new data structure
names_to_sequences.setdefault(name, [])
names_to_sequences[name].append(seq)
# generate the format string (note the 'meta formatting')
format_str = '%%-%ds %%-%ds %%s' % (seq_len, name_len)
lines.append(format_str % ('BINDINGS', 'ACTIONS', 'HELP'))
names = names_to_sequences.keys()
names.sort()
for name in names:
sequences = names_to_sequences[name]
sequences.sort()
seq = sequences[0]
help = w.application.methods[name].help
if help is None:
help = ''
lines.append(format_str % (seq, name, help))
for seq2 in sequences[1:]:
lines.append(format_str % (seq2, '', ''))
data = '\n'.join(lines)
w.application.data_buffer("*Bindings-Help*", data, switch_to=True)
class CmdHelpBuffer(Method):
'''Get help with the specified command'''
args = [Argument('method', datatype="method", prompt="Help for command: ")]
def _execute(self, w, **vargs):
lines = []
name = vargs['method']
if name not in w.application.methods:
err = "No command called %r in mode %r" % (name, w.mode.name)
raise Exception, err
m = w.application.methods[name]
lines.append('HELP FOR %r' % name)
lines.append('')
# sequences
sequences = []
for seq in w.mode.bindings:
if w.mode.bindings[seq] == name:
sequences.append(seq)
sequences.sort()
lines.append('Keys bound to this command:')
for seq in sequences:
lines.append(' %s' % (seq))
lines.append('')
# arguments
if m.args:
lines.append('Arguments for this command:')
for arg in m.args:
if arg.datatype is None:
if arg.type == type(""):
t = 'str'
elif arg.type == type(0):
t = 'int'
elif arg.type == type(0.0):
t = 'float'
else:
t = 'str'
else:
t = arg.datatype
if arg.help:
lines.append(' %s %r: %s' % (t, arg.name, arg.help))
else:
lines.append(' %s %r' % (t, arg.name))
lines.append('')
# help text
lines.append('Help text for this command:')
h = m.help
if not h:
h = 'No help available'
lines.append(' %s' % h)
data = '\n'.join(lines)
w.application.data_buffer("*Command-Help*", data, switch_to=True)
class WhichCommand(Method):
'''Display which command is run for a given key-sequence'''
def _execute(self, w, **vargs):
self.old_window = w
w.application.open_mini_buffer('Enter a key sequence to be explained: ',
lambda x: None,
self,
None,
'which')
class AboutPmacs(Method):
'''print some information about pmacs'''
def _execute(self, w, **vargs):
a = w.application
if not a.has_buffer_name('*About*'):
b = buffer.AboutBuffer()
a.add_buffer(b)
window.Window(b, a)
b = a.bufferlist.get_buffer_by_name('*About*')
if a.window().buffer is not b:
a.switch_buffer(b)

148
method/introspect.py Normal file
View File

@ -0,0 +1,148 @@
import os, commands, re, sets, tempfile
from subprocess import Popen, PIPE, STDOUT
import buffer, default, dirutil, regex, util, window
from point import Point
from method import DATATYPES, Method, Argument
class DumpRegions(Method):
'''debug region highlighting'''
def _execute(self, w, **vargs):
lines = []
for (w, p1, p2) in w.application.highlighted_ranges:
lines.append("%r %s %s" % (w, p1, p2))
output = "\n".join(lines)
w.application.data_buffer("region-dump", output, switch_to=True)
class DumpMarkers(Method):
'''Dump all tab markers (tab debugging)'''
def _execute(self, w, **vargs):
lines = []
if w.mode.tabber:
keys = w.mode.tabber.lines.keys()
keys.sort()
for i in keys:
line = w.mode.tabber.lines[i]
lines.append("LINE %d: %r" % (i, line))
lines.append(" %s" % repr(w.mode.tabber.record[i]))
else:
lines.append("no tokens")
output = "\n".join(lines)
w.application.data_buffer("marker-dump", output, switch_to=True)
class DumpTokens(Method):
'''Dump all lexical tokens (syntax highlighting debugging)'''
def _execute(self, w, **vargs):
modename = w.mode.name()
lines = []
if modename in w.buffer.highlights:
tokens = w.buffer.highlights[modename].tokens
for i in range(0, len(tokens)):
lines.append("LINE %d" % i)
group = tokens[i]
for token in group:
fqname = token.fqname()
p1 = Point(token.x, token.y)
if token.parent is None:
pcoord = ''
else:
pcoord = '[%d, %d]' % (token.parent.x, token.parent.y)
if fqname in w.mode.ghist and p1 in w.mode.ghist[fqname]:
g = '[' + w.mode.ghist[fqname][p1].name() + ']'
else:
g = ''
fields = (str(p1), pcoord, token.fqname(), g, token.string)
lines.append(' %-10s %-10s %-20s %-10s %r' % fields)
else:
lines.append("no tokens")
output = "\n".join(lines)
w.application.data_buffer("token-dump", output, switch_to=True)
class GetToken(Method):
'''View type and data of the "current" token'''
def _execute(self, w, **vargs):
token = w.get_token()
if token is None:
w.set_error('No Token')
else:
w.set_error('Token: %r (%s)' % (token.string, token.fqname()))
class TokenComplete(Method):
'''Complete token names based on other tokens in the buffer'''
name_overrides = {}
def _min_completion(self, w, t):
h = w.get_highlighter()
minlen = None
if t.name in self.name_overrides:
ok = name_overrides[t.name]
else:
ok = (t.name,)
strings = {}
for line in h.tokens:
for t2 in line:
if t2 is t:
continue
elif False and t2.name not in ok:
continue
elif t2.string.startswith(t.string):
strings[t2.string] = 1
if minlen is None:
minlen = len(t2.string)
else:
minlen = min(minlen, len(t2.string))
strings = strings.keys()
if not strings:
return ([], t.string)
i = len(t.string)
while i < minlen:
c = strings[0][i]
for s in strings:
if s[i] != c:
return (strings, strings[0][:i])
i += 1
return (strings, strings[0][:minlen])
def _execute(self, w, **vargs):
t = w.get_token2()
if t is None:
w.set_error("No token to complete!")
return
elif regex.reserved_token_names.match(t.name):
w.set_error("Will not complete reserved token")
return
(candidates, result) = self._min_completion(w, t)
if candidates:
p1 = Point(t.x, t.y)
p2 = Point(t.end_x(), t.y)
w.buffer.delete(p1, p2)
w.insert_string(p1, result)
if not candidates:
w.set_error("No completion: %r" % result)
elif len(candidates) == 1:
w.set_error("Unique completion: %r" % result)
elif result in candidates:
w.set_error("Ambiguous completion: %r" % candidates)
else:
w.set_error("Partial completion: %r" % candidates)
class OpenConsole(Method):
'''Evaluate python expressions (for advanced use and debugging only)'''
def execute(self, w, **vargs):
a = w.application
if not a.has_buffer_name('*Console*'):
b = buffer.ConsoleBuffer()
a.add_buffer(b)
window.Window(b, a)
b = a.bufferlist.get_buffer_by_name('*Console*')
if a.window().buffer is not b:
a.switch_buffer(b)
f = lambda x: None
w.application.open_mini_buffer('>>> ', f, self, None, 'consolemini')

118
method/move.py Normal file
View File

@ -0,0 +1,118 @@
import os, commands, re, sets, tempfile
from subprocess import Popen, PIPE, STDOUT
import buffer, default, dirutil, regex, util, window
from point import Point
from method import DATATYPES, Method, Argument
class StartOfLine(Method):
'''Move the cursor to the start of the current line'''
def _execute(self, w, **vargs):
w.start_of_line()
class EndOfLine(Method):
'''Move the cursor to the end of the current line'''
def _execute(self, w, **vargs):
w.end_of_line()
class Forward(Method):
'''Move the cursor right one character'''
def _execute(self, w, **vargs):
w.forward()
class Backward(Method):
'''Move the cursor left one character'''
def _execute(self, w, **vargs):
w.backward()
class NextLine(Method):
'''Move the cursor down one line'''
def _execute(self, w, **vargs):
w.next_line()
class PreviousLine(Method):
'''Move the cursor up one line'''
def _execute(self, w, **vargs):
w.previous_line()
class PageUp(Method):
'''Move the cursor up one page'''
def _execute(self, w, **vargs):
w.page_up()
class PageDown(Method):
'''Move the cursor down one page'''
def _execute(self, w, **vargs):
w.page_down()
class GotoBeginning(Method):
'''Move the cursor to the beginning of the buffer'''
def _execute(self, w, **vargs):
w.goto_beginning()
class GotoEnd(Method):
'''Move the cursor to the end of the buffer'''
def _execute(self, w, **vargs):
w.goto_end()
class RightWord(Method):
'''Move the cursor to the start of the word to the right'''
def _execute(self, w, **vargs):
w.right_word()
class LeftWord(Method):
'''Move the cursor to the start of the word to the left'''
def _execute(self, w, **vargs):
w.left_word()
class NextSection(Method):
'''Move the cursor to the next section'''
def _execute(self, w, **vargs):
cursor = w.logical_cursor()
i = cursor.y + 1
seen_null_line = False
while i < len(w.buffer.lines):
if seen_null_line:
w.goto_line(i)
break
seen_null_line = regex.whitespace.match(w.buffer.lines[i])
i += 1
class PreviousSection(Method):
'''Move the cursor to the previous section'''
def _execute(self, w, **vargs):
cursor = w.logical_cursor()
i = cursor.y - 1
seen_null_line = False
while i >= 0:
if seen_null_line:
w.goto_line(i)
break
seen_null_line = regex.whitespace.match(w.buffer.lines[i])
i -= 1
class GotoChar(Method):
'''Jump to the specified character'''
args = [Argument("charno", type=type(0), prompt="Goto char: ")]
def _execute(self, w, **vargs):
w.goto_char(vargs["charno"])
class ForwardChars(Method):
'''Move forward the specified number of characters'''
args = [Argument("charno", type=type(0), prompt="Forward chars: ")]
def _execute(self, w, **vargs):
w.forward_chars(vargs["charno"])
class GotoLine(Method):
'''Jump to the specified line number'''
args = [Argument("lineno", type=type(0), prompt="Goto line: ")]
def _execute(self, w, **vargs):
n = vargs["lineno"]
if n < 0:
n = len(w.buffer.lines) + n + 1
if n > len(w.buffer.lines):
n = len(w.buffer.lines)
elif n < 1:
n = 1
w.goto_line(n)
class ForwardLines(Method):
'''Move forward the specified number of characters'''
args = [Argument("lineno", type=type(0), prompt="Forward lines: ")]
def _execute(self, w, **vargs):
w.forward_lines(vargs["lineno"])

55
method/search.py Normal file
View File

@ -0,0 +1,55 @@
import os, commands, re, sets, tempfile
from subprocess import Popen, PIPE, STDOUT
import buffer, default, dirutil, regex, util, window
from point import Point
from method import DATATYPES, Method, Argument
class Search(Method):
'''Interactive search; finds next occurance of text in buffer'''
is_literal = True
direction = 'next'
prompt = 'I-Search: '
def execute(self, w, **vargs):
self.old_cursor = w.logical_cursor()
self.old_window = w
w.application.open_mini_buffer(self.prompt, lambda x: None, self, None, 'search')
class ReverseSearch(Search):
'''Interactive search; finds previous occurance of text in buffer'''
direction = 'previous'
class RegexSearch(Search):
'''Interactive search; finds next occurance of regex in buffer'''
is_literal = False
prompt = 'I-RegexSearch: '
class RegexReverseSearch(RegexSearch):
'''Interactive search; finds prevoius occurance of regex in buffer'''
direction = 'previous'
class Replace(Method):
'''Replace occurances of string X with string Y'''
is_literal = True
args = [Argument('before', prompt="Replace String: ",
default=default.last_replace_before, load_default=True),
Argument('after', prompt="Replace With: ",
default=default.last_replace_after, load_default=True)]
def _execute(self, w, **vargs):
a = w.application
a.last_replace_before = self.before = vargs['before']
a.last_replace_after = self.after = vargs['after']
self.old_window = w
a.open_mini_buffer('I-Replace: ', lambda x: None, self, None, 'replace')
class RegexReplace(Method):
'''Replace occurances of string X with string Y'''
is_literal = False
args = [Argument('before', prompt="Replace Regex: ",
default=default.last_replace_before, load_default=True),
Argument('after', prompt="Replace With: ",
default=default.last_replace_after, load_default=True)]
def _execute(self, w, **vargs):
w.application.last_replace_before = self.before = vargs['before']
w.application.last_replace_after = self.after = vargs['after']
self.old_window = w
f = lambda x: None
w.application.open_mini_buffer('I-RegexReplace: ', f, self, None, 'replace')

74
method/shell.py Normal file
View File

@ -0,0 +1,74 @@
import os, commands, re, sets, tempfile
from subprocess import Popen, PIPE, STDOUT
import buffer, default, dirutil, regex, util, window
from point import Point
from method import DATATYPES, Method, Argument
class Exec(Method):
'''Execute a command in a shell and put the output in a new buffer'''
args = [Argument('cmd', prompt="Exec: ", datatype='shell')]
def _doit(self, w, path, cmd):
if path:
try:
cmd = cmd % {'path': path}
except:
pass
(status, output) = commands.getstatusoutput(cmd)
bufname = '*%s*' % self.name.title()
w.application.data_buffer(bufname, output, switch_to=True)
w.set_error("Shell exited with %d" % status)
def _execute(self, w, **vargs):
if w.buffer.btype == 'dir':
name = dirutil.resolve_name(w)
path = dirutil.resolve_path(w)
self._doit(w, path, vargs['cmd'])
dirutil.find_name(w, name)
elif hasattr(w.buffer, 'path'):
path = w.buffer.path
self._doit(w, path, vargs['cmd'])
else:
self._doit(w, None, vargs['cmd'])
class Pipe(Method):
'''Pipe the buffer's contents through the command, and display the output in a new buffer'''
args = [Argument('cmd', datatype="str", prompt="Command: ")]
def _parse(self, w, **vargs):
# return 3 things: prog name, cmd, and whether to use the shell
m = regex.shell_command.match(vargs['cmd'])
if m:
prog = m.group(0)
return (prog, vargs['cmd'], True)
else:
return (None, None, False)
def _execute(self, w, **vargs):
(prog, cmd, shell) = self._parse(w, **vargs)
if prog is None or not cmd:
return
pipe = Popen(cmd, shell=shell, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
pid = pipe.pid
indata = w.buffer.make_string()
pipe.stdin.write(indata)
pipe.stdin.close()
outdata = pipe.stdout.read()
status = pipe.wait() >> 8
bufname = '*%s*' % self.name.title()
w.application.data_buffer(bufname, outdata, switch_to=True)
w.set_error("%s exited with status %d" % (prog, status))
class Grep(Pipe):
'''Grep the buffer's contents for instances of a pattern, and display them in a new buffer'''
args = [Argument('pattern', datatype="str", prompt="Pattern: ")]
def _parse(self, w, **vargs):
return ('grep', ('grep', '-E', '-n', vargs['pattern']), False)
class Sed(Pipe):
'''Push the buffer's contents through a sed expression'''
args = [Argument('expression', datatype="str", prompt="Expression: ")]
def _parse(self, w, **vargs):
return ('grep', ('sed', '-r', '-e', vargs['expression']), False)

View File

@ -170,7 +170,6 @@ class Fundamental(Handler):
self.add_bindings('indent-block', ('C-c >',))
self.add_bindings('unindent-block', ('C-c <',))
self.add_bindings('token-complete', ('M-c', 'C-c c', 'C-c TAB',))
self.add_bindings('shell-cmd', ('C-c !',))
self.add_bindings('open-aes-file', ('C-c a',))
self.add_bindings('open-console', ('M-e',))
self.add_bindings('show-bindings-buffer', ('C-c M-h','C-c M-?',))
@ -178,7 +177,7 @@ class Fundamental(Handler):
self.add_bindings('cmd-help-buffer', ('M-h',))
self.add_bindings('set-mode', ('C-x m',))
self.add_bindings('cancel', ('C-]',))
self.add_bindings('exec', ('C-c e',))
self.add_bindings('exec', ('C-c e', 'C-c !'))
self.add_bindings('grep', ('C-c g',))
self.add_bindings('pipe', ('C-c p',))
self.add_bindings('view-buffer-parent', ('C-c .',))
@ -188,9 +187,6 @@ class Fundamental(Handler):
self.add_bindings('insert-escaped-dquote', ('C-c M-"',))
self.add_bindings('get-token', ('C-c t',))
# unbound actions
self.add_action(method.GetToken())
# create all the insert actions for the basic text input
for c in string.letters + string.digits + string.punctuation:
self.add_binding('insert-string-%s' % c, c)