Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Visual Studio Code互換なsyntax highlighterの実装

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

Visual Studio Code互換なsyntax highlighterの実装

Avatar for omochimetaru

omochimetaru

March 01, 2019
Tweet

More Decks by omochimetaru

Other Decks in Programming

Transcript

  1. ۙ೥ͷτϨϯυ • TextMate • Sublime Text • Atom • Visual

    Studio Code ͜ΕΒશ͕ͯTextMateܗࣜΛ࠾༻ 5
  2. 8

  3. 12

  4. { "name": "JSON (Javascript Next)", "scopeName": "source.json", "patterns": [ ],

    "repository": { "array": { }, "comments": { }, "constant": { }, "number": { }, "object": { }, "string": { }, "objectkey": { }, "stringcontent": { }, "value": { } } } 16
  5. { "patterns": [ { "include": "#value" } ], "repository": {

    "array": { }, "comments": { }, "constant": { }, "number": { }, "object": { }, "string": { }, "objectkey": { }, "stringcontent": { }, "value": { "patterns": [ { "include": "#constant" }, { "include": "#number" }, { "include": "#string" }, { "include": "#array" }, { "include": "#object" }, { "include": "#comments" } ] } } } 18
  6. { "repository": { "constant": { "match": "\\b(?:true|false|null)\\b", "name": "constant.language.json" },

    "number": { "match": "(?x) # turn on extended mode\n" " -? # an optional minus\n" " (?:\n" " 0 # a zero\n" " | # ...or...\n" " [1-9] # a 1-9 character\n" " \\d* # followed by zero or more digits\n" " )\n" " (?:\n" " (?:\n" " \\. # a period\n" " \\d+ # followed by one or more digits\n" " )?\n" " (?:\n" " [eE] # an e character\n" " [+-]? # followed by an option +/-\n" " \\d+ # followed by one or more digits\n" " )? # make exponent optional\n" " )? # make decimal portion optional", "name": "constant.numeric.json" }, } } number.match͸දࣔͷ౎߹্෼ׂ͍ͯ͠·͕࣮͢ࡍʹ͸1ͭͷ௕͍จࣈྻͰ͋Δɻ 21
  7. JSONͷ਺஋ͷਖ਼نදݱ (?x) # turn on extended mode -? # an

    optional minus (?: 0 # a zero | # ...or... [1-9] # a 1-9 character \d* # followed by zero or more digits )\n (?: (?: \. # a period \d+ # followed by one or more digits )? (?: [eE] # an e character\n [+-]? # followed by an option +/- \d+ # followed by one or more digits )? # make exponent optional )? # make decimal portion optional ๯಄ͷ(?x)Ͱ֦ுه๏ϞʔυΛ։࢝ͯ͠վߦͱίϝϯτΛ༗ޮԽ 23
  8. { "repository": { "array": { "begin": "\\[", "end": "\\]", "name":

    "meta.structure.array.json", "patterns": [ { "include": "#value" }, { "match": ",", "name": "punctuation.separator.array.json" }, { "match": "[^\\s\\]]", "name": "invalid.illegal.expected-array-separator.json" } ] }, } } 26
  9. JSONจ๏ͰͷϚονϯάϦ ετ rootͷ࣌ • \b(?:true|false|null)\b: root[0]→value[0]→constant.match • (?x)...: root[0]→value[1]→number.match •

    \": root[0]→value[2]→string.begin • \[": root[0]→value[3]→array.begin • \{: root[0]→value[4]→object.begin • /\*\*(?!/): root[0]→value[5]→comments[0] • /\*: root[0]→value[5]→comments[1] • (//).*$\n?: root[0]→value[5]→comments[2] 29
  10. arrayͷ࣌ • \]: array.end • \b(?:true|false|null)\b: array[0]→value[0]→constant.match • (?x)...: array[0]→value[1]→number.match

    • \": array[0]→value[2]→string.begin • \[": array[0]→value[3]→array.begin • \{: array[0]→value[4]→object.begin • /\*\*(?!/): array[0]→value[5]→comments[0] • /\*: array[0]→value[5]→comments[1] • (//).*$\n?: array[0]→value[5]→comments[2] • ,: array[1].match • [^\s\]]: array[2].match 30
  11. HTMLͷߏจͷதͰPHPͷߏจΛݺͿ { "name": "PHP", "scopeName": "text.html.php", "repository": { "php-tag": {

    "patterns": [ { "begin": "<\\?(?i:php|=)?(?![^?]*\\?>)", "end": "(\\?)>", "name": "meta.embedded.block.php", "contentName": "source.php", "patterns": [ { "include": "source.php" } ] }, ] } } } 36
  12. جຊฤ ·ͱΊ • Grammar, Repository, Rule • Hub, Include, Match,

    BeginEnd • ݱࡏͷRule • ϚονϦετͷચ͍ग़͠ • ࠷΋ࠨͰϚονͨ͠ਖ਼نදݱ • ߦ୯Ґॲཧ ࢓૊Έͷࠎ૊Έ͸͜Ε͚ͩ 37
  13. { "captures": { "1": { "name": "support.function.construct.php" }, "2": {

    "name": "punctuation.definition.array.begin.php" }, "3": { "name": "punctuation.definition.array.end.php" } }, "match": "(array)(\\()(\\))", "name": "meta.array.empty.php" } 41
  14. { "array": { "begin": "\\[", "beginCaptures": { "0": { "name":

    "punctuation.definition.array.begin.json" } }, "end": "\\]", "endCaptures": { "0": { "name": "punctuation.definition.array.end.json" } }, "name": "meta.structure.array.json", "patterns": [ ... ] } } 42
  15. { "begin": "(?x)\\s*\n" "\t\t\t\t\t ((?:(?:final|abstract|public|private|protected|static)\\s+)*)\n" "\t\t\t\t (function)\n" "\t\t\t\t (?:\\s+|(\\s*&\\s*))\n" "\t\t\t\t

    (?:\n" "\t\t\t\t (__(?:call|construct|destruct|get|set|isset|unset|tostring|" "clone|set_state|sleep|wakeup|autoload|invoke|callStatic))\n" "\t\t\t\t |([a-zA-Z0-9_]+)\n" "\t\t\t\t )\n" "\t\t\t\t \\s*\n" "\t\t\t\t (\\()", "beginCaptures": { "1": { "patterns": [ { "match": "final|abstract|public|private|protected|static", "name": "storage.modifier.php" } ] }, "2": { "name": "storage.type.function.php" }, "3": { "name": "storage.modifier.reference.php" }, "4": { "name": "support.function.magic.php" }, "5": { "name": "entity.name.function.php" }, "6": { "name": "punctuation.definition.parameters.begin.php" } } } 45
  16. { "begin": "(?><<-(\\w+))", "beginCaptures": { "0": { "name": "punctuation.definition.string.begin.ruby" }

    }, "comment": "heredoc with indented terminator", "end": "\\s*\\1$", "endCaptures": { "0": { "name": "punctuation.definition.string.end.ruby" } }, "name": "string.unquoted.heredoc.ruby", "patterns": [ { "include": "#heredoc" }, { "include": "#interpolated_ruby" }, { "include": "#escaped_char" } ] } 48
  17. { "begin": "(^[ \\t]+)?(?=//)", "beginCaptures": { "1": { "name": "punctuation.whitespace.comment.leading.php"

    } }, "end": "(?!\\G)", "patterns": [ { "begin": "//", "beginCaptures": { "0": { "name": "punctuation.definition.comment.php" } }, "end": "\\n|(?=\\?>)", "name": "comment.line.double-slash.php" } ] } 51
  18. { "string-double-quoted": { "begin": "\"", "beginCaptures": { "0": { "name":

    "punctuation.definition.string.begin.php" } }, "contentName": "meta.string-contents.quoted.double.php", "end": "\"", "endCaptures": { "0": { "name": "punctuation.definition.string.end.php" } }, "name": "string.quoted.double.php", "patterns": [ { "include": "#interpolation" } ] } 54
  19. { "begin": "\\?", "beginCaptures": { "0": { "name": "keyword.operator.ternary.c" }

    }, "end": ":", "applyEndPatternLast": true, "endCaptures": { "0": { "name": "keyword.operator.ternary.c" } }, "patterns": [ { "include": "#access" }, { "include": "#libc" }, { "include": "#c_function_call" }, { "include": "$base" } ] } 57
  20. { "begin": "\\b(require|require_relative|gem)\\b", "captures": { "1": { "name": "keyword.other.special-method.ruby" }

    }, "end": "$|(?=#|\\})", "name": "meta.require.ruby", "patterns": [ { "include": "$self" } ] } 60
  21. { "parens": { "begin": "\\(", "beginCaptures": { "0": { "name":

    "punctuation.section.parens.begin.c" } }, "end": "\\)", "endCaptures": { "0": { "name": "punctuation.section.parens.end.c" } }, "name": "meta.parens.c", "patterns": [ { "include": "$base" } ] } } 63
  22. { "begin": "@\"", "beginCaptures": { "0": { "name": "punctuation.definition.string.begin.objc" }

    }, "end": "\"", "endCaptures": { "0": { "name": "punctuation.definition.string.end.objc" } }, "name": "string.quoted.double.objc", "patterns": [ { "include": "source.c#string_escaped_char" }, { "match": "(?x)%\n" "\t\t\t\t\t\t(\\d+\\$)? # field (argument #)\n" "\t\t\t\t\t\t[#0\\- +']* # flags\n" "\t\t\t\t\t\t((-?\\d+)|\\*(-?\\d+\\$)?)? # minimum field width\n" "\t\t\t\t\t\t(\\.((-?\\d+)|\\*(-?\\d+\\$)?)?)? # precision\n" "\t\t\t\t\t\t[@] # conversion type\n" "\t\t\t\t\t", "name": "constant.other.placeholder.objc" }, { "include": "source.c#string_placeholder" } ] } 66
  23. { "regular_expressions": { "comment": "Changed disabled to 1 to turn

    off syntax highlighting in “r” strings.", "disabled": 0, "patterns": [ { "include": "source.regexp.python" } ] } } 69
  24. { "scopeName": "todo-comment.injection", "injectionSelector": "L:comment.line.double-slash", "patterns": [ { "include": "#todo-keyword"

    } ], "repository": { "todo-keyword": { "match": "TODO", "name": "keyword.todo" } } } 74
  25. { "injectionSelector": "text, string, comment", "name": "Hyperlink", "patterns": [ {

    "match": "(?x)\n" "\t\t\t\t( (https?|s?ftp|ftps|file|smb|afp|nfs|(x-)?man(-page)?|gopher|txmt|issue)://|mailto:)\n" "\t\t\t\t[-:@a-zA-Z0-9_.,~%+/?=&#;]+(?<![-.,?:#;])\n" "\t\t\t", "name": "markup.underline.link.$2.hyperlink" }, { "match": "(?i)\\bRFC(?: |(?<= RFC))(\\d+)\\b", "name": "markup.underline.link.rfc.$1.hyperlink" } ], "scopeName": "text.hyperlink" } 75
  26. { "injections": { "text.html.php - (meta.embedded | meta.tag), " "L:text.html.php

    meta.tag, " "L:source.js.embedded.html": { "patterns": [ { }, { }, { } ] } }, "name": "PHP", "patterns": [ { "include": "text.html.basic" } ], "repository": { } } 77