diff --git a/Embeddings/CSS (for Ngx).sublime-syntax b/Embeddings/CSS (for Ngx).sublime-syntax new file mode 100644 index 0000000..270c627 --- /dev/null +++ b/Embeddings/CSS (for Ngx).sublime-syntax @@ -0,0 +1,42 @@ +%YAML 1.2 +--- +# A special syntax definition to drive double quoted inline style attributes +# with {...} interpolation support +scope: source.css.embedded.ngx +version: 2 +hidden: true + +extends: Packages/CSS/CSS.sublime-syntax + +variables: + ident_start: (?:{{nmstart}}|{{) + +contexts: + + prototype: + - meta_prepend: true + - include: NgxHTML.sublime-syntax#ng-interpolations + + string-content: + - meta_prepend: true + - include: NgxHTML.sublime-syntax#ng-string-interpolations + + at-keyframe-block-body: + # required until ST4174 (PR #3820) + - meta_prepend: true + - meta_include_prototype: false + + at-layer-name-list: + # required until ST4174 (PR #3820) + - meta_prepend: true + - meta_include_prototype: false + + property-list-body: + # required until ST4174 (PR #3820) + - meta_prepend: true + - meta_include_prototype: false + + stylesheet-block-body: + # required until ST4174 (PR #3831) + - meta_prepend: true + - meta_include_prototype: false diff --git a/NgxHTML.sublime-syntax b/NgxHTML.sublime-syntax index 2fa7686..dd04854 100644 --- a/NgxHTML.sublime-syntax +++ b/NgxHTML.sublime-syntax @@ -14,6 +14,18 @@ contexts: ###[ HTML CUSTOMIZATIONS ]##################################################### + main: + - meta_prepend: true + - meta_scope: meta.template.ngx + + cdata-content: + - meta_prepend: true + - include: ng-string-interpolations + + strings-common-content: + - meta_prepend: true + - include: ng-string-interpolations + tag: - meta_prepend: true - include: ng-declarations @@ -24,6 +36,61 @@ contexts: - meta_prepend: true - include: ng-directives + tag-generic-attribute-name: + - meta_prepend: true + - include: ng-interpolations + + tag-attribute-value-content: + - meta_prepend: true + - include: ng-string-interpolations + +###[ HTML STYLE TAG ]########################################################## + + style-css-content: + - meta_include_prototype: false + - match: '{{style_content_begin}}' + captures: + 1: comment.block.html punctuation.definition.comment.begin.html + pop: 1 # make sure to match only once + embed: scope:source.css.embedded.ngx + embed_scope: source.css.embedded.html + escape: '{{style_content_end}}' + escape_captures: + 1: source.css.embedded.html + 2: comment.block.html punctuation.definition.comment.end.html + 3: source.css.embedded.html + 4: comment.block.html punctuation.definition.comment.end.html + +###[ HTML STYLE ATTRIBUTES ]################################################### + + tag-style-attribute-assignment: + - meta_include_prototype: false + - match: = + scope: punctuation.separator.key-value.html + set: + - immediately-pop # workaround https://github.com/sublimehq/sublime_text/issues/4069 + - tag-style-attribute-value + - include: else-pop + + tag-style-attribute-value: + - match: \" + scope: meta.string.html string.quoted.double.html punctuation.definition.string.begin.html + embed: scope:source.css.embedded.ngx#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 + pop: 1 + - match: \' + scope: meta.string.html string.quoted.single.html punctuation.definition.string.begin.html + embed: scope:source.css.embedded.ngx#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 + pop: 1 + - include: else-pop + ###[ ANGULAR DIRECTIVES ]###################################################### ng-directives: @@ -85,7 +152,7 @@ contexts: - match: \" scope: meta.string.ngx string.quoted.double.ngx punctuation.definition.string.begin.ngx embed: ng-directive-expressions - embed_scope: meta.directive.value.ngx meta.string.ngx meta.interpolation.ngx source.ngx.embedded.html + embed_scope: meta.directive.value.ngx meta.string.ngx meta.embedded.expression.ngx source.ngx.embedded.html escape: \" escape_captures: 0: meta.string.ngx string.quoted.double.ngx punctuation.definition.string.end.ngx @@ -93,7 +160,7 @@ contexts: - match: \' scope: meta.string.ngx string.quoted.single.ngx punctuation.definition.string.begin.ngx embed: ng-directive-expressions - embed_scope: meta.directive.value.ngx meta.string.ngx meta.interpolation.ngx source.ngx.embedded.html + embed_scope: meta.directive.value.ngx meta.string.ngx meta.embedded.expression.ngx source.ngx.embedded.html escape: \' escape_captures: 0: meta.string.ngx string.quoted.single.ngx punctuation.definition.string.end.ngx @@ -114,7 +181,9 @@ contexts: ng-declarations: - match: (@)let{{ident_break}} - scope: meta.let.ngx keyword.declaration.variable.ngx + scope: + meta.embedded.statement.ngx.html source.ngx.embedded.html + meta.let.ngx keyword.declaration.variable.ngx captures: 1: punctuation.definition.keyword.ngx push: @@ -128,15 +197,21 @@ contexts: - include: else-pop ng-let-assignment: - - meta_content_scope: meta.let.identifier.ngx + - meta_content_scope: + meta.embedded.statement.ngx.html source.ngx.embedded.html + meta.let.identifier.ngx - match: = - scope: meta.let.ngx keyword.operator.assignment.ngx + scope: + meta.embedded.statement.ngx.html source.ngx.embedded.html + meta.let.ngx keyword.operator.assignment.ngx set: ng-let-value - include: else-pop ng-let-value: - meta_include_prototype: false - - meta_content_scope: meta.let.value.ngx + - meta_content_scope: + meta.embedded.statement.ngx.html source.ngx.embedded.html + meta.let.value.ngx - match: ';' scope: punctuation.terminator.expression.ngx pop: 1 @@ -148,39 +223,51 @@ contexts: # conditionals # https://angular.dev/guide/templates/control-flow#conditionally-display-content-with-if-else-if-and-else - match: (@)if{{ident_break}} - scope: keyword.control.conditional.if.ngx + scope: + meta.embedded.statement.ngx.html source.ngx.embedded.html + keyword.control.conditional.if.ngx captures: 1: punctuation.definition.keyword.ngx push: - ng-block - ng-conditional-group - match: (@)else\s+if{{ident_break}} - scope: keyword.control.conditional.elseif.ngx + scope: + meta.embedded.statement.ngx.html source.ngx.embedded.html + keyword.control.conditional.elseif.ngx captures: 1: punctuation.definition.keyword.ngx push: - ng-block - ng-conditional-group - match: (@)else{{ident_break}} - scope: keyword.control.conditional.else.ngx + scope: + meta.embedded.statement.ngx.html source.ngx.embedded.html + keyword.control.conditional.else.ngx captures: 1: punctuation.definition.keyword.ngx push: ng-block # https://angular.dev/guide/templates/control-flow#conditionally-display-content-with-the-switch-block - match: (@)case{{ident_break}} - scope: keyword.control.conditional.case.ngx + scope: + meta.embedded.statement.ngx.html source.ngx.embedded.html + keyword.control.conditional.case.ngx captures: 1: punctuation.definition.keyword.ngx push: - ng-block - ng-conditional-group - match: (@)default{{ident_break}} - scope: keyword.control.conditional.case.ngx + scope: + meta.embedded.statement.ngx.html source.ngx.embedded.html + keyword.control.conditional.case.ngx captures: 1: punctuation.definition.keyword.ngx push: ng-block - match: (@)switch{{ident_break}} - scope: keyword.control.conditional.switch.ngx + scope: + meta.embedded.statement.ngx.html source.ngx.embedded.html + keyword.control.conditional.switch.ngx captures: 1: punctuation.definition.keyword.ngx push: @@ -188,20 +275,26 @@ contexts: - ng-conditional-group # https://angular.dev/guide/templates/control-flow#providing-a-fallback-for-for-blocks-with-the-empty-block - match: (@)for{{ident_break}} - scope: keyword.control.loop.for.ngx + scope: + meta.embedded.statement.ngx.html source.ngx.embedded.html + keyword.control.loop.for.ngx captures: 1: punctuation.definition.keyword.ngx push: - ng-block - ng-for-group - match: (@)empty{{ident_break}} - scope: keyword.control.loop.else.ngx + scope: + meta.embedded.statement.ngx.html source.ngx.embedded.html + keyword.control.loop.else.ngx captures: 1: punctuation.definition.keyword.ngx push: ng-block # https://angular.dev/guide/templates/defer - match: (@)(?:defer|error|loading|placeholder){{ident_break}} - scope: keyword.control.flow.ngx + scope: + meta.embedded.statement.ngx.html source.ngx.embedded.html + keyword.control.flow.ngx captures: 1: punctuation.definition.keyword.ngx push: @@ -210,6 +303,7 @@ contexts: ng-block: - meta_include_prototype: false + - meta_content_scope: meta.embedded.statement.ngx.html source.ngx.embedded.html - match: \{ scope: punctuation.section.block.begin.ngx set: ng-block-body @@ -295,16 +389,27 @@ contexts: ###[ ANGULAR INTERPOLATIONS ]################################################## + ng-string-interpolations: + - match: '{{' + scope: meta.embedded.expression.ngx.html punctuation.section.embedded.begin.ngx.html + push: ng-string-interpolation-body + + ng-string-interpolation-body: + - clear_scopes: 1 + - meta_include_prototype: false + - meta_content_scope: meta.embedded.expression.ngx.html source.ngx.embedded.html + - include: ng-interpolation-body + ng-interpolations: - match: '{{' - scope: meta.embedded.ngx.html punctuation.section.embedded.begin.ngx.html + scope: meta.embedded.expression.ngx.html punctuation.section.embedded.begin.ngx.html push: ng-interpolation-body ng-interpolation-body: - meta_include_prototype: false - - meta_content_scope: meta.embedded.ngx.html source.ngx.embedded.html + - meta_content_scope: meta.embedded.expression.ngx.html source.ngx.embedded.html - match: '}}' - scope: meta.embedded.ngx.html punctuation.section.embedded.end.ngx.html + scope: meta.embedded.expression.ngx.html punctuation.section.embedded.end.ngx.html pop: 1 - include: ng-expressions diff --git a/tests/syntax_test_scopes.component.html b/tests/syntax_test_scopes.component.html index 0449ccb..4cbefac 100644 --- a/tests/syntax_test_scopes.component.html +++ b/tests/syntax_test_scopes.component.html @@ -6,6 +6,8 @@ --> @let name = user.name; + + @@ -16,6 +18,7 @@ @let func = user.func(); + @@ -29,6 +32,7 @@ @let greeting = 'Hello, ' + name; + @@ -41,6 +45,7 @@ @let data = data$ | async; + @@ -53,6 +58,7 @@ @let item = var[10]['bar']; + @@ -71,6 +77,7 @@ @let path = .foo?.bar? ; + @@ -87,6 +94,7 @@ @let path = .orders.value()?.[0]?.$extra?.#currency.unit; + @@ -116,6 +124,7 @@ @let path = orders.value()?.[0]?.$extra?.#currency.unit; + @@ -149,9 +158,10 @@ --> @if (a > b) { - - - + + + + @@ -160,9 +170,9 @@ {{ a }} is greater than {{ b }} - - - + + + @@ -173,6 +183,7 @@ } @else if (b > a()) { + @@ -184,9 +195,9 @@ {{ a() }} is less than {{ b.c() }} - - - + + + @@ -202,13 +213,14 @@ } @else { - + + {{ a }} is equal to {{ b }} - - - + + + @@ -235,7 +247,7 @@ {{ startDate }} - + @@ -250,6 +262,8 @@ --> @switch (accessLevel) { + + @@ -257,7 +271,7 @@ @case ('admin') { - + @@ -277,7 +291,7 @@ @case { - + @@ -292,7 +306,7 @@ @default { - + @@ -311,6 +325,8 @@ --> @for (user of users; track user.id) { + + @@ -326,14 +342,16 @@ {{ user.name }} } @empty { - - + + + Empty list of users -} - +.html} + @for (item of items; track item.id; let idx = $index, e = $even) { + @@ -357,12 +375,12 @@ Item #{{ idx }}: {{ item.name }} - + - + @@ -370,9 +388,11 @@ } - + @if (users$ | async; as users) { + + @@ -390,7 +410,7 @@ - + @@ -402,7 +422,7 @@ } - + @defer { } + @@ -422,6 +443,7 @@ @defer (on viewport) { + @@ -433,18 +455,21 @@ } @loading { + Loading… } @error { + Loading failed :( } @placeholder { + @@ -454,6 +479,7 @@ @defer (on viewport; when $var prefetch on idle; prefetch when true) { + @@ -489,7 +515,7 @@ {{ "\xAF \u2AFF \n \"" }} - + @@ -534,7 +560,7 @@ {{ { name: 'Alice', 'object': { array + "name": [0, 2, 3] } } }} - + @@ -607,7 +633,7 @@ {{ foo ? bar : baz }} - + @@ -618,7 +644,7 @@ {{ foo = null ?? 'default' }} - + @@ -631,7 +657,7 @@ {{ person['name'][0] = "Mirabel" }} - + @@ -650,20 +676,20 @@ {{ obj?.member }} - - - - + + + + {{ obj.member [5] }} - - - - + + + + @@ -672,10 +698,10 @@ {{ obj.method() }} - - - - + + + + @@ -685,10 +711,10 @@ {{ orders.value()?.[0]?.$extra?.#currency }} - - - - + + + + @@ -709,7 +735,7 @@ {{ func(arg, "value") }} - + @@ -723,7 +749,7 @@ {{ var | filter | annimation ("forward") }} - + @@ -742,6 +768,102 @@ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + - + @@ -776,7 +898,7 @@ - + @@ -801,7 +923,7 @@ - + @@ -820,7 +942,7 @@ - + @@ -845,7 +967,7 @@ - + @@ -868,7 +990,7 @@ - + @@ -892,7 +1014,7 @@ - + @@ -916,7 +1038,7 @@ - + @@ -932,7 +1054,7 @@ - + @@ -949,7 +1071,7 @@ - + @@ -971,7 +1093,7 @@ - + @@ -987,7 +1109,7 @@ - + @@ -999,7 +1121,7 @@ - + @@ -1016,6 +1138,6 @@ - +