import mode, method, ispell
from mode import Fundamental
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 TextWrapParagraph(method.WrapParagraph):
    pass

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

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

class Text(Fundamental):
    name       = 'Text'
    extensions = ['.txt']
    grammar    = TextGrammar
    actions    = [LearnWord, TextInsertSpace, TextWrapParagraph]
    config     = {
        'text.margin': 78,
    }
    _bindings = {
        'learn-word':          ('C-c l',),
        'text-insert-space':   ('SPACE',),
        'text-wrap-paragraph': ('M-q',),
    }

install = Text.install