jakebathman
8/11/2017 - 8:47 PM

Update SQL syntax parsing for Sublime Text 3

Update SQL syntax parsing for Sublime Text 3

# This file is used by Sublime Text 3 to parse code using the SQL syntax. 
# 
# Below is unchanged from the default, except for a few modifications:
#   - Adjusted regex for alias (... AS Foo) to match the alias name as keyword.other.alias-name.sql
#   - Fixed regex for table/column name when the name is wraped in backticks or an asterisk (e.g. Foo.`Bar` or Foo.*)
#

%YAML 1.2
---
name: SQL
file_extensions:
  - sql
  - ddl
  - dml
scope: source.sql
contexts:
  main:
    - include: comments
    - match: '(?i:\s*\b(create(?:\s+or\s+replace)?)\s+(aggregate|conversion|database|domain|function|group|(?:unique\s+)?index|language|operator class|operator|procedure|rule|schema|sequence|table|tablespace|trigger|type|user|view)\s+)(?:(\w+)|''(\w+)''|"(\w+)"|`(\w+)`)'
      scope: meta.create.sql
      captures:
        1: keyword.other.create.sql
        2: keyword.other.sql
        3: entity.name.function.sql
        4: entity.name.function.sql
        5: entity.name.function.sql
        6: entity.name.function.sql
    - match: (?i:\s*\b(drop)\s+(aggregate|conversion|database|domain|function|group|index|language|operator class|operator|procedure|rule|schema|sequence|table|tablespace|trigger|type|user|view))
      scope: meta.drop.sql
      captures:
        1: keyword.other.create.sql
        2: keyword.other.sql
    - match: (?i:\s*(drop)\s+(table)\s+(\w+)(\s+cascade)?\b)
      scope: meta.drop.sql
      captures:
        1: keyword.other.create.sql
        2: keyword.other.table.sql
        3: entity.name.function.sql
        4: keyword.other.cascade.sql
    - match: (?i:\s*\b(alter)\s+(aggregate|conversion|database|domain|function|group|index|language|operator class|operator|procedure|rule|schema|sequence|table|tablespace|trigger|type|user|view)\s+)
      scope: meta.alter.sql
      captures:
        1: keyword.other.create.sql
        2: keyword.other.table.sql
    - match: |-
        (?xi)

                # normal stuff, capture 1
                 \b(bigint|bigserial|bit|boolean|box|bytea|cidr|circle|date|datetime|double\sprecision|inet|int|integer|line|lseg|macaddr|money|ntext|oid|path|point|polygon|real|serial|smallint|sysdate|sysname|text)\b

                # numeric suffix, capture 2 + 3i
                |\b(bit\svarying|character\s(?:varying)?|tinyint|var\schar|float|interval)\((\d+)\)

                # optional numeric suffix, capture 4 + 5i
                |\b(char|number|nvarchar|varbinary|varchar\d?)\b(?:\((\d+)\))?

                # special case, capture 6 + 7i + 8i
                |\b(numeric|decimal)\b(?:\((\d+),(\d+)\))?

                # special case, captures 9, 10i, 11
                |\b(times?)\b(?:\((\d+)\))?(\swith(?:out)?\stime\szone\b)?

                # special case, captures 12, 13, 14i, 15
                |\b(timestamp)(?:(s|tz))?\b(?:\((\d+)\))?(\s(with|without)\stime\szone\b)?


      captures:
        1: storage.type.sql
        2: storage.type.sql
        3: constant.numeric.sql
        4: storage.type.sql
        5: constant.numeric.sql
        6: storage.type.sql
        7: constant.numeric.sql
        8: constant.numeric.sql
        9: storage.type.sql
        10: constant.numeric.sql
        11: storage.type.sql
        12: storage.type.sql
        13: storage.type.sql
        14: constant.numeric.sql
        15: storage.type.sql
    - match: (?i:\b((?:primary|foreign)\s+key|references|on\sdelete(\s+cascade)?|on\supdate(\s+cascade)?|check|constraint|default)\b)
      scope: storage.modifier.sql
    - match: \b\d+\b
      scope: constant.numeric.sql
    - match: (?i:\b(true|false)\b)
      scope: constant.boolean.sql
    - match: (?i:\b(select(\s+(distinct|top))?|insert(\s+(ignore\s+)?into)?|update|delete|from|set|where|group\sby|or|like|between|and|with|case|when|then|else|end|union(\s+all)?|having|order\sby|limit|(inner|cross)\s+join|join|straight_join|(left|right)(\s+outer)?\s+join|natural(\s+(left|right)(\s+outer)?)?\s+join)\b)
      scope: keyword.other.DML.sql
    - match: (?i:\b(on|((is\s+)?not\s+)?null)\b)
      scope: keyword.other.DDL.create.II.sql
    - match: (?i:\bvalues\b)
      scope: keyword.other.DML.II.sql
    - match: (?i:\b(begin(\s+work)?|start\s+transaction|commit(\s+work)?|rollback(\s+work)?)\b)
      scope: keyword.other.LUW.sql
    - match: (?i:\b(grant(\swith\sgrant\soption)?|revoke)\b)
      scope: keyword.other.authorization.sql
    - match: (?i:\b(?:in|not in|is)\b)
      scope: keyword.other.data-integrity.sql
    - match: (?i:\s*\b(comment\s+on\s+(table|column|aggregate|constraint|database|domain|function|index|operator|rule|schema|sequence|trigger|type|view))\s+.*?\s+(is)\s+)
      scope: keyword.other.object-comments.sql
    - match: (?i)\bAS\s+([A-Za-z0-9\_\-]+)\b
      scope: keyword.other.alias.sql
      captures:
        1: keyword.other.alias-name.sql
    - match: (?i)\b(DESC|ASC)\b
      scope: keyword.other.order.sql
    - match: \*
      scope: keyword.operator.star.sql
    - match: "[!<>]?=|<>|<|>"
      scope: keyword.operator.comparison.sql
    - match: '-|\+|/'
      scope: keyword.operator.math.sql
    - match: \|\|
      scope: keyword.operator.concatenator.sql
    - match: (?i)\b(CURRENT_(DATE|TIME(STAMP)?|USER)|(SESSION|SYSTEM)_USER)\b
      comment: List of SQL99 built-in functions from http://www.oreilly.com/catalog/sqlnut/chapter/ch04.html
      scope: support.function.scalar.sql
    - match: (?i)\b(AVG|COUNT|MIN|MAX|SUM)(?=\s*\()
      comment: List of SQL99 built-in functions from http://www.oreilly.com/catalog/sqlnut/chapter/ch04.html
      scope: support.function.aggregate.sql
    - match: (?i)\b(CONCATENATE|CONVERT|LOWER|SUBSTRING|TRANSLATE|TRIM|UPPER)\b
      scope: support.function.string.sql
    - match: \b(\w+?)\.((?:[\w*]+)|(?:`(?:[\w*]+)`))(\b|$|\s)
      captures:
        1: constant.other.database-name.sql
        2: constant.other.table-name.sql
    - include: strings
    - include: regexps
    - match: (\()(\))
      comment: Allow for special ↩ behavior
      scope: meta.block.sql
      captures:
        1: punctuation.section.scope.begin.sql
        2: punctuation.section.scope.end.sql
  comments:
    - match: "--"
      scope: punctuation.definition.comment.sql
      push:
        - meta_scope: comment.line.double-dash.sql
        - match: \n
          pop: true
    - match: "#"
      scope: punctuation.definition.comment.sql
      push:
        - meta_scope: comment.line.number-sign.sql
        - match: \n
          pop: true
    - match: /\*
      scope: punctuation.definition.comment.sql
      push:
        - meta_scope: comment.block.c
        - match: \*/
          pop: true
  regexps:
    - match: /(?=\S.*/)
      captures:
        0: punctuation.definition.string.begin.sql
      push:
        - meta_scope: string.regexp.sql
        - match: /
          captures:
            0: punctuation.definition.string.end.sql
          pop: true
        - include: string_interpolation
        - match: \\/
          scope: constant.character.escape.slash.sql
    - match: '%r\{'
      comment: We should probably handle nested bracket pairs!?! -- Allan
      captures:
        0: punctuation.definition.string.begin.sql
      push:
        - meta_scope: string.regexp.modr.sql
        - match: '\}'
          captures:
            0: punctuation.definition.string.end.sql
          pop: true
        - include: string_interpolation
  string_escape:
    - match: \\.
      scope: constant.character.escape.sql
  string_interpolation:
    - match: '(#\{)([^\}]*)(\})'
      scope: string.interpolated.sql
      captures:
        1: punctuation.definition.string.begin.sql
        3: punctuation.definition.string.end.sql
  strings:
    - match: "'"
      captures:
        0: punctuation.definition.string.begin.sql
      push:
        - meta_scope: string.quoted.single.sql
        - match: "''"
          scope: constant.character.escape.sql
        - match: "'"
          captures:
            0: punctuation.definition.string.end.sql
          pop: true
        - include: string_escape
    - match: "`"
      captures:
        0: punctuation.definition.string.begin.sql
      push:
        - meta_scope: string.quoted.other.backtick.sql
        - match: "`"
          captures:
            0: punctuation.definition.string.end.sql
          pop: true
        - include: string_escape
    - match: '"'
      captures:
        0: punctuation.definition.string.begin.sql
      push:
        - meta_scope: string.quoted.double.sql
        - match: '""'
          scope: constant.character.escape.sql
        - match: '"'
          captures:
            0: punctuation.definition.string.end.sql
          pop: true
        - include: string_interpolation
    - match: '%\{'
      captures:
        0: punctuation.definition.string.begin.sql
      push:
        - meta_scope: string.other.quoted.brackets.sql
        - match: '\}'
          captures:
            0: punctuation.definition.string.end.sql
          pop: true
        - include: string_interpolation