import code, os, re, string, StringIO, sys, traceback
import buffer, buffer.pipe, buffer.emul
import color, completer, lex, method, mode, window
from lex import Grammar, PatternRule, RegionRule
from point import Point
from method import Method
from subprocess import Popen, PIPE, STDOUT

class ShellMiniGrammar(Grammar):
    rules = [
        PatternRule('word', r'(?:(?:\\.|[^\n\\\'" ])+|"(?:\\.|[^\\\"])*"|\'(?:\\.|[^\\\'])*\')+'),
        PatternRule('spaces', r' +'),
        PatternRule('eol', r'\n'),
    ]

class ShellExec(Method):
    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)
        b.pipe_write(s + "\n")

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*')

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 xrange(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

        s1 = curr_t.string
        if(curr_i == 0) and '/' not in s1:
            completer = completer.get_completer['command']
        else:
            completer = completer.get_completer['path']

        s2, exists, complete = completer.tab_string(s1, w)
        w.delete(Point(curr_t.x, curr_t.y), Point(curr_t.end_x(), curr_t.y))
        w.insert_string_at_cursor(s2)
        candidates = completer.get_candidates(s1, w)
        mode.mini.use_completion_window(a, s2, 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 OpenShellRaw(method.shell.Interact):
    '''Evaluate sh expressions'''
    args = []
    reuse = True
    def _execute(self, w, **vargs):
        method.shell.Interact._execute(self, w, bname='*Shell*', cmd='bash')
class OpenShell(OpenShellRaw):
    '''Evaluate sh expressions'''
    args = []
    reuse = True
    def _execute(self, w, **vargs):
        OpenShellRaw._execute(self, w)
        f = lambda x: None
        w.application.open_mini_buffer('>>> ', f, self, None, 'shellmini')

class ShellMini(mode.Fundamental):
    name    = 'ShellMini'
    actions = [ShellExec, ShellClear, ShellCancel,
               ShellHistoryPrev, ShellHistoryNext,
               ShellTab,
               ShellPageUp, ShellPageDown, ShellGotoBeginning, ShellGotoEnd,
               OpenShell, OpenShellRaw]
    def __init__(self, w):
        mode.Fundamental.__init__(self, w)
        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