%YAML 1.2
---
# See http://www.sublimetext.com/docs/3/syntax.html
name: Grammalecte rules
file_extensions:
  - grx
scope: source.grammalecte
contexts:
  main:
    # Strings begin and end with quotes, and use backslashes as an escape
    # character
    - match: '"[^"]*"'
      scope: string.quoted.double
      #push: double_quoted_string

    # Comments begin with a '#' and finish at the end of the line
    - match: '^#.*'
      scope: comment
    - match: '^    ##.*'
      scope: comment.within

    # Error message
    - match: '(?<= )&& '
      scope: string.message
      push:
        - meta_scope: string.message
        - match: '\\-?[0-9]+'
          scope: string.message.esc
        - match: '\| ?https?://[\w./%?&=#+-]+'
          scope: string.message.url
        - match: $
          pop: true

    # Numbers
    - match: '\b(-)?[0-9.]+\b'
      scope: constant.numeric

    # Bookmarks
    - match: '^!!.*|^\[\+\+\].*'
      scope: bookmark

    # Graph
    - match: '^@@@@GRAPH: *(\w+) *\| *(\w+) .*$'
      scope: graphline
      captures:
        1: string.graphname
        2: string.graphcode

    - match: '^@@@@(?:END_GRAPH .*$| *)'
      scope: graphline

    # Keywords are if, else.
    # Note that blackslashes don't need to be escaped within single quoted
    # strings in YAML. When using single quoted strings, only single quotes
    # need to be escaped: this is done by using two single quotes next to each
    # other.
    - match: '\b(?:if|else|and|or|not|in)\b'
      scope: keyword.python

    - match: '\b(?:True|False|None)\b'
      scope: constant.language

    - match: '\b(?:spell|morph|morphVC|stem|tag|value|space_after|textarea0?\w*|before0?\w*|after0?\w*|word|option|define|define_from|select|exclude|analyse\w*|tag_\w+|apposition|is[A-Z]\w+|rewriteSubject|checkD\w+|getD\w+|has[A-Z]\w+|sugg[A-Z]\w+|switch[A-Z]\w+|ceOrCet|formatN\w+|mbUnit)\b'
      scope: entity.name.function

    - match: '\b(?:replace|endswith|startswith|search|upper|lower|capitalize|strip|rstrip|is(?:alpha|upper|lower|digit|title))\b'
      scope: support.function

    - match: '\becho\b'
      scope: support.function.debug

    - match: '\bre\b'
      scope: support.class

    # Regex rule option
    - match: '^__[\[<]([isu])[\]>](/\w+|)(\(\w+\)|)(![0-9]|)__|</?js>'
      scope: rule.options
      captures:
        1: rule.casing
        2: rule.optionname
        3: rule.rulename_regex
        4: rule.priority

    # Graph rules option
    - match: '^__(\w+)(![0-9]|)__'
      scope: rule.options
      captures:
        1: rule.rulename_graph
        2: rule.priority

    - match: '/(\w+)/'
      scope: rule.actionoption
      captures:
        1: rule.optionname

    - match: '!!(.+)¡¡'
      scope: rule.antipattern
      captures:
        1: rule.antipattern.token

    # Definitions and options
    - match: '^OPT(?:GROUP|LANG|PRIORITY)/|^OPT(?:SOFTWARE|COLORTHEME):|^COLOR/'
      scope: options.command

    - match: '^OPT(?:LABEL|COLOR|)/'
      scope: options.parameter

    - match: '^DEF: '
      scope: definition

    # Tests & TODO
    - match: '^TEST: (?:__[a-zA-Z0-9]+__ |)'
      scope: test.header

    - match: '{{.+?}}'
      scope: test.error

    - match: '^TODO: '
      scope: todo

    # JS groups positioning codes
    - match: ' @@[0-9w,$*>:]+'
      scope: comment.line.percentage

    # rule delimiters
    - match: '<<-|>>>'
      scope: entity.action
    - match: '__also__'
      scope: entity.cond.green
    - match: '__else__'
      scope: entity.cond.red
    - match: '-(-?\d*\.?(?::\.?-?\d+|))(?::|)>>'
      scope: entity.error
      captures:
        1: entity.error.group
    - match: '~(-?\d*(?::-?\d+|))>>'
      scope: entity.tproc
      captures:
        1: entity.tproc.group
    - match: '=>>'
      scope: entity.disambiguator
    - match: '/(-?\d*(?::-?\d+|))>>'
      scope: entity.tag
      captures:
        1: entity.tag.group
    - match: '!(-?\d*(?::-?\d+|))>>'
      scope: entity.tag
      captures:
        1: entity.tag.group

    # Tokens
    - match: '(>)[\w-]+'
      scope: string.lemma
      captures:
        1: entity.valid

    - match: '(~)(?!(?:\d+(?::\d+|)|)>>)[^\s¬]*'
      scope: string.regex
      captures:
        1: entity.valid

    - match: '(@)([^@\s¬]*)'
      scope: string.morph
      captures:
        1: entity.valid
        2: string.morph.regex

    - match: '(\$)([^@\s¬]*)'
      scope: string.morph
      captures:
        1: entity.valid
        2: string.morph.regex

    - match: '(/)[\w-]+'
      scope: string.tag
      captures:
        1: entity.valid

    - match: '(?<=[^\w])([*][a-zA-Z0-9_]+)'
      scope: string.morph
      captures:
        1: entity.valid
        2: string.meta

    - match: '(¬)(\S+)'
      scope: string.morph
      captures:
        1: entity.invalid
        2: string.morph.negregex

    - match: '<(?:start|end)>'
      scope: string.token

    - match: '<>'
      scope: string.jumptoken

    # Escaped chars
    - match: '\\(?:-?\d+|w|d|b|n|s|t)'
      scope: constant.character.escape

    # URL
    - match: '\| ?https?://[\w./%?&=#+-]+'
      scope: string.other

    # special chars
    - match: '[@=*^?¿!:+<>~]'
      scope: keyword.other

    - match: '\(\?(?:[:=!]|<!)|[(|)]'
      scope: entity.parenthesis

    - match: '\[|[]{}]'
      scope: entity.brackets
