pmacs3/mode/consolemini.py

242 lines
8.0 KiB
Python

import code, re, string, StringIO, sys, traceback
import color, completer, lex, method, mode
from lex import Grammar, PatternRule
from mode.python import PythonGrammar
from point import Point
PAD = ' '
class ConsoleExec(method.Method):
def _execute(self, w, **vargs):
if w.application.completion_window_is_open():
w.application.close_completion_buffer()
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()
limit = min([w.width for w in b.windows]) - len(PAD)
if output:
newlines = []
for line in output.split('\n'):
i = 0
while i + limit < len(line):
j = limit
while j > 0 and line[i + j] != ' ':
j -= 1
if j == 0:
newlines.append(PAD + line[i:i + limit])
i += j
else:
newlines.append(PAD + line[i:i + j])
i += j + 1
newlines.append(PAD + line[i:])
assert newlines[-1] == PAD
newlines[-1] = ''
b.insert_lines(b.get_buffer_end(), newlines, force=True)
for w2 in b.windows:
w2.goto_end(force=True)
class ConsoleCancel(method.Method):
def execute(self, w, **vargs):
w.application.close_mini_buffer()
if w.application.completion_window_is_open():
w.application.close_completion_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
name_re = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
if name_re.match(curr_t.string):
names = [curr_t.string]
elif curr_t.string == '.':
names = ['']
else:
names = []
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
if not names:
return
obj = None
g = globals()
i = 0
name = names[0]
if len(names) > 1:
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 = set()
newnames.update(__builtins__)
newnames.update(w.mode.locals)
newnames.update(w.mode.globals)
candidates = [x for x in newnames if x.startswith(name)]
s = completer.find_common_string(candidates)[len(name):]
w.insert_string_at_cursor(s)
mode.mini.use_completion_window(a, name, candidates)
class ConsoleBaseMethod(method.Method):
subcls = method.Method
subbuf = '*Console*'
def __init__(self):
method.Method.__init__(self)
self.submethod = self.subcls()
def _execute(self, w, **vargs):
a = w.application
if not a.has_buffer_name(self.subbuf):
raise Exception, "No console found!"
w2 = a.bufferlist.get_buffer_by_name(self.subbuf).windows[0]
self.submethod.execute(w2, **vargs)
class ConsolePageUp(ConsoleBaseMethod):
subcls = method.move.PageUp
class ConsolePageDown(ConsoleBaseMethod):
subcls = method.move.PageDown
class ConsoleGotoBeginning(ConsoleBaseMethod):
subcls = method.move.GotoBeginning
class ConsoleGotoEnd(ConsoleBaseMethod):
subcls = method.move.GotoEnd
class ConsoleMini(mode.Fundamental):
modename = 'ConsoleMini'
grammar = PythonGrammar
actions = [ConsoleExec, ConsoleClear, ConsoleCancel, ConsoleHistoryPrev,
ConsoleHistoryNext, ConsoleTab,
ConsolePageUp, ConsolePageDown, ConsoleGotoBeginning, ConsoleGotoEnd]
_bindings = {
'console-exec': ('RETURN',),
'console-clear': ('C-l',),
'console-cancel': ('C-]', 'C-g'),
'console-history-prev': ('C-p', 'UP'),
'console-history-next': ('C-n', 'DOWN'),
'console-tab': ('TAB',),
'console-page-up': ('M-v',),
'console-page-down': ('C-v',),
'console-goto-beginning': ('M-<',),
'console-goto-end': ('M->',),
}
def __init__(self, w):
mode.Fundamental.__init__(self, w)
self.globals = dict(w.application.globals())
self.locals = dict(w.application.locals())
self.saved_input = ""
self.history = ['']
self.hindex = 0
install = ConsoleMini.install