import color, mode, method, ispell
from lex import Token, Rule, PatternRule, RegionRule, Grammar

class WordRule(PatternRule):
    def __init__(self):
        PatternRule.__init__(self, r'word', pattern=r"[a-zA-Z][a-zA-Z-\']*[a-zA-Z](?=$|[^a-zA-Z0-9-_])")
    def _spelled_ok(self, word):
        if ispell.can_spell():
            speller = ispell.get_speller()
            return speller.check(word, caps=False, title=False)
        else:
            return True
    def lex(self, lexer, parent, m):
        if m:
            s = m.group(0)
            if self._spelled_ok(s):
                token = Token('word', self, lexer.y, lexer.x, s, None, parent, {})
            else:
                token = Token('misspelled', self, lexer.y, lexer.x, s, None, parent, {})            
            token.color = lexer.get_color(token)
            lexer.x += len(s)
            yield token
        raise StopIteration

class ContinuedRule(RegionRule):
    def __init__(self):
        RegionRule.__init__(self, r'cont', r'[a-zA-Z0-9_]+- *$', Grammar, r'^ *(?:[^ ]+|$)')

class TextGrammar(Grammar):
    rules = [
        ContinuedRule(),
        WordRule(),
        PatternRule(r'punct', r'[^a-zA-Z0-9_]'),
        PatternRule(r'stuff', r'[a-zA-Z0-9_]+'),
    ]

class Text(mode.Fundamental):
    modename = 'Text'
    extensions=['.txt']
    grammar  = TextGrammar
    colors   = {
        'misspelled': ('red', 'default'),
        'cont.start': ('default', 'default'),
        'cont.end':   ('default', 'default'),
        'word':       ('default', 'default'),
        'punct':      ('default', 'default'),
        'stuff':      ('default', 'default'),
    }
    def __init__(self, w):
        mode.Fundamental.__init__(self, w)
        self.add_action_and_bindings(LearnWord(), ('C-c l',))
        self.add_action_and_bindings(TextInsertSpace(), ('SPACE',))
        self.add_action_and_bindings(method.WrapParagraph(), ('M-q',))

class TextInsertSpace(method.Method):
    limit   = 80
    wrapper = method.WrapParagraph
    def execute(self, w, **vargs):
        w.insert_string_at_cursor(' ')
        cursor = w.logical_cursor()
        i = cursor.y
        if len(w.buffer.lines[i]) > self.limit:
            self.wrapper().execute(w)

class LearnWord(method.Method):
    def execute(self, w, **vargs):
        if not ispell.can_spell():
            w.application.set_error('Spelling support is unavailable')
            return

        cursor = w.logical_cursor()
        word = None
        for token in w.buffer.highlights[w.mode.name()].tokens[cursor.y]:
            if (token.x <= cursor.x and
                token.end_x() > cursor.x and
                token.name == 'misspelled'):
                word = token.string

        if word is None:
            w.application.set_error('No misspelled word was found')
            return

        speller = ispell.get_speller()
        speller.learn(word)
        w.application.set_error("Added %r to personal dictionary" % (word))
        # cheap way to relex just this word; there should really be a function
        w.insert_string_at_cursor(' ')
        w.left_delete()

install = Text.install