%YAML 1.2 --- name: HTML file_extensions: - html - htm - shtml - xhtml first_line_match: (?i)<(!DOCTYPE\s*)?html scope: text.html.basic variables: ascii_space: '\t\n\f ' # https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 attribute_name_char: '[{{ascii_space}}=/>]' attribute_name_start: (?=[^{{attribute_name_char}}]) attribute_name_break: (?={{attribute_name_char}}) # https://html.spec.whatwg.org/multipage/syntax.html#syntax-attribute-value unquoted_attribute_start: (?=[^{{ascii_space}}=>]) unquoted_attribute_break: (?=[{{ascii_space}}]|/?>) # https://html.spec.whatwg.org/multipage/parsing.html#tag-name-state tag_name_char: '[^{{ascii_space}}/<>]' tag_name_break: (?=[^{{tag_name_char}}]) tag_name: '[A-Za-z]{{tag_name_char}}*' block_tag_name: |- (?ix: address|applet|article|aside|blockquote|center|dd|dir|div|dl|dt|figcaption|figure|footer|frame|frameset|h1|h2|h3|h4|h5|h6|header|iframe|menu|nav|noframes|object|ol|p|pre|section|ul ){{tag_name_break}} inline_tag_name: |- (?ix: abbr|acronym|area|audio|b|base|basefont|bdi|bdo|big|br|canvas|caption|cite|code|del|details|dfn|dialog|em|font|head|html|i|img|ins|isindex|kbd|li|link|map|mark|menu|menuitem|meta|noscript|param|picture|q|rp|rt|rtc|ruby|s|samp|script|small|source|span|strike|strong|style|sub|summary|sup|time|title|track|tt|u|var|video|wbr ){{tag_name_break}} form_tag_name: |- (?ix: button|datalist|input|label|legend|meter|optgroup|option|output|progress|select|template|textarea ){{tag_name_break}} javascript_mime_type: |- (?ix: # https://mimesniff.spec.whatwg.org/#javascript-mime-type (?:application|text)/(?:x-)?(?:java|ecma)script | text/javascript1\.[0-5] | text/jscript | text/livescript ) custom_element_char: |- (?x: # https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-core-concepts [-_a-z0-9\x{00B7}] | \\\. | [\x{00C0}-\x{00D6}] | [\x{00D8}-\x{00F6}] | [\x{00F8}-\x{02FF}] | [\x{0300}-\x{037D}] | [\x{037F}-\x{1FFF}] | [\x{200C}-\x{200D}] | [\x{203F}-\x{2040}] | [\x{2070}-\x{218F}] | [\x{2C00}-\x{2FEF}] | [\x{3001}-\x{D7FF}] | [\x{F900}-\x{FDCF}] | [\x{FDF0}-\x{FFFD}] | [\x{10000}-\x{EFFFF}] ) script_close_lookahead: (?i:(?=(?:-->\s*)?' scope: punctuation.definition.tag.end.html pop: true - include: tag-generic-attribute - include: string-double-quoted - include: string-single-quoted - match: (<)((?i:style)){{tag_name_break}} captures: 0: meta.tag.style.begin.html 1: punctuation.definition.tag.begin.html 2: entity.name.tag.style.html push: style-css - match: '(<)((?i:script)){{tag_name_break}}' captures: 0: meta.tag.script.begin.html 1: punctuation.definition.tag.begin.html 2: entity.name.tag.script.html push: script-javascript - match: ( scope: invalid.illegal.incomplete.html tag-custom-name: - meta_content_scope: entity.name.tag.custom.html - match: '{{tag_name_break}}' pop: true - match: '{{custom_element_char}}+' # no scope - match: '{{tag_name_char}}' scope: invalid.illegal.custom-tag-name.html tag-custom-body: - meta_scope: meta.tag.custom.html - include: tag-end-maybe-self-closing - include: tag-attributes tag-other-name: - meta_content_scope: entity.name.tag.other.html - match: '{{tag_name_break}}' pop: true tag-other-body: - meta_scope: meta.tag.other.html - include: tag-end-maybe-self-closing - include: tag-attributes entities: - match: (&#[xX])\h+(;) scope: constant.character.entity.hexadecimal.html captures: 1: punctuation.definition.entity.html 2: punctuation.terminator.entity.html - match: (&#)[0-9]+(;) scope: constant.character.entity.decimal.html captures: 1: punctuation.definition.entity.html 2: punctuation.terminator.entity.html - match: (&)[a-zA-Z0-9]+(;) scope: constant.character.entity.named.html captures: 1: punctuation.definition.entity.html 2: punctuation.terminator.entity.html cdata: - match: (' scope: punctuation.definition.tag.end.html pop: true comment: - match: (' scope: invalid.illegal.bad-comments-or-CDATA.html doctype: - match: (' scope: punctuation.definition.tag.end.html pop: true doctype-name: - match: '{{tag_name}}' scope: constant.language.doctype.html pop: true - include: else-pop doctype-content-type: - match: (?:PUBLIC|SYSTEM)\b scope: keyword.content.external.html pop: true - include: else-pop doctype-content: - match: \[ scope: punctuation.section.brackets.begin.html set: - meta_scope: meta.brackets.html meta.internal-subset.xml.html - match: \] scope: punctuation.section.brackets.end.html pop: true - include: comment - include: string-double-quoted - include: string-single-quoted - include: else-pop style-css: - meta_content_scope: meta.tag.style.begin.html - include: style-common - match: '>' scope: punctuation.definition.tag.end.html set: - include: style-close-tag - match: (?=\S) embed: scope:source.css embed_scope: source.css.embedded.html escape: (?i)(?=(?:-->\s*)?' scope: punctuation.definition.tag.end.html set: - include: style-close-tag style-close-tag: - match: (?i)() scope: meta.tag.style.end.html captures: 1: punctuation.definition.tag.begin.html 2: entity.name.tag.style.html 3: punctuation.definition.tag.end.html pop: true style-common: - include: style-type-attribute - include: tag-attributes - include: tag-end-self-closing style-type-attribute: - match: (?i)\btype\b scope: meta.attribute-with-value.html entity.other.attribute-name.html set: - meta_content_scope: meta.tag.style.begin.html meta.attribute-with-value.html - match: = scope: punctuation.separator.key-value.html set: - meta_content_scope: meta.tag.style.begin.html meta.attribute-with-value.html - include: style-type-decider - match: (?=\S) set: style-css style-type-decider: - match: (?i)(?=text/css{{unquoted_attribute_break}}|'text/css'|"text/css") set: - style-css - tag-generic-attribute-meta - tag-generic-attribute-value - match: (?i)(?=>|''|"") set: - style-css - tag-generic-attribute-meta - tag-generic-attribute-value - match: (?=\S) set: - style-other - tag-generic-attribute-meta - tag-generic-attribute-value script-javascript: - meta_content_scope: meta.tag.script.begin.html - include: script-common - match: '>' scope: punctuation.definition.tag.end.html set: - include: script-close-tag - match: (?=\S) embed: scope:source.js embed_scope: source.js.embedded.html escape: '{{script_close_lookahead}}' script-html: - meta_content_scope: meta.tag.script.begin.html - include: script-common - match: '>' scope: punctuation.definition.tag.end.html set: - meta_content_scope: text.html.embedded.html - include: comment - include: script-close-tag - include: main script-other: - meta_content_scope: meta.tag.script.begin.html - include: script-common - match: '>' scope: punctuation.definition.tag.end.html set: - include: script-close-tag script-close-tag: - match: ' scope: comment.block.html punctuation.definition.comment.end.html - match: (?i:(|''|"") set: - script-javascript - tag-generic-attribute-meta - tag-generic-attribute-value - match: (?i)(?=text/html{{unquoted_attribute_break}}|'text/html'|"text/html") set: - script-html - tag-generic-attribute-meta - tag-generic-attribute-value - match: (?=\S) set: - script-other - tag-generic-attribute-meta - tag-generic-attribute-value string-double-quoted: - match: '"' scope: punctuation.definition.string.begin.html push: - meta_scope: string.quoted.double.html - match: '"' scope: punctuation.definition.string.end.html pop: true - include: entities string-single-quoted: - match: "'" scope: punctuation.definition.string.begin.html push: - meta_scope: string.quoted.single.html - match: "'" scope: punctuation.definition.string.end.html pop: true - include: entities tag-generic-attribute: - match: '{{attribute_name_start}}' push: - tag-generic-attribute-meta - tag-generic-attribute-equals - tag-generic-attribute-name tag-generic-attribute-name: - meta_scope: entity.other.attribute-name.html - match: '{{attribute_name_break}}' pop: true - match: '["''`<]' scope: invalid.illegal.attribute-name.html tag-generic-attribute-meta: - meta_scope: meta.attribute-with-value.html - include: immediately-pop tag-generic-attribute-equals: - match: '=' scope: punctuation.separator.key-value.html set: tag-generic-attribute-value - include: else-pop tag-generic-attribute-value: - match: '"' scope: punctuation.definition.string.begin.html set: - meta_scope: string.quoted.double.html - match: '"' scope: punctuation.definition.string.end.html pop: true - include: entities - match: "'" scope: punctuation.definition.string.begin.html set: - meta_scope: string.quoted.single.html - match: "'" scope: punctuation.definition.string.end.html pop: true - include: entities - match: '{{unquoted_attribute_start}}' set: - meta_scope: string.unquoted.html - match: '{{unquoted_attribute_break}}' pop: true - match: '["''`<]' scope: invalid.illegal.attribute-value.html - include: entities - include: else-pop tag-class-attribute: - match: '\bclass\b' scope: entity.other.attribute-name.class.html push: - tag-class-attribute-meta - tag-class-attribute-equals tag-class-attribute-meta: - meta_scope: meta.attribute-with-value.class.html - include: immediately-pop tag-class-attribute-equals: - match: '=' scope: punctuation.separator.key-value.html set: tag-class-attribute-value - include: else-pop tag-class-attribute-value: - match: '"' scope: punctuation.definition.string.begin.html set: - meta_scope: string.quoted.double.html - meta_content_scope: meta.class-name.html - match: '"' scope: punctuation.definition.string.end.html pop: true - include: tag-attribute-value-separator - include: entities - match: "'" scope: punctuation.definition.string.begin.html set: - meta_scope: string.quoted.single.html - meta_content_scope: meta.class-name.html - match: "'" scope: punctuation.definition.string.end.html pop: true - include: tag-attribute-value-separator - include: entities - match: '{{unquoted_attribute_start}}' set: - meta_scope: string.unquoted.html meta.class-name.html - match: '{{unquoted_attribute_break}}' pop: true - match: '["''`<]' scope: invalid.illegal.attribute-value.html - include: entities - include: else-pop tag-id-attribute: - match: '\bid\b' scope: entity.other.attribute-name.id.html push: - tag-id-attribute-meta - tag-id-attribute-equals tag-id-attribute-meta: - meta_scope: meta.attribute-with-value.id.html - include: immediately-pop tag-id-attribute-equals: - match: '=' scope: punctuation.separator.key-value.html set: tag-id-attribute-value - include: else-pop tag-id-attribute-value: - match: '"' scope: punctuation.definition.string.begin.html set: - meta_scope: string.quoted.double.html - meta_content_scope: meta.toc-list.id.html - match: '"' scope: punctuation.definition.string.end.html pop: true - include: tag-attribute-value-separator - include: entities - match: "'" scope: punctuation.definition.string.begin.html set: - meta_scope: string.quoted.single.html - meta_content_scope: meta.toc-list.id.html - match: "'" scope: punctuation.definition.string.end.html pop: true - include: tag-attribute-value-separator - include: entities - match: '{{unquoted_attribute_start}}' set: - meta_scope: string.unquoted.html meta.toc-list.id.html - match: '{{unquoted_attribute_break}}' pop: true - match: '["''`<]' scope: invalid.illegal.attribute-value.html - include: entities - include: else-pop tag-style-attribute: - match: '\bstyle\b' scope: entity.other.attribute-name.style.html push: - tag-style-attribute-meta - tag-style-attribute-equals tag-style-attribute-meta: - meta_scope: meta.attribute-with-value.style.html - include: immediately-pop tag-style-attribute-equals: - match: '=' scope: punctuation.separator.key-value.html set: tag-style-attribute-value - include: else-pop tag-style-attribute-value: - match: '"' scope: string.quoted.double punctuation.definition.string.begin.html embed: scope:source.css#rule-list-body embed_scope: source.css escape: '"' escape_captures: 0: string.quoted.double punctuation.definition.string.end.html - match: "'" scope: string.quoted.single punctuation.definition.string.begin.html embed: scope:source.css#rule-list-body embed_scope: source.css escape: "'" escape_captures: 0: string.quoted.single punctuation.definition.string.end.html - include: else-pop tag-event-attribute: - match: |- (?x)\bon( abort|autocomplete|autocompleteerror|auxclick|blur|cancel|canplay |canplaythrough|change|click|close|contextmenu|cuechange|dblclick|drag |dragend|dragenter|dragexit|dragleave|dragover|dragstart|drop |durationchange|emptied|ended|error|focus|input|invalid|keydown |keypress|keyup|load|loadeddata|loadedmetadata|loadstart|mousedown |mouseenter|mouseleave|mousemove|mouseout|mouseover|mouseup|mousewheel |pause|play|playing|progress|ratechange|reset|resize|scroll|seeked |seeking|select|show|sort|stalled|submit|suspend|timeupdate|toggle |volumechange|waiting )\b scope: entity.other.attribute-name.event.html push: - tag-event-attribute-meta - tag-event-attribute-equals tag-event-attribute-meta: - meta_scope: meta.attribute-with-value.event.html - include: immediately-pop tag-event-attribute-equals: - match: '=' scope: punctuation.separator.key-value.html set: tag-event-attribute-value - include: else-pop tag-event-attribute-value: - match: '"' scope: string.quoted.double punctuation.definition.string.begin.html embed: scope:source.js embed_scope: meta.attribute-with-value.event.html escape: '"' escape_captures: 0: string.quoted.double punctuation.definition.string.end.html - match: "'" scope: string.quoted.single punctuation.definition.string.begin.html meta.attribute-with-value.event.html embed: scope:source.js embed_scope: meta.attribute-with-value.event.html escape: "'" escape_captures: 0: string.quoted.single punctuation.definition.string.end.html - include: else-pop # This is to prevent breaking syntaxes referencing the old context name tag-stuff: - include: tag-attributes tag-attributes: - include: tag-id-attribute - include: tag-class-attribute - include: tag-style-attribute - include: tag-event-attribute - include: tag-generic-attribute tag-attribute-value-separator: - match: (?=[{{ascii_space}}]) push: - clear_scopes: 1 # clear `meta.class-name` or `meta.toc-list.id` - include: else-pop tag-end: - match: '>' scope: punctuation.definition.tag.end.html pop: true tag-end-self-closing: - match: '/>' scope: punctuation.definition.tag.end.html pop: true tag-end-maybe-self-closing: - match: '/?>' scope: punctuation.definition.tag.end.html pop: true