diff --git a/HTML/syntax_test_html.html b/HTML/syntax_test_html.html index 9c1539aa100..2d2aedcd40e 100644 --- a/HTML/syntax_test_html.html +++ b/HTML/syntax_test_html.html @@ -127,23 +127,23 @@ diff --git a/JSON/.python-version b/JSON/.python-version new file mode 100644 index 00000000000..cc1923a40b1 --- /dev/null +++ b/JSON/.python-version @@ -0,0 +1 @@ +3.8 diff --git a/JSON/Comments - JSON5.tmPreferences b/JSON/Comments - JSON5.tmPreferences new file mode 100644 index 00000000000..75aac0ef338 --- /dev/null +++ b/JSON/Comments - JSON5.tmPreferences @@ -0,0 +1,25 @@ + + + + scope + source.json.json5 + settings + + shellVariables + + + nameTM_COMMENT_START + value// + + + nameTM_COMMENT_START_2 + value/* + + + nameTM_COMMENT_END_2 + value*/ + + + + + diff --git a/JSON/Comments - JSONC.tmPreferences b/JSON/Comments - JSONC.tmPreferences new file mode 100644 index 00000000000..1ee8dd7e2af --- /dev/null +++ b/JSON/Comments - JSONC.tmPreferences @@ -0,0 +1,25 @@ + + + + scope + source.json.jsonc + settings + + shellVariables + + + nameTM_COMMENT_START + value// + + + nameTM_COMMENT_START_2 + value/* + + + nameTM_COMMENT_END_2 + value*/ + + + + + diff --git a/JSON/Comments.tmPreferences b/JSON/Comments.tmPreferences deleted file mode 100644 index d9695e9cf24..00000000000 --- a/JSON/Comments.tmPreferences +++ /dev/null @@ -1,31 +0,0 @@ - - - - scope - source.json - settings - - shellVariables - - - name - TM_COMMENT_START - value - // - - - name - TM_COMMENT_START_2 - value - /* - - - name - TM_COMMENT_END_2 - value - */ - - - - - diff --git a/JSON/Context.sublime-menu b/JSON/Context.sublime-menu new file mode 100644 index 00000000000..c55090cced5 --- /dev/null +++ b/JSON/Context.sublime-menu @@ -0,0 +1,29 @@ +// Packages/JSON/Context.sublime-menu + + +// This file is being maintained at: +// https://github.com/sublimehq/Packages/blob/master/JSON/Context.sublime-menu + + +[ + // visible only with JSON syntax highlighting + { + "caption": "JSON: Minify", + "command": "json_minify" + }, + { + "caption": "JSON: Prettify", + "command": "json_prettify" + }, + + + // visible only with JSONC syntax highlighting + { + "caption": "JSONC: Minify", + "command": "jsonc_minify" + }, + { + "caption": "JSONC: Prettify", + "command": "jsonc_prettify" + } +] diff --git a/JSON/Default.sublime-commands b/JSON/Default.sublime-commands new file mode 100644 index 00000000000..c6a9be5e676 --- /dev/null +++ b/JSON/Default.sublime-commands @@ -0,0 +1,29 @@ +// Packages/JSON/Default.sublime-commands + + +// This file is being maintained at: +// https://github.com/sublimehq/Packages/blob/master/JSON/Default.sublime-commands + + +[ + // visible only with JSON syntax highlighting + { + "caption": "JSON: Minify JSON", + "command": "json_minify" + }, + { + "caption": "JSON: Prettify JSON", + "command": "json_prettify" + }, + + + // visible only with JSONC syntax highlighting + { + "caption": "JSONC: Minify JSONC", + "command": "jsonc_minify" + }, + { + "caption": "JSONC: Prettify JSONC", + "command": "jsonc_prettify" + } +] diff --git a/JSON/Default.sublime-keymap b/JSON/Default.sublime-keymap index e11d9bce5c6..56ef9e4a4e7 100644 --- a/JSON/Default.sublime-keymap +++ b/JSON/Default.sublime-keymap @@ -1,63 +1,70 @@ +// Packages/JSON/Default.sublime-keymap + + +// This file is being maintained at: +// https://github.com/sublimehq/Packages/blob/master/JSON/Default.sublime-keymap + + [ - // Auto-pair quotations: "key": '|', - { "keys": ["'"], "command": "insert_snippet", "args": {"contents": "'$0'"}, "context": - [ - { "key": "setting.auto_match_enabled" }, - { "key": "selector", "operand": "source.json" }, - { "key": "selection_empty", "match_all": true }, - { "key": "preceding_text", "operator": "not_regex_contains", "operand": "['\\w]$", "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |]|,|:|\\}|$)", "match_all": true } - ] - }, - - // Auto-pair quotations: "key": "|", - { "keys": ["\""], "command": "insert_snippet", "args": {"contents": "\"$0\""}, "context": - [ - { "key": "setting.auto_match_enabled" }, - { "key": "selector", "operand": "source.json" }, - { "key": "selection_empty", "match_all": true }, - { "key": "preceding_text", "operator": "not_regex_contains", "operand": "[\"\\w]$", "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |]|,|:|\\}|$)", "match_all": true } - ] - }, - - // Auto-pair braces: "key": {|}, - { "keys": ["{"], "command": "insert_snippet", "args": {"contents": "{$0}"}, "context": - [ - { "key": "setting.auto_match_enabled" }, - { "key": "selector", "operand": "source.json" }, - { "key": "selection_empty", "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |]|,|:|\\}|$)", "match_all": true } - ] - }, - - // Auto-pair square brackets: "key": [|], - { "keys": ["["], "command": "insert_snippet", "args": {"contents": "[$0]"}, "context": - [ - { "key": "setting.auto_match_enabled" }, - { "key": "selector", "operand": "source.json" }, - { "key": "selection_empty", "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |]|,|:|\\}|$)", "match_all": true } - ] - }, - - // Add indented line in square brackets - { "keys": ["enter"], "command": "insert_snippet", "args": {"contents": "\n\t$0\n"}, "context": - [ - { "key": "setting.auto_indent" }, - { "key": "selector", "operand": "source.json" }, - { "key": "selection_empty", "match_all": true }, - { "key": "preceding_text", "operator": "regex_contains", "operand": "\\[$", "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^\\]", "match_all": true } - ] - }, - { "keys": ["shift+enter"], "command": "insert_snippet", "args": {"contents": "\n\t$0\n"}, "context": - [ - { "key": "setting.auto_indent" }, - { "key": "selector", "operand": "source.json" }, - { "key": "selection_empty", "match_all": true }, - { "key": "preceding_text", "operator": "regex_contains", "operand": "\\[$", "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^\\]", "match_all": true } - ] - }, -] \ No newline at end of file + // Auto-pair quotations: "key": '|', + { "keys": ["'"], "command": "insert_snippet", "args": {"contents": "'$0'"}, "context": + [ + { "key": "setting.auto_match_enabled" }, + { "key": "selector", "operand": "source.json" }, + { "key": "selection_empty", "match_all": true }, + { "key": "preceding_text", "operator": "not_regex_contains", "operand": "['\\w]$", "match_all": true }, + { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |]|,|:|\\}|$)", "match_all": true } + ] + }, + + // Auto-pair quotations: "key": "|", + { "keys": ["\""], "command": "insert_snippet", "args": {"contents": "\"$0\""}, "context": + [ + { "key": "setting.auto_match_enabled" }, + { "key": "selector", "operand": "source.json" }, + { "key": "selection_empty", "match_all": true }, + { "key": "preceding_text", "operator": "not_regex_contains", "operand": "[\"\\w]$", "match_all": true }, + { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |]|,|:|\\}|$)", "match_all": true } + ] + }, + + // Auto-pair braces: "key": {|}, + { "keys": ["{"], "command": "insert_snippet", "args": {"contents": "{$0}"}, "context": + [ + { "key": "setting.auto_match_enabled" }, + { "key": "selector", "operand": "source.json" }, + { "key": "selection_empty", "match_all": true }, + { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |]|,|:|\\}|$)", "match_all": true } + ] + }, + + // Auto-pair square brackets: "key": [|], + { "keys": ["["], "command": "insert_snippet", "args": {"contents": "[$0]"}, "context": + [ + { "key": "setting.auto_match_enabled" }, + { "key": "selector", "operand": "source.json" }, + { "key": "selection_empty", "match_all": true }, + { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |]|,|:|\\}|$)", "match_all": true } + ] + }, + + // Add indented line in square brackets + { "keys": ["enter"], "command": "insert_snippet", "args": {"contents": "\n\t$0\n"}, "context": + [ + { "key": "setting.auto_indent" }, + { "key": "selector", "operand": "source.json" }, + { "key": "selection_empty", "match_all": true }, + { "key": "preceding_text", "operator": "regex_contains", "operand": "\\[$", "match_all": true }, + { "key": "following_text", "operator": "regex_contains", "operand": "^\\]", "match_all": true } + ] + }, + { "keys": ["shift+enter"], "command": "insert_snippet", "args": {"contents": "\n\t$0\n"}, "context": + [ + { "key": "setting.auto_indent" }, + { "key": "selector", "operand": "source.json" }, + { "key": "selection_empty", "match_all": true }, + { "key": "preceding_text", "operator": "regex_contains", "operand": "\\[$", "match_all": true }, + { "key": "following_text", "operator": "regex_contains", "operand": "^\\]", "match_all": true } + ] + }, +] diff --git a/JSON/Fold.tmPreferences b/JSON/Fold.tmPreferences deleted file mode 100644 index 09d2cbf5356..00000000000 --- a/JSON/Fold.tmPreferences +++ /dev/null @@ -1,27 +0,0 @@ - - - - scope - source.json - settings - - indentationFoldingEnabled - - foldScopes - - - begin - punctuation.section.sequence.begin - end - punctuation.section.sequence.end - - - begin - punctuation.section.mapping.begin - end - punctuation.section.mapping.end - - - - - diff --git a/JSON/Folding Rules - JSON.tmPreferences b/JSON/Folding Rules - JSON.tmPreferences new file mode 100644 index 00000000000..6fbb72cbbe6 --- /dev/null +++ b/JSON/Folding Rules - JSON.tmPreferences @@ -0,0 +1,27 @@ + + + + scope + source.json - (source.json.json-dotnet | source.json.json5 | source.json.jsonc) + settings + + indentationFoldingEnabled + + foldScopes + + + begin + punctuation.definition.mapping.begin + end + punctuation.definition.mapping.end + + + begin + punctuation.definition.sequence.begin + end + punctuation.definition.sequence.end + + + + + diff --git a/JSON/Folding Rules - JSON5.tmPreferences b/JSON/Folding Rules - JSON5.tmPreferences new file mode 100644 index 00000000000..a77da66569c --- /dev/null +++ b/JSON/Folding Rules - JSON5.tmPreferences @@ -0,0 +1,31 @@ + + + + scope + source.json.json5 + settings + + foldScopes + + + begin + punctuation.definition.comment.begin + end + punctuation.definition.comment.end + + + begin + punctuation.definition.mapping.begin + end + punctuation.definition.mapping.end + + + begin + punctuation.definition.sequence.begin + end + punctuation.definition.sequence.end + + + + + diff --git a/JSON/Folding Rules - JSONC.tmPreferences b/JSON/Folding Rules - JSONC.tmPreferences new file mode 100644 index 00000000000..5c219270eeb --- /dev/null +++ b/JSON/Folding Rules - JSONC.tmPreferences @@ -0,0 +1,31 @@ + + + + scope + source.json.jsonc + settings + + foldScopes + + + begin + punctuation.definition.comment.begin + end + punctuation.definition.comment.end + + + begin + punctuation.definition.mapping.begin + end + punctuation.definition.mapping.end + + + begin + punctuation.definition.sequence.begin + end + punctuation.definition.sequence.end + + + + + diff --git a/JSON/Folding Rules - JSON_dotNET.tmPreferences b/JSON/Folding Rules - JSON_dotNET.tmPreferences new file mode 100644 index 00000000000..6b1b4bd8892 --- /dev/null +++ b/JSON/Folding Rules - JSON_dotNET.tmPreferences @@ -0,0 +1,27 @@ + + + + scope + source.json.json-dotnet + settings + + indentationFoldingEnabled + + foldScopes + + + begin + punctuation.definition.mapping.begin + end + punctuation.definition.mapping.end + + + begin + punctuation.definition.sequence.begin + end + punctuation.definition.sequence.end + + + + + diff --git a/JSON/JSON.sublime-completions b/JSON/JSON.sublime-completions new file mode 100644 index 00000000000..2bffbac3e4a --- /dev/null +++ b/JSON/JSON.sublime-completions @@ -0,0 +1,27 @@ +{ + "scope": "source.json", + "completions": + [ + { + "trigger": "true", + "contents": "true", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "literal JSON constant" + }, + { + "trigger": "false", + "contents": "false", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "literal JSON constant" + }, + { + "trigger": "null", + "contents": "null", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "literal JSON constant" + } + ] +} diff --git a/JSON/JSON.sublime-settings b/JSON/JSON.sublime-settings new file mode 100644 index 00000000000..40b58cd7ac7 --- /dev/null +++ b/JSON/JSON.sublime-settings @@ -0,0 +1,13 @@ +// Packages/JSON/JSON.sublime-settings +// Settings - Syntax Specific (Default) +// +// This file is being maintained at: +// https://github.com/sublimehq/Packages/blob/master/JSON/JSON.sublime-settings + + +{ + "default_extension": "json", + + // whether `on_pre_save_async` events auto-trigger the `json_prettify` command + "json.auto_prettify": false +} diff --git a/JSON/JSON.sublime-syntax b/JSON/JSON.sublime-syntax index 9d1aa3aa281..239981a8d96 100644 --- a/JSON/JSON.sublime-syntax +++ b/JSON/JSON.sublime-syntax @@ -1,171 +1,534 @@ %YAML 1.2 --- +# YAML Documentation: +# https://yaml.org/spec/1.2/spec.html +# Sublime Text Documentation: +# https://www.sublimetext.com/docs/syntax.html#ver-dev +# https://www.sublimetext.com/docs/syntax.html#testing:ver-dev +# https://www.sublimetext.com/docs/scope_naming.html +# This file is being maintained at: +# https://github.com/sublimehq/Packages/blob/master/JSON/JSON.sublime-syntax + name: JSON scope: source.json version: 2 file_extensions: - json - - sublime-build - - sublime-color-scheme - - sublime-commands - - sublime-completions - - sublime-keymap - - sublime-macro - - sublime-menu - - sublime-mousemap - - sublime-project - - sublime-settings - - sublime-theme - - sublime-workspace - - ipynb + # https://www.json.org/json-en.html + # https://datatracker.ietf.org/doc/html/rfc7159 + # https://www.ecma-international.org/publications-and-standards/standards/ecma-404/ + +hidden_file_extensions: + - .bowerrc + # Bower + # https://bower.io/docs/config/ + + - .htmlhintrc + # HTML hint + # https://htmlhint.com/docs/user-guide/getting-started + + - .jscsrc + # JavaScript Code Style Configuration + # https://jscs-dev.github.io + + - .markdownlintrc + # https://github.com/DavidAnson/markdownlint + + - .tern-config + # Tern.js Server Configuration + # https://ternjs.net/doc/manual.html#server + + - .tern-project + # Tern.js Project Configuration + # https://ternjs.net/doc/manual.html#configuration + + - .watchmanconfig + # Facebook Watchman + # root specific configuration file + # https://facebook.github.io/watchman/docs/config.html + - Pipfile.lock + # Pipfile + # https://github.com/pypa/pipfile + + - avsc + # Pure JavaScript implementation of the Avro specification + # https://github.com/mtth/avsc + + - composer.lock + # Composer lock file + # https://getcomposer.org/doc/01-basic-usage.md + + - css.map + # CSS Source Map + + - geojson + # JSON for geographic data structures + # https://geojson.org + # https://datatracker.ietf.org/wg/geojson/charter/ + # https://datatracker.ietf.org/doc/html/rfc7946 + - gltf + # glTF Runtime 3D asset delivery + # https://www.khronos.com/gltf + + - har + # HTTP Archive Format + + - ipynb + # Jupyter Notebook, formerly known as iPython Notebook + # https://jupyter.org/documentation + + - js.map + # JavaScript Source Map + + - jsonld + # JSON for Linking Data + # https://json-ld.org + + - ldjson + # JSON for Linking Data + # https://json-ld.org + + - schema + # JSON Schema + # https://json-schema.org/learn + + - tfstate + # Hashicorp Terraform State + # https://www.terraform.io/docs/language/state/index.html + + - tfstate.backup + # Hashicorp Terraform State + # https://www.terraform.io/docs/language/state/index.html + + - topojson + # TopoJSON, an extension to GeoJSON + # https://github.com/topojson/topojson-specification + + - ts.map + # TypeScript Source Map + + - webapp + # Web app manifests + # https://developer.mozilla.org/en-US/docs/Web/Manifest + + - webmanifest + # Web app manifests + # https://developer.mozilla.org/en-US/docs/Web/Manifest first_line_match: |- (?xi: - ^ \s* // .*? -\*- .*? \bjson\b .*? -\*- # editorconfig + ^ \s* // .*? -\*- .*? \bjson\b .*? -\*- # editorconfig ) +variables: + exponent: (?:[eE][-+]?\d+) + pos_integer_decimal: (?:0|[1-9]\d*) + html_entity: '&([a-zA-Z0-9]+|#\d+|#[Xx]\h+);' + email_domain: '[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?' + email_user: '[a-zA-Z0-9.!#$%&''*+/=?^_`{|}~-]+' + +######################################################################################################################## + contexts: prototype: - include: comments main: - - include: value + - match: (?=\S) + push: + - invalid-remainder + - any-else-pop - value: - - include: constant - - include: number - - include: string - - include: array - - include: object +####[ Helpers ]######################################################################################################### - array: - - match: \[ - scope: punctuation.section.sequence.begin.json - push: - - meta_scope: meta.sequence.json - - match: \] - scope: punctuation.section.sequence.end.json - pop: 1 - - include: value - - match: ',' - scope: punctuation.separator.sequence.json - - match: '[^\s\]]' - scope: invalid.illegal.expected-sequence-separator.json + any: + - include: structures + - include: values + + any-else-pop: + - include: any + - include: else-pop + + structures: + - include: objects + - include: arrays + + values: + - include: constants + - include: numbers + - include: strings + + invalid-remainder: + - match: '[,:]' + scope: invalid.illegal.unexpected-separator.json + - match: '[^,:\s]+' + scope: invalid.illegal.unexpected-code-after-first-structure-or-value.json + +####[ Prototypes ]###################################################################################################### + + else-pop: + - match: (?=\S) + pop: 1 + + eol-pop: + - match: '$\n?' + pop: 1 + +####[ Comments ]######################################################################################################## comments: - - match: /\*\*(?!/) - scope: punctuation.definition.comment.json - push: - - meta_scope: comment.block.documentation.json - - meta_include_prototype: false - - match: \*/ - pop: 1 - - match: ^\s*(\*)(?!/) - captures: - 1: punctuation.definition.comment.json + - include: comment-line + - include: comment-block + + comment-line: + - match: // + push: comment-line-content + + comment-line-content: + - meta_include_prototype: false + - meta_scope: invalid.illegal.comment.json + - include: eol-pop + + comment-block: + - match: /\*\*+/ + scope: invalid.illegal.comment.json - match: /\* - scope: punctuation.definition.comment.json - push: - - meta_scope: comment.block.json - - meta_include_prototype: false - - match: \*/ - pop: 1 - - match: (//).*$\n? - scope: comment.line.double-slash.js - captures: - 1: punctuation.definition.comment.json + push: comment-block-content + + comment-block-content: + - meta_include_prototype: false + - meta_scope: invalid.illegal.comment.json + - match: \*/ + pop: 1 + +####[ Constants ]####################################################################################################### + + constants: + - include: valid-constants + - include: invalid-constants - constant: + valid-constants: + - match: \b(?:null)\b + scope: constant.language.null.json + pop: 1 - match: \b(?:false|true)\b scope: constant.language.boolean.json - - match: \bnull\b - scope: constant.language.null.json + pop: 1 - number: - # handles integer and decimal numbers - - match: (-?)((?:0|[1-9]\d*)(?:(?:(\.)\d+)(?:[eE][-+]?\d+)?|(?:[eE][-+]?\d+))) + invalid-constants: + # when erroneously containing upper case letters + - match: \b(?i:null)\b + scope: invalid.illegal.expected-lower-case-null.json + pop: 1 + - match: \b(?i:false|true)\b + scope: invalid.illegal.expected-lower-case-boolean.json + pop: 1 + +####[ Numbers ]######################################################################################################### + + numbers: + - include: float + - include: integer + + float: + - include: decimal-float + + decimal-float: + - match: |- + (?x: + (?:(-)|(\+))? + ( + {{pos_integer_decimal}} + (?: + (\.)\d+ {{exponent}}? # 1.1 1.1e1 1.1e-1 1.1e+1 + | {{exponent}} # 1e1 1+e1 1-e1 + ) + ) + ) scope: meta.number.float.decimal.json captures: - 1: keyword.operator.arithmetic.json - 2: constant.numeric.value.json - 3: punctuation.separator.decimal.json - - match: (-?)(0|[1-9]\d*) + 1: constant.numeric.sign.json + 2: invalid.illegal.numeric-sign.json + 3: constant.numeric.value.json + 4: punctuation.separator.decimal.json + pop: 1 + + integer: + - include: decimal-integer + + decimal-integer: + - match: (?:(-)|(\+))?({{pos_integer_decimal}}) scope: meta.number.integer.decimal.json captures: - 1: keyword.operator.arithmetic.json - 2: constant.numeric.value.json + 1: constant.numeric.sign.json + 2: invalid.illegal.numeric-sign.json + 3: constant.numeric.value.json + pop: 1 - object: - # a JSON object - - match: \{ - scope: punctuation.section.mapping.begin.json - push: - - meta_scope: meta.mapping.json - - match: \} - scope: punctuation.section.mapping.end.json - pop: 1 - - match: \" - scope: punctuation.definition.string.begin.json - push: - - clear_scopes: 1 - - meta_scope: meta.mapping.key.json string.quoted.double.json - - meta_include_prototype: false - - include: inside-string - - match: ':' - scope: punctuation.separator.key-value.json - push: - - match: ',|\s?(?=\})' - scope: invalid.illegal.expected-mapping-value.json - pop: 1 - - match: (?=\S) - set: - - clear_scopes: 1 - - meta_scope: meta.mapping.value.json - - include: value - - match: '' - set: - - match: ',' - scope: punctuation.separator.sequence.json - pop: 1 - - match: \s*(?=\}) - pop: 1 - - match: \s(?!/[/*])(?=[^\s,])|[^\s,] - scope: invalid.illegal.expected-mapping-separator.json - pop: 1 - - match: '[^\s\}]' - scope: invalid.illegal.expected-mapping-key.json - - string: +####[ Strings ]######################################################################################################### + + strings: + - include: double-quoted-string + + double-quoted-string: - match: \" scope: punctuation.definition.string.begin.json - push: inside-string + set: double-quoted-string-content - inside-string: - - meta_scope: string.quoted.double.json + double-quoted-string-content: - meta_include_prototype: false + - meta_scope: >- + meta.string.json + string.quoted.double.json - match: \" scope: punctuation.definition.string.end.json pop: 1 - - include: string-escape + - include: double-quoted-string-escape-characters + - include: links - match: \n scope: invalid.illegal.unclosed-string.json pop: 1 - string-escape: + links: + - include: autolink-email + - include: autolink-inet + + autolink-email: - match: |- - (?x: # turn on extended mode - \\ # a literal backslash - (?: # ...followed by... - ["\\/bfnrt] # one of these characters - | # ...or... - u # a u - [0-9a-fA-F]{4} # and four hex digits + (?x: + (<) + ( + (?:mailto(:))? + {{email_user}} + (@) + {{email_domain}}(?:\.{{email_domain}})* ) + (>) ) - scope: constant.character.escape.json + scope: meta.link.email.json + captures: + 1: punctuation.definition.link.begin.json + 2: markup.underline.link.json + 3: punctuation.separator.path.json + 4: punctuation.separator.path.json + 5: punctuation.definition.link.end.json + - match: |- + (?x: + [\w.+-]+ + (@) + [\w-]+(?:\.(?:(?![._-][\W])[\w_-])+)+(?![_-]) + ) + scope: >- + meta.link.email.json + markup.underline.link.json + captures: + 1: punctuation.separator.path.json + + autolink-inet: + - match: <(?=[[:alpha:]][[:alnum:].+-]+:) + scope: punctuation.definition.link.begin.json + push: + - autolink-inet-angled-content + - link-url-scheme-separator + - match: (?:(?:https|http|ftp)(://)|www\.)[\w-]+ + captures: + 1: punctuation.separator.path.json + push: autolink-inet-unquoted-content + + autolink-inet-angled-content: + - meta_scope: meta.link.inet.json + - meta_content_scope: markup.underline.link.json + - match: \> + scope: punctuation.definition.link.end.json + pop: 1 + - match: (?=\s) + pop: 1 + - include: autolink-inet-common + + autolink-inet-unquoted-content: + - meta_scope: >- + meta.link.inet.json + markup.underline.link.json + - match: (?=(?:\)|(?:{{html_entity}})*)[?!.,:*_~]*[\s<]) + pop: 1 + - include: autolink-inet-common + + autolink-inet-group: + - match: \) + pop: 1 + - match: (?=(?:{{html_entity}})*[?!.,:*_~]*[\s<]) + pop: 1 + - include: autolink-inet-common + + autolink-inet-common: + - match: \( + push: autolink-inet-group + - match: '[/&?#]' + scope: punctuation.separator.path.json + - match: (%)\h{2} + scope: constant.character.escape.url.json + captures: + 1: punctuation.definition.escape.json + + link-url-scheme-separator: + - match: ':/{,2}' + scope: punctuation.separator.path.json + pop: 1 + + double-quoted-string-escape-characters: + - match: (\\)\" + scope: constant.character.escape.double-quote.json # quotation mark + captures: + 1: punctuation.definition.escape.json + - include: string-escape-characters + + string-escape-characters: + - include: valid-string-escape-characters + - include: invalid-string-escape-characters + + valid-string-escape-characters: + - match: (\\)\\ + scope: constant.character.escape.back-slash.json # reverse solidus + captures: + 1: punctuation.definition.escape.json + - match: (\\)\/ + scope: constant.character.escape.forward-slash.json # solidus + captures: + 1: punctuation.definition.escape.json + - match: (\\)b + scope: constant.character.escape.backspace.json + captures: + 1: punctuation.definition.escape.json + - match: (\\)f + scope: constant.character.escape.form-feed.json + captures: + 1: punctuation.definition.escape.json + - match: (\\)n + scope: constant.character.escape.newline.json # linefeed + captures: + 1: punctuation.definition.escape.json + - match: (\\)r + scope: constant.character.escape.carriage-return.json + captures: + 1: punctuation.definition.escape.json + - match: (\\)t + scope: constant.character.escape.horizontal-tab.json + captures: + 1: punctuation.definition.escape.json + - match: (\\)u[0-9a-fA-F]{4} + scope: >- + constant.character.escape.unicode-symbol.basic-multilingual-plane.json + captures: + 1: punctuation.definition.escape.json + + invalid-string-escape-characters: - match: \\. scope: invalid.illegal.unrecognized-string-escape.json + +####[ Sequences ]####################################################################################################### + + arrays: + - match: \[ + scope: punctuation.definition.sequence.begin.json + set: + - array-body + - array-item + + array-body: + - meta_scope: meta.sequence.list.json + - match: \] + scope: punctuation.definition.sequence.end.json + pop: 1 + - include: array-separators + + array-separators: + - match: (?=,) + branch_point: array-separators + branch: + - valid-array-separator + - invalid-array-separator + - match: (?=\S) + push: array-item + + valid-array-separator: + - match: ',' + scope: punctuation.separator.sequence.json + set: array-expect-value + + array-expect-value: + - match: (?=\]) + fail: array-separators + - include: array-item + + array-item: + - include: any + - include: invalid-array-separator + + invalid-array-separator: + - match: ',' + scope: invalid.illegal.unexpected-separator.json + - include: else-pop + +####[ Mappings ]######################################################################################################## + + # FIXME: leading separators + # FIXME: trailing commas + + objects: + - match: \{ + scope: punctuation.definition.mapping.begin.json + set: object-body + + object-body: + - meta_scope: meta.mapping.json + - match: \} + scope: punctuation.definition.mapping.end.json + pop: 1 + - include: mapping-key + - include: mapping-separator + - match: '[^\s\}]' + scope: invalid.illegal.expected-mapping-key.json + + mapping-key: + - match: \" + scope: punctuation.definition.string.begin.json + push: mapping-key-double-quoted + + mapping-key-double-quoted: + - clear_scopes: 1 + - meta_include_prototype: false + - meta_scope: >- + meta.mapping.key.json + meta.string.json + string.quoted.double.json + - include: double-quoted-string-content + + mapping-separator: + - match: ':' + scope: punctuation.separator.key-value.json + push: mapping-expect-value + + mapping-expect-value: + - match: ',|\s?(?=\})' + scope: invalid.illegal.expected-mapping-value.json + pop: 1 + - match: (?=\S) + set: + - mapping-value + - any-else-pop + + mapping-value: + - clear_scopes: 1 + - meta_scope: meta.mapping.value.json + - match: ',' + scope: punctuation.separator.sequence.json + pop: 1 + - match: \s*(?=\}) + pop: 1 + - match: \s(?!/[/*])(?=[^\s,])|[^\s,] + scope: invalid.illegal.expected-mapping-separator.json + pop: 1 diff --git a/JSON/JSON5.sublime-completions b/JSON/JSON5.sublime-completions new file mode 100644 index 00000000000..6cfbd1d9c3d --- /dev/null +++ b/JSON/JSON5.sublime-completions @@ -0,0 +1,48 @@ +{ + "scope": "source.json.json5", + "completions": + [ + { + "trigger": "Infinity", + "contents": "Infinity", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "JSON5 number

