pmacs3/mode/consolemini.py

247 lines
8.1 KiB
Python

import code
import re
import StringIO
import sys
import traceback
import completer
from method import Method
import method.move
import mode.mini
from lex import Lexer, Grammar, PatternRule
from mode.python import PythonGrammar
PAD = ' '
class ConsoleExec(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:
except Exception, 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 += limit
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):
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):
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()
w.buffer.parentw.buffer.clear()
class ConsoleHistoryPrev(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):
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):
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 = 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 ConsoleBase(Method):
subcls = Method
subbuf = '*Console*'
def __init__(self):
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(ConsoleBase): subcls = method.move.PageUp
class ConsolePageDown(ConsoleBase): subcls = method.move.PageDown
class ConsoleGotoBeginning(ConsoleBase): subcls = method.move.GotoBeginning
class ConsoleGotoEnd(ConsoleBase): subcls = method.move.GotoEnd
class ConsoleMini(mode.Fundamental):
name = '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