pmacs3/mode/consolemini.py

215 lines
7.7 KiB
Python

import code, re, string, StringIO, sets, sys, traceback
import color, completer, lex, method, mode
from lex import Grammar, PatternRule
from mode.python import PythonGrammar
from point import Point
class ConsoleMini(mode.Fundamental):
modename = 'ConsoleMini'
grammar = PythonGrammar
def __init__(self, w):
mode.Fundamental.__init__(self, w)
self.bindings = {}
self.globals = dict(w.application.globals())
self.locals = dict(w.application.locals())
self.saved_input = ""
self.history = ['']
self.hindex = 0
self.add_bindings('start-of-line', ('C-a', 'HOME',))
self.add_bindings('end-of-line', ('C-e', 'END',))
self.add_bindings('backward', ('C-b', 'L_ARROW',))
self.add_bindings('forward', ('C-f', 'R_ARROW',))
self.add_bindings('delete-left', ('DELETE', 'BACKSPACE',))
self.add_bindings('delete-left-word', ('M-DELETE', 'M-BACKSPACE',))
self.add_bindings('delete-right', ('C-d',))
self.add_bindings('delete-right-word', ('M-d',))
self.add_bindings('kill-region', ('C-w',))
self.add_bindings('copy-region', ('M-w',))
self.add_bindings('kill', ('C-k',))
self.add_bindings('copy', ('M-k',))
self.add_bindings('yank', ('C-y',))
self.add_bindings('pop-kill', ('M-y',))
self.add_bindings('right-word', ('M-f',))
self.add_bindings('left-word', ('M-b',))
self.add_bindings('set-mark', ('C-@',))
self.add_bindings('switch-mark', ('C-x C-x',))
self.add_bindings('undo', ('C-/', 'C-x u',))
self.add_bindings('redo', ('M-/', 'M-_', 'C-x r',))
self.add_bindings('toggle-margins', ('M-m',))
self.add_bindings('transpose-words', ('M-t',))
self.add_bindings('delete-left-whitespace', ('C-c DELETE', 'C-c BACKSPACE',))
self.add_bindings('delete-right-whitespace', ('C-c d',))
self.add_bindings('insert-space', ('SPACE',))
self.add_bindings('insert-tab', ('TAB',))
self.add_action_and_bindings(ConsoleExec(), ('RETURN',))
self.add_action_and_bindings(ConsoleClear(), ('C-l',))
self.add_action_and_bindings(ConsoleCancel(), ('C-]',))
self.add_action_and_bindings(ConsoleHistoryPrev(), ('C-p',))
self.add_action_and_bindings(ConsoleHistoryNext(), ('C-n',))
self.add_action_and_bindings(ConsoleTab(), ('TAB',))
for c in string.letters + string.digits + string.punctuation:
self.add_binding('insert-string-%s' % c, c)
class ConsoleExec(method.Method):
def _execute(self, w, **vargs):
s = w.buffer.make_string()
w.mode.history[-1] = s
w.mode.history.append('')
w.buffer.set_data('')
w.mode.hindex = len(w.mode.history) - 1
a = w.application
if not a.has_buffer_name('*Console*'):
raise Exception, "No console found!"
b = a.bufferlist.get_buffer_by_name('*Console*')
if a.window().buffer is not b:
a.switch_buffer(b)
p = a.get_mini_buffer_prompt()
b.insert_string(b.get_buffer_end(), p + s + '\n', force=True)
if w.mode.saved_input:
s = w.mode.saved_input + '\n' + s
try:
code_obj = code.compile_command(s)
if code_obj is None:
w.mode.saved_input = s
a.set_mini_buffer_prompt('--> ')
output = None
else:
w.mode.saved_input = ''
a.set_mini_buffer_prompt('>>> ')
sys.stdout = code_out = StringIO.StringIO()
sys.stderr = code_err = StringIO.StringIO()
ok = True
try:
exec code_obj in w.mode.globals, w.mode.locals
except Exception, e:
ok = False
output = str(e) + '\n'
sys.stdout = sys.__stdout__
sys.stdout = sys.__stderr__
if ok:
output = code_out.getvalue()
code_out.close()
code_err.close()
except (SyntaxError, OverflowError, ValueError), e:
a.set_mini_buffer_prompt('>>> ')
t = sys.exc_traceback
output = str(e) + traceback.format_exc()
if output:
newlines = [' %s' % x for x in output.split('\n')]
assert newlines[-1] == ' '
newlines[-1] = ''
b.insert_lines(b.get_buffer_end(), newlines, force=True)
for w2 in b.windows:
w2.goto_end()
class ConsoleCancel(method.Method):
def execute(self, w, **vargs):
w.application.close_mini_buffer()
class ConsoleClear(method.Method):
def execute(self, w, **vargs):
a = w.application
if not a.has_buffer_name('*Console*'):
raise Exception, "No console found!"
b = a.bufferlist.get_buffer_by_name('*Console*')
b.clear()
class ConsoleHistoryPrev(method.Method):
def execute(self, w, **vargs):
if w.mode.hindex <= 0:
w.mode.hindex = 0
return
elif w.mode.hindex == len(w.mode.history) - 1:
w.mode.history[-1] = w.buffer.make_string()
w.mode.hindex -= 1
w.buffer.set_data(w.mode.history[w.mode.hindex])
class ConsoleHistoryNext(method.Method):
def execute(self, w, **vargs):
if w.mode.hindex == len(w.mode.history) - 1:
return
w.mode.hindex += 1
w.buffer.set_data(w.mode.history[w.mode.hindex])
class ConsoleTab(method.Method):
def execute(self, w, **vargs):
a = w.application
s = w.buffer.make_string()
x = w.logical_cursor().x
if not s or s[:x].isspace():
w.insert_string_at_cursor(' ' * w.mode.tabwidth)
return
l = lex.Lexer(w.mode, PythonGrammar)
tokens = list(l.lex([s]))
curr_t = None
curr_i = None
for i in range(0, len(tokens)):
t = tokens[i]
if t.x < x and t.end_x() >= x:
curr_i = i
curr_t = t
if curr_t is None:
return
first_t = curr_t
j = curr_i
names = [curr_t.string]
name_re = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
while j >= 1:
j -= 1
t = tokens[j]
if name_re.match(t.string):
names.insert(0, t.string)
elif t.string == '.':
pass
else:
break
#raise Exception, repr(names)
obj = None
g = globals()
i = 0
name = None
while i < len(names):
name = names[i]
if obj is None:
if name in w.mode.locals:
obj = w.mode.locals[name]
elif name in w.mode.globals:
obj = w.mode.globals[name]
else:
break
else:
if hasattr(obj, name):
obj = getattr(obj, name)
else:
break
i += 1
if i == len(names) - 1:
if obj is not None:
newnames = dir(obj)
else:
newnames = sets.Set()
newnames.update(__builtins__)
newnames.update(w.mode.locals)
newnames.update(w.mode.globals)
candidates = [x for x in newnames if x.startswith(name)]
if len(candidates) > 1:
s = completer.find_common_string(candidates)[len(name):]
w.insert_string_at_cursor(s)
elif len(candidates) == 1:
s = candidates[0][len(name):]
w.insert_string_at_cursor(s)
install = ConsoleMini.install