IEEE 754 positive infinity
literal constant \"Infinity\"" + }, + { + "trigger": "Infinity", + "contents": "+Infinity", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "JSON5 number

IEEE 754 positive infinity
literal constant \"Infinity\" with an optional plus as prefix" + }, + { + "trigger": "Infinity", + "contents": "-Infinity", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "JSON5 number

IEEE 754 negative infinity
literal constant \"-Infinity\"" + }, + { + "trigger": "NaN", + "contents": "NaN", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "JSON5 number

IEEE 754 NaN
literal constant \"NaN\"" + }, + { + "trigger": "NaN", + "contents": "+NaN", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "JSON5 number

IEEE 754 NaN
literal constant \"NaN\" with an optional plus as prefix" + }, + { + "trigger": "NaN", + "contents": "-NaN", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "JSON5 number

IEEE 754 NaN
literal constant \"NaN\" with an optional minus as prefix" + } + ] +} diff --git a/JSON/JSON5.sublime-settings b/JSON/JSON5.sublime-settings new file mode 100644 index 00000000000..047cb2547ad --- /dev/null +++ b/JSON/JSON5.sublime-settings @@ -0,0 +1,10 @@ +// Packages/JSON/JSON5.sublime-settings +// Settings - Syntax Specific (Default) +// +// This file is being maintained at: +// https://github.com/sublimehq/Packages/blob/master/JSON/JSON5.sublime-settings + + +{ + "default_extension": "json5" +} diff --git a/JSON/JSON5.sublime-syntax b/JSON/JSON5.sublime-syntax new file mode 100644 index 00000000000..ffe7c7a8c1f --- /dev/null +++ b/JSON/JSON5.sublime-syntax @@ -0,0 +1,255 @@ +%YAML 1.2 +--- +# YAML Documentation: +# https://yaml.org/spec/1.2/spec.html +# Sublime Text Documentation: +# https://www.sublimetext.com/docs/syntax.html#ver-dev +# https://www.sublimetext.com/docs/syntax.html#testing:ver-dev +# https://www.sublimetext.com/docs/scope_naming.html +# This file is being maintained at: +# https://github.com/sublimehq/Packages/blob/master/JSON/JSON5.sublime-syntax + +name: JSON5 +scope: source.json.json5 +version: 2 + +# https://www.sublimetext.com/docs/syntax.html#inheritance +extends: Packages/JSON/JSONC.sublime-syntax + +file_extensions: + - json5 + # https://json5.org/ + # https://spec.json5.org/#summary-of-features + # https://262.ecma-international.org/5.1/ + +hidden_file_extensions: + - .babelrc + # Babel.js File-relative Configuration + # https://babeljs.io/docs/en/config-files + + - .babelrc.json + # Babel.js File-relative Configuration + # https://babeljs.io/docs/en/config-files + + - .jupyterlab-settings + # JupyterLab User Settings + # https://jupyterlab.readthedocs.io/en/stable/user/directories.html?highlight=json5#jupyterlab-user-settings-directory + + - .parcelrc + # parcel Bundler Configuration + # https://github.com/parcel-bundler/parcel + # https://parceljs.org/features/plugins/#.parcelrc + + - .postcssrc.json + # PostCSS Configuration + # https://postcss.org + + - babel.config.json + # Babel.js Project-wide Configuration + # https://babeljs.io/docs/en/config-files + + - next.config.json + # Vercel Next.js Configuration + # https://nextjs.org/docs/api-reference/next.config.js/introduction + + - nextrc.json + # Vercel Next.js Configuration + # https://nextjs.org/docs/api-reference/next.config.js/introduction + + - techdocs_metadata.json + # Spotify's @backstage/techdocs_common Configuration + # https://github.com/backstage/backstage/tree/master/packages/techdocs-common + # https://backstage.io/docs/features/techdocs/techdocs-overview + +first_line_match: |- + (?xi: + ^ \s* // .*? -\*- .*? \bjson5\b .*? -\*- # editorconfig + ) + +variables: + + # Boost documentation: + # https://www.boost.org/doc/libs/1_64_0/libs/regex/doc/html/boost_regex/syntax/perl_syntax.html + # Unicode documentation: + # https://www.unicode.org/versions/latest/ + # https://www.unicode.org/Public/UCD/latest/ucd/ + # Oniguruma documentation: + # https://github.com/kkos/oniguruma/blob/master/doc/RE + # https://github.com/kkos/oniguruma/blob/master/doc/UNICODE_PROPERTIES + + identifier_escape: (?:\\u(?:\h{4}|\{\h+\})) + identifier_start: (?:[_$\p{L}\p{Nl}]|{{identifier_escape}}) + identifier_part: (?:[_$\p{L}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\x{200C}\x{200D}]|{{identifier_escape}}) + identifier_break: (?!{{identifier_part}}) + + identifier_name: (?:{{identifier_start}}{{identifier_part}}*{{identifier_break}}) + +######################################################################################################################## + +contexts: + + # TODO: check whitespace valid chars + +####[ Numbers ]######################################################################################################### + + decimal-float: + - match: |- + (?x: + ([-+]?) + ( + {{pos_integer_decimal}} + (?: + (\.)\d* {{exponent}}? # 1. 1.e1 1.e-1 1.e+1 1.1 1.1e1 1.1e-1 1.1e+1 + | {{exponent}} # 1e1 1+e1 1-e1 + ) + | (\.)\d+ {{exponent}}? # .1 .1e1 .1e+1 .1e-1 + ) + ) + scope: meta.number.float.decimal.json5 + captures: + 1: constant.numeric.sign.json5 + 2: constant.numeric.value.json5 + 3: punctuation.separator.decimal.json5 + 4: punctuation.separator.decimal.json5 + pop: 1 + - match: ([-+]?)(Infinity) + scope: meta.number.float.decimal.json5 + captures: + 1: constant.numeric.sign.json5 + 2: constant.language.infinity.json5 + pop: 1 + - match: ([-+]?)(NaN) + scope: meta.number.float.decimal.json5 + captures: + 1: constant.numeric.sign.json5 + 2: constant.language.nan.json5 + pop: 1 + + # when erroneously containing wrongly cased letters + - match: ([-+]?)(?i:(infinity)) + scope: meta.number.float.decimal.json5 + captures: + 1: constant.numeric.sign.json5 + 2: invalid.illegal.expected-language-constant.json5 + pop: 1 + - match: ([-+]?)(?i:(nan)) + scope: meta.number.float.decimal.json5 + captures: + 1: constant.numeric.sign.json5 + 2: invalid.illegal.expected-language-constant.json5 + pop: 1 + + integer: + - meta_prepend: true + - include: hexadecimal-integer + + decimal-integer: + - match: ([-+]?)({{pos_integer_decimal}}) + scope: meta.number.integer.decimal.json5 + captures: + 1: constant.numeric.sign.json5 + 2: constant.numeric.value.json5 + pop: 1 + + hexadecimal-integer: + - match: ([-+]?)(0[xX])(\h+) + scope: meta.number.integer.hexadecimal.json5 + captures: + 1: constant.numeric.sign.json5 + 2: constant.numeric.base.json5 + 3: constant.numeric.value.json5 + pop: 1 + +####[ Strings ]######################################################################################################### + + strings: + - meta_append: true + - include: single-quoted-string + + single-quoted-string: + - match: \' + scope: punctuation.definition.string.begin.json5 + set: single-quoted-string-content + + single-quoted-string-content: + - meta_include_prototype: false + - meta_scope: >- + meta.string.json5 + string.quoted.single.json5 + - match: \' + scope: punctuation.definition.string.end.json5 + pop: 1 + - include: single-quoted-string-escape-characters + - match: \n + scope: invalid.illegal.unclosed-string.json5 + pop: 1 + + single-quoted-string-escape-characters: + - match: \\\' + scope: constant.character.escape.single-quote.json5 + - include: string-escape-characters + + valid-string-escape-characters: + - meta_prepend: true + - match: ((\\)\x{2028})(.*)$\n? + captures: + 1: constant.character.escape.line-separator.json5 + 2: punctuation.separator.continuation.line.json5 + 3: invalid.illegal.expected-eol-after-line-continuation.json5 + - match: ((\\)\x{2029})(.*)$\n? + captures: + 1: constant.character.escape.paragraph-separator.json5 + 2: punctuation.separator.continuation.line.json5 + 3: invalid.illegal.expected-eol-after-line-continuation.json5 + - match: (\\)$\n? + captures: + 1: punctuation.separator.continuation.line.json5 + - match: \\v + scope: constant.character.escape.vertical-tab.json5 + - match: (\\0)([0-9])? + captures: + 1: constant.character.escape.null.json5 + 2: invalid.illegal.unexpected-digit-character.json5 + - match: \\x[0-9a-fA-F]{2} + scope: constant.character.escape.unicode-symbol.basic-latin-or-latin-1-supplement.json5 + - match: \\u[0-9a-fA-F]{4}\\u[0-9a-fA-F]{4} + scope: constant.character.escape.unicode-symbol.utf16-surrogate-pair.json5 + + invalid-string-escape-characters: + - meta_prepend: true + - match: ([^\\])(?:\x{2028}|\x{2029}) + captures: + 1: invalid.illegal.expected-backslash-char.json5 + +####[ Mappings ]######################################################################################################## + + mapping-key: + - meta_append: true + - match: \' + scope: punctuation.definition.string.begin.json5 + push: mapping-key-single-quoted + + # looking ahead at `identifier_start` would've been faster with possibly + # invalid matches, but we want to make sure we only match valid ecma + # `identifier_name`s as keys + - match: (?={{identifier_name}}) + push: mapping-key-ecma + + mapping-key-ecma: + - clear_scopes: 1 + - meta_include_prototype: false + - meta_scope: >- + meta.mapping.key.json5 + meta.string.json5 + string.unquoted.plain.json5 + - match: '{{identifier_break}}' + pop: 1 + + mapping-key-single-quoted: + - clear_scopes: 1 + - meta_include_prototype: false + - meta_scope: >- + meta.mapping.key.json5 + meta.string.json5 + string.quoted.single.json5 + - include: single-quoted-string-content diff --git a/JSON/JSONC.sublime-settings b/JSON/JSONC.sublime-settings new file mode 100644 index 00000000000..9bd53bcb1f2 --- /dev/null +++ b/JSON/JSONC.sublime-settings @@ -0,0 +1,10 @@ +// Packages/JSON/JSONC.sublime-settings +// Settings - Syntax Specific (Default) +// +// This file is being maintained at: +// https://github.com/sublimehq/Packages/blob/master/JSON/JSONC.sublime-settings + + +{ + "default_extension": "jsonc" +} diff --git a/JSON/JSONC.sublime-syntax b/JSON/JSONC.sublime-syntax new file mode 100644 index 00000000000..280dccc816a --- /dev/null +++ b/JSON/JSONC.sublime-syntax @@ -0,0 +1,136 @@ +%YAML 1.2 +--- +# YAML Documentation: +# https://yaml.org/spec/1.2/spec.html +# Sublime Text Documentation: +# https://www.sublimetext.com/docs/syntax.html#ver-dev +# https://www.sublimetext.com/docs/syntax.html#testing:ver-dev +# https://www.sublimetext.com/docs/scope_naming.html +# This file is being maintained at: +# https://github.com/sublimehq/Packages/blob/master/JSON/JSONC.sublime-syntax + +name: JSONC +scope: source.json.jsonc +version: 2 + +# https://www.sublimetext.com/docs/syntax.html#inheritance +extends: Packages/JSON/JSON.sublime-syntax + +file_extensions: + - jsonc + + - sublime-build # https://www.sublimetext.com/docs/build_systems.html + - sublime-color-scheme # https://www.sublimetext.com/docs/color_schemes.html + - sublime-commands + - sublime-completions # https://www.sublimetext.com/docs/completions.html + - sublime-keymap # https://www.sublimetext.com/docs/key_bindings.html + - sublime-macro + - sublime-menu # https://www.sublimetext.com/docs/menus.html + - sublime-mousemap + - sublime-project # https://www.sublimetext.com/docs/projects.html + - sublime-settings # https://www.sublimetext.com/docs/settings.html + - sublime-theme # https://www.sublimetext.com/docs/themes.html + - sublime-workspace # https://www.sublimetext.com/docs/projects.html + +hidden_file_extensions: + - .ember-cli + + - .esformatter + # esformatter: ECMAScript code formatter + # https://github.com/millermedeiros/esformatter + + - .eslintrc + # ESLint Configuration + # https://eslint.org/docs/user-guide/configuring/ + + - .eslintrc.json + # ESLint Configuration + # https://eslint.org/docs/user-guide/configuring/ + + - .hintrc + # Webhint Configuration + # https://webhint.io/docs/user-guide/configuring-webhint/summary/ + + - .htmlhintrc + # HTMLHint Configuration + # https://htmlhint.com/docs/user-guide/configuration + + - .jsfmtrc + # jsfmt: For formatting, searching and re-writing JavaScript + # https://github.com/rdio/jsfmt#formatting + + - .jshintrc + # JSHint + # https://www.jshint.com/docs/#options + + - .jslintrc + # JSLint's implementation of JSHint + # https://www.jslint.com/lint.html + + - .stylintrc + # stylint Configuration + # https://github.com/SimenB/stylint + + - .swcrc + # swc Configuration + # https://swc.rs/docs/configuring-swc + + - eslintrc.json + # ESLint Configuration + # https://eslint.org/docs/user-guide/configuring/ + + - languagebabel + + - tsconfig.json + # TypeScript Configuration + # https://www.typescriptlang.org/docs/handbook/tsconfig-json.html + +first_line_match: |- + (?xi: + ^ \s* // .*? -\*- .*? \bjsonc\b .*? -\*- # editorconfig + ) + +######################################################################################################################## + +contexts: + +####[ Comments ]######################################################################################################## + + comment-line: + - match: // + scope: punctuation.definition.comment.jsonc + push: comment-line-content + + comment-line-content: + - meta_include_prototype: false + - meta_scope: comment.line.double-slash.jsonc + - include: eol-pop + + comment-block: + # empty block comments + - match: (/\*)\**(\*/) + scope: comment.block.empty.jsonc + captures: + 1: punctuation.definition.comment.begin.jsonc + 2: punctuation.definition.comment.end.jsonc + # normal block comments + - match: /\* + scope: punctuation.definition.comment.begin.jsonc + push: comment-block-content + + comment-block-content: + - meta_include_prototype: false + - meta_scope: comment.block.jsonc + - include: comment-block-end + + comment-block-end: + - match: \*/ + scope: punctuation.definition.comment.end.jsonc + pop: 1 + +####[ Sequences ]####################################################################################################### + + array-separators: + - match: ',' + scope: punctuation.separator.sequence.jsonc + push: array-item diff --git a/JSON/JSON_dotNET.sublime-syntax b/JSON/JSON_dotNET.sublime-syntax new file mode 100644 index 00000000000..cd20d59dbae --- /dev/null +++ b/JSON/JSON_dotNET.sublime-syntax @@ -0,0 +1,106 @@ +%YAML 1.2 +--- +# YAML Documentation: +# https://yaml.org/spec/1.2/spec.html +# Sublime Text Documentation: +# https://www.sublimetext.com/docs/syntax.html#ver-dev +# https://www.sublimetext.com/docs/syntax.html#testing:ver-dev +# https://www.sublimetext.com/docs/scope_naming.html +# This file is being maintained at: +# https://github.com/sublimehq/Packages/blob/master/JSON/JSON_dotNET.sublime-syntax +# +# Date formatting: +# https://www.iso.org/standard/70907.html (Basic rules) +# https://www.iso.org/standard/70908.html (Extensions) +# https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings + +name: 'JSON .NET' +scope: source.json.json-dotnet +version: 2 + +# https://www.sublimetext.com/docs/syntax.html#inheritance +extends: Packages/JSON/JSON.sublime-syntax + +first_line_match: |- + (?xi: + ^ \s* // .*? -\*- .*? \bjson\.net\b .*? -\*- # editorconfig + ) + +######################################################################################################################## + +contexts: + +####[ Strings ]######################################################################################################### + + strings: + - meta_prepend: true + - include: datetime-string + + datetime-string: + + # for date strings of json.Net v4.5+ with an ISO Date + # like "2000-01-01T00:00:00Z" + - match: |- + (?x: + (\") + ( + \d{4} [-] \d{2} [-] \d{2} + [Tt] + \d{2} [:] \d{2} [:] \d{2} + (?: + Z | [-+] \d{1,2} (?: [:]\d{1,2})? + )? + ) + (\") + ) + scope: >- + meta.string.json-dotnet + string.quoted.double.datetime.json-dotnet + captures: + 1: punctuation.definition.string.begin.json-dotnet + 2: constant.other.timestamp.json-dotnet + 3: punctuation.definition.string.end.json-dotnet + + # for date strings (of the old discontinued format) erroneously containing + # double escapes like "\/Date(1234)\/" + - match: |- + (?x: + (\") + ( + (\\) + \/Date\( + \d+ + \) + (\\) + \/ + ) + (\") + ) + scope: >- + meta.string.json-dotnet + string.quoted.double.datetime.json-dotnet + captures: + 1: punctuation.definition.string.begin.json-dotnet + 2: constant.other.timestamp.json-dotnet + 3: invalid.illegal.double-escape.json-dotnet + 4: invalid.illegal.double-escape.json-dotnet + 5: punctuation.definition.string.end.json-dotnet + + # the old discontinued format like "/Date(1234)/" + - match: |- + (?x: + (\") + ( + \/Date\( + \d+ + \)\/ + ) + (\") + ) + scope: >- + meta.string.json-dotnet + string.quoted.double.datetime.json-dotnet + captures: + 1: punctuation.definition.string.begin.json-dotnet + 2: constant.other.timestamp.json-dotnet + 3: punctuation.definition.string.end.json-dotnet diff --git a/JSON/Main.sublime-menu b/JSON/Main.sublime-menu new file mode 100644 index 00000000000..fe6d5172c22 --- /dev/null +++ b/JSON/Main.sublime-menu @@ -0,0 +1,130 @@ +// Packages/JSON/Main.sublime-menu +// +// This file is being maintained at: +// https://github.com/sublimehq/Packages/blob/master/JSON/Main.sublime-menu + + +[ + { + "id": "preferences", + "children": + [ + { + "id": "package-settings", + "children": + [ + { + "caption": "JSON", + "children": + [ + { + "caption": "JSON", + "children": + [ + { + "caption": "Minify", + "command": "json_minify" + }, + { + "caption": "Prettify", + "command": "json_prettify" + }, + { "caption": "-" }, + { + "caption": "Automatically prettify before saving", + "command": "json_toggle_auto_prettify" + }, + { + "caption": "Settings - Syntax Specific", + "command": "edit_settings", + "args": + { + "base_file": "${packages}/JSON/JSON.sublime-settings", + "default": "{\n\t$0\n}\n" + } + }, + { "caption": "-" }, + { + "caption": "Documentation: Specs", + "command": "open_url", + "args": + { + "url": "https://www.json.org/json-en.html" + } + }, + { + "caption": "Documentation: RFC 7159", + "command": "open_url", + "args": + { + "url": "https://datatracker.ietf.org/doc/html/rfc7159" + } + }, + { + "caption": "Documentation: ECMA 404", + "command": "open_url", + "args": + { + "url": "https://www.ecma-international.org/publications-and-standards/standards/ecma-404/" + } + } + ] + }, + { + "caption": "JSONC (JSON with Comments)", + "children": + [ + { + "caption": "Minify", + "command": "jsonc_minify" + }, + { + "caption": "Prettify", + "command": "jsonc_prettify" + } + ] + }, + { + "caption": "JSON5", + "children": + [ + { + "caption": "Documentation: Specs", + "command": "open_url", + "args": + { + "url": "https://spec.json5.org/#summary-of-features" + } + } + ] + }, + { "caption": "-" }, + { + "caption": "Support", + "children": + [ + { + "caption": "Changelog (Packages/JSON)", + "command": "open_url", + "args": + { + "url": "https://github.com/sublimehq/Packages/commits/master/JSON" + } + }, + { + "caption": "Report a (JSON package) issue", + "command": "open_url", + "args": + { + "url": "https://github.com/sublimehq/Packages/issues" + } + } + ] + } + ] + } + ] + } + ] + } +] diff --git a/JSON/Symbol List.tmPreferences b/JSON/Symbol List.tmPreferences new file mode 100644 index 00000000000..22c59c8cf92 --- /dev/null +++ b/JSON/Symbol List.tmPreferences @@ -0,0 +1,14 @@ + + + + scope + source.json meta.mapping.key - (meta.mapping.value meta.mapping.key | meta.sequence.list meta.mapping.key) + settings + + showInSymbolList + 1 + showInIndexedSymbolList + 1 + + + diff --git a/JSON/main.py b/JSON/main.py new file mode 100644 index 00000000000..8ddf5603bdb --- /dev/null +++ b/JSON/main.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +# coding: utf-8 + +# This file is being maintained at: +# https://github.com/sublimehq/Packages/blob/master/JSON/main.py + + +import sublime + +from .src import * + + +def plugin_loaded() -> None: + json_prettify.plugin_loaded() + + +def plugin_unloaded() -> None: + json_prettify.plugin_unloaded() diff --git a/JSON/src/__init__.py b/JSON/src/__init__.py new file mode 100644 index 00000000000..181339e8b50 --- /dev/null +++ b/JSON/src/__init__.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python +# coding: utf-8 + +# This file is being maintained at: +# https://github.com/sublimehq/Packages/blob/master/JSON/src/__init__.py + + +from .json_prettify import * +from .jsonc_prettify import * diff --git a/JSON/src/json_prettify.py b/JSON/src/json_prettify.py new file mode 100644 index 00000000000..87edd9af8e5 --- /dev/null +++ b/JSON/src/json_prettify.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python +# coding: utf-8 + +# This file is being maintained at: +# https://github.com/sublimehq/Packages/blob/master/JSON/src/json_prettify.py + + +import sublime +import sublime_plugin + +from __future__ import annotations +import collections +import decimal +import json +from typing import ( + Union +) + + +PKG_NAME: str = __package__.split('.')[0] +settings: Union[sublime.Settings, None] = None +base_settings: str = 'JSON.sublime-settings' +base_scope: str = 'source.json - (source.json.json-dotnet | source.json.json5 | source.json.jsonc)' + + +def status_msg(msg: str = '') -> None: + if msg == '': return + sublime.status_message(f'{PKG_NAME}: {msg}') + + +def print_msg(msg_header: str = '', msg_body: str = '') -> None: + if msg_body == '': return + print(f'JSON: {msg_header}:\n\n{msg_body}\n\n') + + +def json2py(view: sublime.View) -> sublime.Value: + old_contents: str = view.substr( + x=whole_view(view) + ) + try: + return json.loads( # https://docs.python.org/3.8/library/json.html#json.loads + s=old_contents, + object_pairs_hook=collections.OrderedDict, + parse_float=decimal.Decimal + ) + except Exception as e: + print_msg( + msg_header='Conversion failed due to error:', + msg_body=f'{e}' + ) + return None + + +def whole_view(view: sublime.View) -> sublime.Region: + return sublime.Region( + a=0, + b=view.size() + ) + + +def is_json(view: sublime.View) -> bool: + return view.match_selector( + pt=0, + selector=base_scope + ) + + +def plugin_loaded(reload: bool = False) -> None: + try: + global settings + settings = sublime.load_settings(base_name=base_settings) + settings.clear_on_change(tag='reload') + settings.add_on_change( + tag='reload', + callback=lambda: plugin_loaded(reload=True) + ) + except Exception as e: + print_msg( + msg_header=f'Loading "{base_settings}" failed due to error', + msg_body=f'{e}' + ) + + if reload: + status_msg('Reloaded settings on change.') + + +def plugin_unloaded() -> None: + global settings + settings = None + + +class JsonToggleAutoPrettify(sublime_plugin.WindowCommand): + + _is_checked: bool = False + _key: str = 'json.auto_prettify' + + def __init__(self, window: sublime.Window) -> None: + self.window: sublime.Window = window + + try: + if settings is None: + return + self._is_checked = settings.get(key=self._key, default=False) + except Exception: + pass + + def run(self) -> None: + try: + global settings + if settings is None: + return + if self._is_checked: + settings.erase(key=self._key) # remove the override (true) of the default (false) + else: + settings.set(key=self._key, value=True) + sublime.save_settings(base_name=base_settings) + self._is_checked = not self._is_checked # toggle + except Exception: + pass + + def is_checked(self) -> bool: + return self._is_checked + + +class JsonAutoPrettifyListener(sublime_plugin.EventListener): + + _key: str = 'json.auto_prettify' + + def on_pre_save_async(self, view) -> None: + if not is_json(view): + return + if settings is None: + return + if not settings.get(key=self._key, default=False): + return + view.run_command(cmd='json_prettify') + + +class JsonPrettify(sublime_plugin.TextCommand): + + def run(self, edit_token: sublime.Edit) -> None: + """ + Attempt to prettify the current view's JSON contents. Print errors to + the console when it fails. + """ + + try: + json_as_python: sublime.Value = json2py(self.view) + if json_as_python is None: return + self.view.replace( + edit_token, + r=whole_view(self.view), + text=json.dumps( # https://docs.python.org/3.8/library/json.html#json.dumps + obj=json_as_python, + allow_nan=False, + indent=4, + sort_keys=True + ) + ) + status_msg('Prettified.') + except Exception as e: + print_msg( + msg_header='Conversion failed due to error', + msg_body=f'{e}' + ) + status_msg('Prettifying failed. See console for details.') + pass + + def is_enabled(self) -> bool: + return is_json(self.view) + + def is_visible(self) -> bool: + return is_json(self.view) + + def description(self) -> str: + return 'Prettify JSON' + + +class JsonMinify(sublime_plugin.TextCommand): + + def run(self, edit_token: sublime.Edit) -> None: + """ + Attempt to minify the current view's JSON contents. Print errors to + the console when it fails. + """ + + try: + json_as_python: sublime.Value = json2py(self.view) + if json_as_python is None: return + self.view.replace( + edit_token, + r=whole_view(self.view), + text=json.dumps( # https://docs.python.org/3.8/library/json.html#json.dumps + obj=json_as_python, + allow_nan=False, + indent=None, + separators=(',', ':'), + sort_keys=True + ) + ) + status_msg('Minified.') + except Exception as e: + print_msg( + msg_header='Conversion failed due to error', + msg_body=f'{e}' + ) + status_msg('Minifying failed. See console for details.') + pass + + def is_enabled(self) -> bool: + return is_json(self.view) + + def is_visible(self) -> bool: + return is_json(self.view) + + def description(self) -> str: + return 'Minify JSON' diff --git a/JSON/src/jsonc_prettify.py b/JSON/src/jsonc_prettify.py new file mode 100644 index 00000000000..40a4a3c5b3d --- /dev/null +++ b/JSON/src/jsonc_prettify.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# coding: utf-8 + +# This file is being maintained at: +# https://github.com/sublimehq/Packages/blob/master/JSON/src/jsonc_prettify.py + + +import sublime +import sublime_plugin + +from __future__ import annotations +import json + + +PKG_NAME: str = __package__.split('.')[0] +base_scope: str = 'source.json.jsonc' + + +def status_msg(msg: str = '') -> None: + if msg == '': return + sublime.status_message(f'{PKG_NAME}: {msg}') + + +def print_msg(msg_header: str = '', msg_body: str = '') -> None: + if msg_body == '': return + print(f'JSONC: {msg_header}:\n\n{msg_body}\n\n') + + +def json2py(view: sublime.View) -> sublime.Value: + old_contents: str = view.substr( + x=whole_view(view) + ) + return sublime.decode_value( + data=old_contents + ) + + +def whole_view(view: sublime.View) -> sublime.Region: + return sublime.Region( + a=0, + b=view.size() + ) + + +def is_jsonc(view: sublime.View) -> bool: + return view.match_selector( + pt=0, + selector=base_scope + ) + + +class JsoncPrettify(sublime_plugin.TextCommand): + + def run(self, edit_token: sublime.Edit, auto: bool = False) -> None: + """ + Attempt to prettify the current view's JSONC contents. Print errors to + the console when it fails. + """ + + try: + if not auto and not sublime.ok_cancel_dialog( + msg='Prettifying JSONC will remove included comments and trailing commas.', + ok_title='Continue', + title='JSONC: Prettify' # only shown on Windows + ): + return + json_as_python: sublime.Value = json2py(self.view) + self.view.replace( + edit_token, + r=whole_view(self.view), + text=json.dumps( # https://docs.python.org/3.8/library/json.html#json.dumps + obj=json_as_python, + allow_nan=False, + indent=4, + sort_keys=True + ) + ) + status_msg('Prettified.') + except Exception as e: + print_msg( + msg_header='Conversion failed due to error', + msg_body=f'{e}' + ) + status_msg('Prettifying failed. See console for details.') + pass + + def is_enabled(self) -> bool: + return is_jsonc(self.view) + + def is_visible(self) -> bool: + return is_jsonc(self.view) + + def description(self) -> str: + return 'Prettify JSONC' + + +class JsoncMinify(sublime_plugin.TextCommand): + + def run(self, edit_token: sublime.Edit, auto: bool = False) -> None: + """ + Attempt to minify the current view's JSONC contents. Print errors to + the console when it fails. + """ + + try: + if not auto and not sublime.ok_cancel_dialog( + msg='Minifying JSONC will remove included comments and trailing commas.', + ok_title='Continue', + title='JSONC: Minify' # only shown on Windows + ): + return + json_as_python: sublime.Value = json2py(self.view) + self.view.replace( + edit_token, + r=whole_view(self.view), + text=json.dumps( # https://docs.python.org/3.8/library/json.html#json.dumps + obj=json_as_python, + allow_nan=False, + indent=None, + separators=(',', ':'), + sort_keys=True + ) + ) + status_msg('Minified.') + except Exception as e: + print_msg( + msg_header='Conversion failed due to error', + msg_body=f'{e}' + ) + status_msg('Minifying failed. See console for details.') + pass + + def is_enabled(self) -> bool: + return is_jsonc(self.view) + + def is_visible(self) -> bool: + return is_jsonc(self.view) + + def description(self) -> str: + return 'Minify JSONC' diff --git a/JSON/syntax_test_json.json b/JSON/syntax_test_json.json deleted file mode 100644 index ae0760eb3fb..00000000000 --- a/JSON/syntax_test_json.json +++ /dev/null @@ -1,123 +0,0 @@ -// SYNTAX TEST "Packages/JSON/JSON.sublime-syntax" - -{ -// <- meta.mapping.json punctuation.section.mapping.begin.json - "bool": false, -//^^^^^^ meta.mapping.key.json -//^^^^^^^^^^^^^^ - meta.mapping meta.mapping -// ^^^^^ constant.language.boolean.json - - "null": null, -//^^^^^^ meta.mapping.key.json -//^^^^^^^^^^^^^ - meta.mapping meta.mapping -// ^^^^ constant.language.null.json - - "dict": { "key": "value" } -// ^^^^^^^^^^^^^^^^^^ meta.mapping.value.json meta.mapping - meta.mapping meta.mapping meta.mapping -// ^ punctuation.section.mapping.begin.json -// ^ punctuation.section.mapping.end.json -// ^^ meta.mapping.value.json meta.mapping.json -// ^^^^^ meta.mapping.key.json string.quoted.double.json -// ^^ meta.mapping.value.json meta.mapping.json -// ^^^^^^^ meta.mapping.value.json meta.mapping.value.json string.quoted.double.json -// ^^ meta.mapping.value.json meta.mapping.json - -, , -// <- punctuation.separator.sequence.json -//^ invalid.illegal.expected-mapping-key.json - - "sep": {}, -// ^ punctuation.separator.key-value.json - - "array": [ /**/ ], -// ^^^^^^^^ meta.mapping.value.json meta.sequence.json -// ^ punctuation.section.sequence.begin.json -// ^^^^ comment.block.json -// ^ punctuation.section.sequence.end.json - - "dict": {"foo": }, -// ^ invalid.illegal.expected-mapping-value.json -// ^ punctuation.section.mapping.end.json - "dict": {"foo": - }, -//^ invalid.illegal.expected-mapping-value.json -// ^ punctuation.section.mapping.end.json - - "dict": {"foo"/*comment*/:/*comment*/"bar"/*comment*/}, -// ^^^^^^^^^^^ comment.block.json -// ^^^^^^^^^^^ comment.block.json -// ^^^^^^^^^^^ comment.block.json - - "dict": { - "foo": "bar" - // comment -// ^ - invalid -// ^^^^^^^^^^ comment.line.double-slash.js - , -// ^ punctuation.separator.sequence.json - "foo": "bar" - /* comment */ -// ^ - invalid -// ^^^^^^^^^^^^^ comment.block.json - }, -//^ punctuation.section.mapping.end.json -// ^ punctuation.separator.sequence.json - - "string": "string", -// ^ punctuation.definition.string.begin.json -// ^^^^^^^^ meta.mapping.value.json string.quoted.double.json -// ^ punctuation.definition.string.end.json - - "num": 20.09, -// ^^^^^ meta.number.float.decimal.json constant.numeric.value.json -// ^ punctuation.separator.decimal.json - - "neg": -9, -// ^^ meta.number.integer.decimal.json -// ^ keyword.operator.arithmetic.json -// ^ constant.numeric.value.json - - "E": 20e10, -// ^^^^^ meta.number.float.decimal.json constant.numeric.value.json -//^^^ meta.mapping.key.json string.quoted.double.json -// ^ punctuation.separator.key-value.json - meta.mapping.key - - "escape": "\n", -// ^^ constant.character.escape.json -// ^^^^ meta.mapping.value.json string.quoted.double.json - meta.mapping.key - - "illegal": "\.", -// ^^ invalid.illegal.unrecognized-string-escape.json - - "unterminated string -//^^^^^^^^^^^^^^^^^^^^ string.quoted.double.json -// ^ string.quoted.double.json invalid.illegal.unclosed-string.json - -// <- - string - -/**/: "test", -// ^ meta.mapping.json comment.block.json -// ^ punctuation.separator.key-value.json - comment -// ^^^^^^ meta.mapping.value.json string.quoted.double.json - - "array2": - [ - "foobar", -// ^^^^^^^^ meta.mapping.value meta.sequence.json string.quoted.double.json - meta.mapping.key - ] - - [], -//^ invalid.illegal.expected-mapping-separator.json -// ^^^ invalid.illegal.expected-mapping-key.json - - "typing json": {} - ,,,, "another key": false, - - "ke//y": "value" -//^^^^^^^ meta.mapping.key.json string.quoted.double.json - comment - -/** - * -// ^ meta.mapping.json comment.block.documentation.json punctuation.definition.comment.json -*/ -} diff --git a/Markdown/Markdown.sublime-syntax b/Markdown/Markdown.sublime-syntax index 64ee99ad7b7..fd47d68c828 100644 --- a/Markdown/Markdown.sublime-syntax +++ b/Markdown/Markdown.sublime-syntax @@ -910,7 +910,9 @@ contexts: - include: fenced-html - include: fenced-java - include: fenced-javascript + - include: fenced-json5 - include: fenced-jsonc + - include: fenced-json - include: fenced-jspx - include: fenced-jsx - include: fenced-lisp @@ -1258,11 +1260,49 @@ contexts: 0: meta.code-fence.definition.end.javascript.markdown-gfm 1: punctuation.definition.raw.code-fence.end.markdown + fenced-json5: + - match: |- + (?x) + {{fenced_code_block_start}} + ((?i:json5)) + {{fenced_code_block_trailing_infostring_characters}} + captures: + 0: meta.code-fence.definition.begin.json5.markdown-gfm + 2: punctuation.definition.raw.code-fence.begin.markdown + 5: constant.other.language-name.markdown + embed: scope:source.json.json5 + embed_scope: + markup.raw.code-fence.json5.markdown-gfm + source.json.json5 + escape: '{{fenced_code_block_escape}}' + escape_captures: + 0: meta.code-fence.definition.end.json5.markdown-gfm + 1: punctuation.definition.raw.code-fence.end.markdown + fenced-jsonc: - match: |- (?x) {{fenced_code_block_start}} - ((?i:jsonc?)) + ((?i:jsonc)) + {{fenced_code_block_trailing_infostring_characters}} + captures: + 0: meta.code-fence.definition.begin.jsonc.markdown-gfm + 2: punctuation.definition.raw.code-fence.begin.markdown + 5: constant.other.language-name.markdown + embed: scope:source.json.jsonc + embed_scope: + markup.raw.code-fence.jsonc.markdown-gfm + source.json.jsonc + escape: '{{fenced_code_block_escape}}' + escape_captures: + 0: meta.code-fence.definition.end.jsonc.markdown-gfm + 1: punctuation.definition.raw.code-fence.end.markdown + + fenced-json: + - match: |- + (?x) + {{fenced_code_block_start}} + ((?i:json)) {{fenced_code_block_trailing_infostring_characters}} captures: 0: meta.code-fence.definition.begin.json.markdown-gfm diff --git a/Markdown/tests/syntax_test_markdown.md b/Markdown/tests/syntax_test_markdown.md index d7e6ec89173..d9f6b9b9b52 100644 --- a/Markdown/tests/syntax_test_markdown.md +++ b/Markdown/tests/syntax_test_markdown.md @@ -1862,6 +1862,27 @@ for (var i = 0; i < 10; i++) { | <- meta.code-fence.definition.end.jsx.markdown-gfm punctuation.definition.raw.code-fence.end.markdown |^^ meta.code-fence.definition.end.jsx.markdown-gfm punctuation.definition.raw.code-fence.end.markdown +```json5 + +| <- markup.raw.code-fence.json5.markdown-gfm +``` +| <- meta.code-fence.definition.end.json5.markdown-gfm punctuation.definition.raw.code-fence.end.markdown +|^^ meta.code-fence.definition.end.json5.markdown-gfm punctuation.definition.raw.code-fence.end.markdown + +```jsonc + +| <- markup.raw.code-fence.jsonc.markdown-gfm +``` +| <- meta.code-fence.definition.end.jsonc.markdown-gfm punctuation.definition.raw.code-fence.end.markdown +|^^ meta.code-fence.definition.end.jsonc.markdown-gfm punctuation.definition.raw.code-fence.end.markdown + +```json + +| <- markup.raw.code-fence.json.markdown-gfm +``` +| <- meta.code-fence.definition.end.json.markdown-gfm punctuation.definition.raw.code-fence.end.markdown +|^^ meta.code-fence.definition.end.json.markdown-gfm punctuation.definition.raw.code-fence.end.markdown + ```lisp | <- markup.raw.code-fence.lisp.markdown-gfm source.lisp diff --git a/Perl/Perl.sublime-syntax b/Perl/Perl.sublime-syntax index 954cdeba3a4..c0fb678dab2 100644 --- a/Perl/Perl.sublime-syntax +++ b/Perl/Perl.sublime-syntax @@ -251,6 +251,18 @@ contexts: embed: scope:source.js embed_scope: source.js.embedded.perl escape: (?=^{{pod}}) + # embedded json5 + - match: \bjson5\b + scope: constant.other.language-name.json5.perl + embed: scope:source.json.json5 + embed_scope: source.json5.embedded.perl + escape: (?=^{{pod}}) + # embedded jsonc + - match: \bjsonc\b + scope: constant.other.language-name.jsonc.perl + embed: scope:source.json.jsonc + embed_scope: source.jsonc.embedded.perl + escape: (?=^{{pod}}) # embedded json - match: \bjson\b scope: constant.other.language-name.json.perl @@ -930,6 +942,22 @@ contexts: 3: entity.name.tag.heredoc.js.perl 4: punctuation.definition.tag.end.perl set: [string-heredoc-javascript, string-heredoc-expr] + # embedded json5 + - match: \s*((['"]?)(\s*JSON5)(\2)) + captures: + 1: meta.tag.heredoc.perl + 2: punctuation.definition.tag.begin.perl + 3: entity.name.tag.heredoc.json5.perl + 4: punctuation.definition.tag.end.perl + set: [string-heredoc-json5, string-heredoc-expr] + # embedded jsonc + - match: \s*((['"]?)(\s*JSONC)(\2)) + captures: + 1: meta.tag.heredoc.perl + 2: punctuation.definition.tag.begin.perl + 3: entity.name.tag.heredoc.jsonc.perl + 4: punctuation.definition.tag.end.perl + set: [string-heredoc-jsonc, string-heredoc-expr] # embedded json - match: \s*((['"]?)(\s*JSON)(\2)) captures: @@ -1013,6 +1041,24 @@ contexts: embed: scope:source.js escape: (?=^ *JAVASCRIPT$) + string-heredoc-json5: + - meta_content_scope: source.json5.embedded.perl + - match: ^\3$ + scope: meta.tag.heredoc.perl entity.name.tag.heredoc.json5.perl + pop: true + - match: '' + embed: scope:source.json.json5 + escape: (?=^ *JSON5$) + + string-heredoc-jsonc: + - meta_content_scope: source.jsonc.embedded.perl + - match: ^\3$ + scope: meta.tag.heredoc.perl entity.name.tag.heredoc.jsonc.perl + pop: true + - match: '' + embed: scope:source.json.jsonc + escape: (?=^ *JSONC$) + string-heredoc-json: - meta_content_scope: source.json.embedded.perl - match: ^\3$ diff --git a/Perl/syntax_test_perl.pl b/Perl/syntax_test_perl.pl index ba96ed7b8b3..44ea4a7e016 100644 --- a/Perl/syntax_test_perl.pl +++ b/Perl/syntax_test_perl.pl @@ -112,18 +112,38 @@ =head1 B<--param> # <- meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl #^^^ meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl +=begin json5 +# <- meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl +#^^^^^^^^^^ meta.comment.perl meta.interpolation.perl +#^^^^^ entity.name.tag.pod.perl +# ^ - constant - entity +# ^^^^ constant.other.language-name.json5.perl + +# <- meta.comment.perl meta.interpolation.perl source.json5.embedded.perl source.json.json5 +=end +# <- meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl +#^^^ meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl + +=begin jsonc +# <- meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl +#^^^^^^^^^^ meta.comment.perl meta.interpolation.perl +#^^^^^ entity.name.tag.pod.perl +# ^ - constant - entity +# ^^^^ constant.other.language-name.jsonc.perl + +# <- meta.comment.perl meta.interpolation.perl source.jsonc.embedded.perl source.json.jsonc +=end +# <- meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl +#^^^ meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl + =begin json # <- meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl #^^^^^^^^^^ meta.comment.perl meta.interpolation.perl #^^^^^ entity.name.tag.pod.perl # ^ - constant - entity # ^^^^ constant.other.language-name.json.perl - { -# ^ meta.comment.perl meta.interpolation.perl source.json.embedded.perl source.json - "key": "value", -# ^^^^^^^^^^^^^^^ meta.comment.perl meta.interpolation.perl source.json.embedded.perl source.json - } -# ^ meta.comment.perl meta.interpolation.perl source.json.embedded.perl source.json + +# <- meta.comment.perl meta.interpolation.perl source.json.embedded.perl source.json =end # <- meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl #^^^ meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl