%YAML 1.2 --- name: HTML file_extensions: - html - htm - shtml - xhtml first_line_match: (?i)<(!DOCTYPE\s*)?html scope: text.html.basic variables: attribute_char: (?:[^ "'>/=\x00-\x1f\x7f-\x9f]) unquoted_attribute_value: (?:[^\s<>/''"]|/(?!>))+ not_equals_lookahead: (?=\s*[^\s=]) # https://html.spec.whatwg.org/multipage/parsing.html#tag-name-state tag_name: '[[:alpha:]_][^/>\s]*' 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 )\b 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 )\b form_tag_name: |- (?ix: button|datalist|input|label|legend|meter|optgroup|option|output|progress|select|template|textarea )\b 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 ) contexts: immediately-pop: - match: '' pop: true else-pop: - match: (?=\S) pop: true main: - include: comment - include: cdata - include: doctype - match: (<\?)(xml) captures: 1: punctuation.definition.tag.begin.html 2: entity.name.tag.xml.html push: - meta_scope: meta.tag.preprocessor.xml.html - match: '\?>' scope: punctuation.definition.tag.end.html pop: true - include: tag-generic-attribute - include: string-double-quoted - include: string-single-quoted - match: ( scope: invalid.illegal.incomplete.html 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 - match: ']]>' scope: invalid.illegal.missing-entity.html 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_value}})|'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: (?i)(?=(?:-->\s*)?' scope: punctuation.definition.tag.end.html set: - meta_content_scope: text.html.embedded.html - include: main - include: script-close-tag 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: )\s*)?() scope: meta.tag.script.end.html captures: 1: comment.block.html punctuation.definition.comment.end.html 2: punctuation.definition.tag.begin.html 3: entity.name.tag.script.html 4: punctuation.definition.tag.end.html pop: true script-common: - include: script-type-attribute - include: tag-attributes - include: tag-end-self-closing script-type-attribute: - match: (?i)\btype\b scope: meta.attribute-with-value.html entity.other.attribute-name.html set: - meta_content_scope: meta.tag.script.begin.html meta.attribute-with-value.html - match: = scope: punctuation.separator.key-value.html set: - meta_content_scope: meta.tag.script.begin.html meta.attribute-with-value.html - include: script-type-decider - match: (?=\S) set: script-javascript script-type-decider: - match: (?i)(?={{javascript_mime_type}}(?!{{unquoted_attribute_value}})|'{{javascript_mime_type}}'|"{{javascript_mime_type}}") set: - script-javascript - tag-generic-attribute-meta - tag-generic-attribute-value - match: (?i)(?=module(?!{{unquoted_attribute_value}})|'module'|"module") set: - script-javascript - tag-generic-attribute-meta - tag-generic-attribute-value - match: (?i)(?=>|''|"") set: - script-javascript - tag-generic-attribute-meta - tag-generic-attribute-value - match: (?i)(?=text/html(?!{{unquoted_attribute_value}})|'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_char}}) scope: entity.other.attribute-name.html push: - tag-generic-attribute-meta - tag-generic-attribute-equals - generic-attribute-name generic-attribute-name: - meta_scope: entity.other.attribute-name.html - match: (?!{{attribute_char}}) pop: true 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 - match: '{{not_equals_lookahead}}' pop: true 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_value}}' scope: string.unquoted.html pop: true - 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 - match: '{{not_equals_lookahead}}' pop: true 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: 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: entities - match: '{{unquoted_attribute_value}}' scope: string.unquoted.html meta.class-name.html pop: true - 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 - match: '{{not_equals_lookahead}}' pop: true 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: 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: entities - match: '{{unquoted_attribute_value}}' scope: string.unquoted.html meta.toc-list.id.html pop: true - 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 - match: '{{not_equals_lookahead}}' pop: true 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 - match: '{{not_equals_lookahead}}' pop: true 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-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