import color, mode
from lex import Grammar, PatternRule, RegionRule, PatternMatchRule
from mode.scheme import SchemeGrammar
from mode.python import StringGrammar1, StringGrammar2
import regex
import tab

class MarkupGrammar(Grammar):
    rules = [PatternRule(r'data', r'[^}]+')]

class CommentGrammar(Grammar):
    rules = [PatternRule(r'data', r'(?:[^%]|%[^}])+')]

class LilyGrammar(Grammar):
    rules = [
        PatternRule(r'comment', r'%.*$'),
        RegionRule(r'comment', r'%\{', CommentGrammar, r'%\}'),
        RegionRule(r'string', r'#?"', StringGrammar2, r'"'),
        PatternRule(r'boolean', r'#?#[tf]'),
        PatternMatchRule(r'x', r'(\\new)( +)([a-zA-Z_]+)', r'lily.directive',
                         r'spaces', r'lily.class'),
        PatternMatchRule(r'x', r'(\\set|\\override)( +)([a-zA-Z_]+)',
                         r'lily.directive', r'spaces', r'lily.var'),
        PatternRule(r'lily.tie', r'~'),
        PatternRule(r'lily.augmentation', r'\.+'),
        PatternRule(r'lily.directive', r'\\[a-zA-Z_][a-zA-Z_0-9]*'),
        PatternRule(r'delimiter', r'(?:[={}]|<<|>>)'),
        RegionRule(r'lily.text', r'^"', StringGrammar2, r'"'),
        RegionRule(r'lily.markup', r'(?<=\\markup) *{', MarkupGrammar, '}'),
        PatternRule(r'lily.huh', r'\\!'),
        PatternRule(r'spaces', ' +'),
        PatternRule(r'eol', '\n'),
        PatternRule(r'lily.chord', r'[<>]'),
        PatternRule(r'lily.beam', r'[\[\]]'),
        PatternRule(r'lily.slur', r'[()]'),
        PatternRule(r'lily.pslur', r'\\[()]'),
        PatternRule(r'lily.articulation', r'[-_+][-.>^+_]'),
        PatternRule(r'lily.fingering', r'[-_+][0-9]+'),
        PatternRule(r'lily.time', r'[0-9]+/[0-9]+'),
        PatternRule(r'lily.note', r"[a-g][sf]?[,']*[0-9]*(?![a-z-])"),
        PatternRule(r'lily.rest', r"r[0-9]*(?![a-z-])"),
        PatternRule(r'lily.srest', r"s[0-9]*(?![a-z-])"),
        PatternRule(r'lily.measure', r'(?:[0-9]+\.)?[0-9]+\\(?:mm|cm|in)'),
        RegionRule(r'lily.scheme', r'#\(', SchemeGrammar, '\)'),
        PatternRule(r'lily.bareword', r'[a-zA-Z][a-zA-Z_0-9-]*[a-zA-Z0-9]'),
    ]

class LilyTabber(tab.StackTabber):
    wsre = regex.whitespace
    wst  = ('spaces', 'null', 'eol',)
    sre  = regex.space
    st   = ('spaces', 'null',)

class Lily(mode.Fundamental):
    name       = 'lily'
    extensions = ['.ly']
    tabwidth   = 2
    tabbercls  = LilyTabber
    grammar    = LilyGrammar
    commentc   = '%'
    colors     = {
        'lily.boolean':      ('magenta', 'default', 'bold'),
        'lily.class':        ('magenta', 'default', 'bold'),
        'lily.var':          ('cyan', 'default', 'bold'),
        'lily.directive':    ('blue', 'default', 'bold'),
        'lily.markup.start': ('cyan', 'default'),
        'lily.markup.data':  ('cyan', 'default'),
        'lily.markup.end':   ('cyan', 'default'),
        'lily.time':         ('yellow', 'default'),
        'lily.note':         ('yellow', 'default', 'bold'),
        'lily.rest':         ('yellow', 'default'),
        'lily.srest':        ('yellow', 'default'),
        'lily.scheme.start': ('magenta', 'default'),
        'lily.scheme.end':   ('magenta', 'default'),
        'lily.measure':      ('green', 'default'),
        'lily.beam':         ('red', 'default'),
        'lily.slur':         ('red', 'default'),
        'lily.plur':         ('red', 'default'),
        'lily.tie':          ('red', 'default'),
        'lily.huh':          ('red', 'default'),
    }
    opentokens  = ('delimiter',)
    opentags    = {'<<': '>>', '{': '}'}
    closetokens = ('delimiter',)
    closetags   = {'>>': '<<', '}': '{'}
    _bindings = {
        'close-brace':   ('}',),
    }

install = Lily.install