import code, os, re, string, StringIO, sys, traceback import buffer, color, completer, lex, method, mode, window from lex import Grammar, PatternRule, RegionRule from mode.sh import StringGrammar from point import Point from method import Method from subprocess import Popen, PIPE, STDOUT LIMIT = 79 class ShellExec(Method): sequences = { '\x1b[01;30m': "[green:default]", '\x1b[01;31m': "[green:default]", '\x1b[01;32m': "[green:default]", '\x1b[01;34m': "[blue:default]", '\x1b[01;36m': "[cyan:default]", '\x1b[0m': "[default:default]", } sequences = {} def _execute(self, w, **vargs): a = w.application if a.completion_window_is_open(): a.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 if not a.has_buffer_name('*Shell*'): raise Exception, "No shell found!" b = a.bufferlist.get_buffer_by_name('*Shell*') 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) a.set_mini_buffer_prompt('>>> ') ok = True args = ['sh', '-c', s] env = {'COLUMNS': '80', 'LINES': '24', 'TERM': os.environ['TERM']} p = Popen(args, bufsize=1024, stderr=STDOUT, stdout=PIPE, close_fds=True, env=env) output = p.stdout.read() output2 = [] i = 0 escaped = [] for c in output: if escaped: escaped.append(c) if c == 'm': #seq = ''.join(escaped) #if seq in self.sequences: # output2.append(self.sequences[seq]) escaped = [] elif c == '\x1b': escaped.append(c) elif c == '\n': output2.append(c) i = 0 elif c == '\t': j = i % 8 output2.append(' ' * (8 - j)) i += 8 - j elif c == '\a': pass elif c == '\b': if i > 0: output2.pop(-1) i -= 1 else: output2.append(c) i += 1 output = ''.join(output2) limit = 1000 for w2 in b.windows: limit = min(w.width, limit) if limit == 1000: limit = LIMIT if output: newlines = [] for line in output.split('\n'): line = line.replace('\x1b[01;32m', "[green:default]") line = line.replace('\x1b[01;34m', "[blue:default]") line = line.replace('\x1b[01;36m', "[cyan:default]") line = line.replace('\x1b[0m', "[default:default]") i = 0 while i + limit < len(line): j = limit while j > 0 and line[i + j] != ' ': j -= 1 if j == 0: newlines.append(line[i:i + limit]) i += limit else: newlines.append(line[i:i + j]) i += j + 1 newlines.append(line[i:]) newlines[-1] = '' b.insert_lines(b.get_buffer_end(), newlines, force=True) for w2 in b.windows: w2.goto_end(force=True) class ShellCancel(Method): def execute(self, w, **vargs): w.application.close_mini_buffer() if w.application.completion_window_is_open(): w.application.close_completion_buffer() class ShellClear(Method): def execute(self, w, **vargs): a = w.application if not a.has_buffer_name('*Shell*'): raise Exception, "No shell found!" b = a.bufferlist.get_buffer_by_name('*Shell*') b.clear() class ShellHistoryPrev(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 ShellHistoryNext(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 ShellTab(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, ShellMiniGrammar) 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 if(i == 0) and '/' not in curr_t.string: # we are completing a command candidates = [] else: # we are completing a path cwd = os.getcwd() if not cwd.endswith('/'): cwd += '/' path = cwd + curr_t.string (d, name) = os.path.split(path) names = [] for x in os.listdir(d): if os.path.isdir(os.path.join(d, x)): names.append(x + '/') else: names.append(x) candidates = [x for x in names 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 ShellBaseMethod(Method): subcls = Method subbuf = '*Shell*' 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 shell found!" w2 = a.bufferlist.get_buffer_by_name(self.subbuf).windows[0] self.submethod.execute(w2, **vargs) class ShellPageUp(ShellBaseMethod): subcls = method.move.PageUp class ShellPageDown(ShellBaseMethod): subcls = method.move.PageDown class ShellGotoBeginning(ShellBaseMethod): subcls = method.move.GotoBeginning class ShellGotoEnd(ShellBaseMethod): subcls = method.move.GotoEnd class OpenShell(Method): '''Evaluate sh expressions''' def execute(self, w, **vargs): a = w.application if not a.has_buffer_name('*Shell*'): b = buffer.ShellBuffer() a.add_buffer(b) window.Window(b, a) b = a.bufferlist.get_buffer_by_name('*Shell*') if a.window().buffer is not b: a.switch_buffer(b) f = lambda x: None w.application.open_mini_buffer('>>> ', f, self, None, 'shellmini') class ShellMiniGrammar(Grammar): rules = [ PatternRule(r'word', r"'.*'"), PatternRule(r'word', r'"(:\\.|[^"\\])*"'), PatternRule(r'word', r'(?:[^ \n"\'\\]|\\.)+'), ] class ShellMini(mode.Fundamental): modename = 'ShellMini' grammar = ShellMiniGrammar actions = [ShellExec, ShellClear, ShellCancel, ShellHistoryPrev, ShellHistoryNext, ShellTab, ShellPageUp, ShellPageDown, ShellGotoBeginning, ShellGotoEnd, OpenShell] 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 self.add_bindings('shell-exec', ('RETURN',)) self.add_bindings('shell-clear', ('C-l',)) self.add_bindings('shell-cancel', ('C-]', 'C-g')) self.add_bindings('shell-history-prev', ('C-p', 'UP')) self.add_bindings('shell-history-next', ('C-n', 'DOWN')) self.add_bindings('shell-tab', ('TAB',)) self.add_bindings('shell-page-up', ('M-v',)) self.add_bindings('shell-page-down', ('C-v',)) self.add_bindings('shell-goto-beginning', ('M-<',)) self.add_bindings('shell-goto-end', ('M->',)) install = ShellMini.install