Skip to content

Commit

Permalink
Fix nested double quotes
Browse files Browse the repository at this point in the history
Twig tags within quoted strings can contain same sort of quotes.

This requires another strategy of handling embedded code blocks
especially in inline event and style attributes.

Solution is borrowed from PHP.
  • Loading branch information
deathaxe committed Oct 20, 2024
1 parent 5020129 commit af35fc3
Show file tree
Hide file tree
Showing 6 changed files with 219 additions and 24 deletions.
16 changes: 16 additions & 0 deletions Syntaxes/CSS/CSS (for HTML double-quoted).sublime-syntax
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
%YAML 1.2
---
scope: source.css.embedded.string.quoted.double.twig
version: 2
hidden: true

extends: CSS (Twig).sublime-syntax

contexts:
prototype:
- meta_prepend: true
- match: (?=")
pop: 1

main:
- include: rule-list-body
16 changes: 16 additions & 0 deletions Syntaxes/CSS/CSS (for HTML single-quoted).sublime-syntax
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
%YAML 1.2
---
scope: source.css.embedded.string.quoted.single.twig
version: 2
hidden: true

extends: CSS (Twig).sublime-syntax

contexts:
prototype:
- meta_prepend: true
- match: (?=')
pop: 1

main:
- include: rule-list-body
70 changes: 46 additions & 24 deletions Syntaxes/HTML/HTML (Twig).sublime-syntax
Original file line number Diff line number Diff line change
Expand Up @@ -122,39 +122,61 @@ contexts:
4: comment.block.html punctuation.definition.comment.end.html

tag-event-attribute-value:
- meta_include_prototype: false
- match: \"
scope: meta.string.html string.quoted.double.html punctuation.definition.string.begin.html
embed: scope:source.js.twig#expressions
embed_scope: meta.string.html source.js.embedded.html
escape: \"
escape_captures:
0: meta.string.html string.quoted.double.html punctuation.definition.string.end.html
scope: string.quoted.double.html punctuation.definition.string.begin.html
set: tag-event-attribute-value-double-quoted-body
- match: \'
scope: meta.string.html string.quoted.single.html punctuation.definition.string.begin.html
embed: scope:source.js.twig#expressions
embed_scope: meta.string.html source.js.embedded.html
escape: \'
escape_captures:
0: meta.string.html string.quoted.single.html punctuation.definition.string.end.html
scope: string.quoted.single.html punctuation.definition.string.begin.html
set: tag-event-attribute-value-single-quoted-body
- include: else-pop

tag-event-attribute-value-double-quoted-body:
- meta_include_prototype: false
- meta_scope: meta.string.html
- meta_content_scope: meta.interpolation.html source.js.embedded.html
- match: \"
scope: string.quoted.double.html punctuation.definition.string.end.html
pop: 1
- include: scope:source.js.embedded.string.quoted.double.twig

tag-event-attribute-value-single-quoted-body:
- meta_include_prototype: false
- meta_scope: meta.string.html
- meta_content_scope: meta.interpolation.html source.js.embedded.html
- match: \'
scope: string.quoted.single.html punctuation.definition.string.end.html
pop: 1
- include: scope:source.js.embedded.string.quoted.single.twig

tag-style-attribute-value:
- meta_include_prototype: false
- match: \"
scope: meta.string.html string.quoted.double.html punctuation.definition.string.begin.html
embed: scope:source.css.twig#rule-list-body
embed_scope: meta.string.html source.css.embedded.html
escape: \"
escape_captures:
0: meta.string.html string.quoted.double.html punctuation.definition.string.end.html
scope: string.quoted.double.html punctuation.definition.string.begin.html
set: tag-style-attribute-value-double-quoted-body
- match: \'
scope: meta.string.html string.quoted.single.html punctuation.definition.string.begin.html
embed: scope:source.css.twig#rule-list-body
embed_scope: meta.string.html source.css.embedded.html
escape: \'
escape_captures:
0: meta.string.html string.quoted.single.html punctuation.definition.string.end.html
scope: string.quoted.single.html punctuation.definition.string.begin.html
set: tag-style-attribute-value-single-quoted-body
- include: else-pop

tag-style-attribute-value-double-quoted-body:
- meta_include_prototype: false
- meta_scope: meta.string.html
- meta_content_scope: meta.interpolation.html source.css.embedded.html
- match: \"
scope: string.quoted.double.html punctuation.definition.string.end.html
pop: 1
- include: scope:source.css.embedded.string.quoted.double.twig

tag-style-attribute-value-single-quoted-body:
- meta_include_prototype: false
- meta_scope: meta.string.html
- meta_content_scope: meta.interpolation.html source.css.embedded.html
- match: \'
scope: string.quoted.single.html punctuation.definition.string.end.html
pop: 1
- include: scope:source.css.embedded.string.quoted.single.twig

tag-attribute-value-content:
- meta_prepend: true
- include: Text (Twig).sublime-syntax#interpolations
Expand Down
109 changes: 109 additions & 0 deletions Syntaxes/HTML/syntax_test_scopes.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -2330,3 +2330,112 @@
{# ^ meta.property-list.css meta.block.css - meta.property-value #}
{# ^ - meta.property-list - meta.block - meta.embedded #}
</style>

|==============================================================================
| Inline Events
|==============================================================================

<div
onclick="on{{ "function-#{name}" }}()"

Check failure on line 2339 in Syntaxes/HTML/syntax_test_scopes.html.twig

View workflow job for this annotation

GitHub Actions / Syntax Tests (4152)

[meta.string.html meta.interpolation.html source.js.embedded.html meta.function-call.arguments.js meta.group.js] does not match scope [text.html.twig meta.template.twig meta.tag.block.any.html meta.attribute-with-value.event.html meta.string.html meta.interpolation.html source.js.embedded.html meta.group.js punctuation.section.group.begin.js]

Check failure on line 2339 in Syntaxes/HTML/syntax_test_scopes.html.twig

View workflow job for this annotation

GitHub Actions / Syntax Tests (4152)

[meta.string.html meta.interpolation.html source.js.embedded.html meta.function-call.arguments.js meta.group.js] does not match scope [text.html.twig meta.template.twig meta.tag.block.any.html meta.attribute-with-value.event.html meta.string.html meta.interpolation.html source.js.embedded.html meta.group.js punctuation.section.group.end.js]
{# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.attribute-with-value.event.html #}
{# ^^^^^^^ entity.other.attribute-name.event.html #}
{# ^ punctuation.separator.key-value.html #}
{# ^ meta.string.html string.quoted.double.html punctuation.definition.string.begin.html #}
{# ^^ meta.string.html meta.interpolation.html source.js.embedded.html variable.other.readwrite.js #}
{# ^^ meta.string.html meta.interpolation.html source.js.embedded.html meta.embedded.expression.twig punctuation.section.embedded.begin.twig #}
{# ^ meta.string.html meta.interpolation.html source.js.embedded.html meta.embedded.expression.twig source.twig.embedded #}
{# ^^^^^^^^^^ meta.string.html meta.interpolation.html source.js.embedded.html meta.embedded.expression.twig source.twig.embedded meta.string.twig string.quoted.double.twig #}
{# ^^^^^^^ meta.string.html meta.interpolation.html source.js.embedded.html meta.embedded.expression.twig source.twig.embedded meta.string.twig meta.interpolation.twig #}
{# ^ meta.string.html meta.interpolation.html source.js.embedded.html meta.embedded.expression.twig source.twig.embedded meta.string.twig string.quoted.double.twig punctuation.definition.string.end.twig #}
{# ^ meta.string.html meta.interpolation.html source.js.embedded.html meta.embedded.expression.twig source.twig.embedded #}
{# ^^ meta.string.html meta.interpolation.html source.js.embedded.html meta.embedded.expression.twig punctuation.section.embedded.end.twig #}
{# ^^ meta.string.html meta.interpolation.html source.js.embedded.html meta.function-call.arguments.js meta.group.js #}
{# ^ meta.string.html string.quoted.double.html punctuation.definition.string.end.html #}

onclick='on{{ 'function-#{name}' }}()'

Check failure on line 2355 in Syntaxes/HTML/syntax_test_scopes.html.twig

View workflow job for this annotation

GitHub Actions / Syntax Tests (4152)

[meta.string.html meta.interpolation.html source.js.embedded.html meta.function-call.arguments.js meta.group.js] does not match scope [text.html.twig meta.template.twig meta.tag.block.any.html meta.attribute-with-value.event.html meta.string.html meta.interpolation.html source.js.embedded.html meta.group.js punctuation.section.group.begin.js]

Check failure on line 2355 in Syntaxes/HTML/syntax_test_scopes.html.twig

View workflow job for this annotation

GitHub Actions / Syntax Tests (4152)

[meta.string.html meta.interpolation.html source.js.embedded.html meta.function-call.arguments.js meta.group.js] does not match scope [text.html.twig meta.template.twig meta.tag.block.any.html meta.attribute-with-value.event.html meta.string.html meta.interpolation.html source.js.embedded.html meta.group.js punctuation.section.group.end.js]
{# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.attribute-with-value.event.html #}
{# ^^^^^^^ entity.other.attribute-name.event.html #}
{# ^ punctuation.separator.key-value.html #}
{# ^ meta.string.html string.quoted.single.html punctuation.definition.string.begin.html #}
{# ^^ meta.string.html meta.interpolation.html source.js.embedded.html variable.other.readwrite.js #}
{# ^^ meta.string.html meta.interpolation.html source.js.embedded.html meta.embedded.expression.twig punctuation.section.embedded.begin.twig #}
{# ^ meta.string.html meta.interpolation.html source.js.embedded.html meta.embedded.expression.twig source.twig.embedded #}
{# ^^^^^^^^^^^^^^^^^^ meta.string.html meta.interpolation.html source.js.embedded.html meta.embedded.expression.twig source.twig.embedded meta.string.twig string.quoted.single.twig #}
{# ^ meta.string.html meta.interpolation.html source.js.embedded.html meta.embedded.expression.twig source.twig.embedded #}
{# ^^ meta.string.html meta.interpolation.html source.js.embedded.html meta.embedded.expression.twig punctuation.section.embedded.end.twig #}
{# ^^ meta.string.html meta.interpolation.html source.js.embedded.html meta.function-call.arguments.js meta.group.js #}
{# ^ meta.string.html string.quoted.single.html punctuation.definition.string.end.html #}
>
{#^^^ meta.tag #}
{# ^ punctuation.definition.tag.end.html #}

|==============================================================================
| Inline Styles
|==============================================================================

<div
style='{{ 'color: \'#{value}\'' }}'
{# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.attribute-with-value.style.html #}
{# ^ meta.string.html string.quoted.single.html punctuation.definition.string.begin.html #}
{# ^^ meta.string.html meta.interpolation.html source.css.embedded.html meta.embedded.expression.twig punctuation.section.embedded.begin.twig #}
{# ^ meta.string.html meta.interpolation.html source.css.embedded.html meta.embedded.expression.twig source.twig.embedded #}
{# ^^^^^^^^^^^^^^^^^^^^^ meta.string.html meta.interpolation.html source.css.embedded.html meta.embedded.expression.twig source.twig.embedded meta.string.twig string.quoted.single.twig #}
{# ^ meta.string.html meta.interpolation.html source.css.embedded.html meta.embedded.expression.twig source.twig.embedded #}
{# ^^ meta.string.html meta.interpolation.html source.css.embedded.html meta.embedded.expression.twig punctuation.section.embedded.end.twig #}
{# ^ meta.string.html string.quoted.single.html punctuation.definition.string.end.html #}
{# ^ - meta.attribute-with-value #}

style="{{ "color: \"#{value}\"" }}"
{# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.attribute-with-value.style.html #}
{# ^ meta.string.html string.quoted.double.html punctuation.definition.string.begin.html #}
{# ^^ meta.string.html meta.interpolation.html source.css.embedded.html meta.embedded.expression.twig punctuation.section.embedded.begin.twig #}
{# ^ meta.string.html meta.interpolation.html source.css.embedded.html meta.embedded.expression.twig source.twig.embedded #}
{# ^^^^^^^^^^ meta.string.html meta.interpolation.html source.css.embedded.html meta.embedded.expression.twig source.twig.embedded meta.string.twig string.quoted.double.twig #}
{# ^^ constant.character.escape.twig #}
{# ^^^^^^^^ meta.string.html meta.interpolation.html source.css.embedded.html meta.embedded.expression.twig source.twig.embedded meta.string.twig meta.interpolation.twig #}
{# ^^ punctuation.section.interpolation.begin.twig #}
{# ^^^^^ variable.other.twig #}
{# ^ punctuation.section.interpolation.end.twig #}
{# ^^^ meta.string.html meta.interpolation.html source.css.embedded.html meta.embedded.expression.twig source.twig.embedded meta.string.twig string.quoted.double.twig #}
{# ^^ constant.character.escape.twig #}
{# ^ meta.string.html meta.interpolation.html source.css.embedded.html meta.embedded.expression.twig source.twig.embedded #}
{# ^^ meta.string.html meta.interpolation.html source.css.embedded.html meta.embedded.expression.twig punctuation.section.embedded.end.twig #}
{# ^ meta.string.html string.quoted.double.html punctuation.definition.string.end.html #}
{# ^ - meta.attribute-with-value #}

style="color-{{ "#{name}" }}: {{ "#{value}" }}"
{# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.attribute-with-value.style.html #}
{# ^^^^^ entity.other.attribute-name.style.html #}
{# ^ punctuation.separator.key-value.html #}
{# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.html #}
{# ^ string.quoted.double.html punctuation.definition.string.begin.html #}
{# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.interpolation.html source.css.embedded.html #}
{# ^^^^^^^^^^^^^^^^^^^^^ meta.property-name.css support.type.property-name.css #}
{# ^^^^^^^^^^^^^^^ meta.embedded.expression.twig #}
{# ^^ punctuation.section.embedded.begin.twig #}
{# ^^^^^^^^^^^ source.twig.embedded #}
{# ^^^^^^^^^ meta.string.twig #}
{# ^ string.quoted.double.twig punctuation.definition.string.begin.twig #}
{# ^^^^^^^ meta.interpolation.twig #}
{# ^^ punctuation.section.interpolation.begin.twig #}
{# ^^^^ meta.path.twig variable.other.twig #}
{# ^ punctuation.section.interpolation.end.twig #}
{# ^ string.quoted.double.twig punctuation.definition.string.end.twig #}
{# ^^ punctuation.section.embedded.end.twig #}
{# ^ punctuation.separator.key-value.css #}
{# ^^^^^^^^^^^^^^^^^ meta.property-value.css #}
{# ^^^^^^^^^^^^^^^^ meta.embedded.expression.twig #}
{# ^^ punctuation.section.embedded.begin.twig #}
{# ^^^^^^^^^^^^ source.twig.embedded #}
{# ^^^^^^^^^^ meta.string.twig #}
{# ^ string.quoted.double.twig punctuation.definition.string.begin.twig #}
{# ^^^^^^^^ meta.interpolation.twig #}
{# ^^ punctuation.section.interpolation.begin.twig #}
{# ^^^^^ meta.path.twig variable.other.twig #}
{# ^ punctuation.section.interpolation.end.twig #}
{# ^ string.quoted.double.twig punctuation.definition.string.end.twig #}
{# ^^ punctuation.section.embedded.end.twig #}
{# ^ string.quoted.double.html punctuation.definition.string.end.html #}
>
{#^^^ meta.tag #}
{# ^ punctuation.definition.tag.end.html #}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
%YAML 1.2
---
scope: source.js.embedded.string.quoted.double.twig
version: 2
hidden: true

extends: JavaScript (Twig).sublime-syntax

contexts:
prototype:
- meta_prepend: true
- match: (?=")
pop: 1

main:
- include: expressions
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
%YAML 1.2
---
scope: source.js.embedded.string.quoted.single.twig
version: 2
hidden: true

extends: JavaScript (Twig).sublime-syntax

contexts:
prototype:
- meta_prepend: true
- match: (?=')
pop: 1

main:
- include: expressions

0 comments on commit af35fc3

Please sign in to comment.