Skip to content

Commit c4fe082

Browse files
Merge pull request #71 from bathos/html-recovery-tweaks
better handling of interpolated spans in html (addresses #70)
2 parents fedb7a7 + dbb7d45 commit c4fe082

2 files changed

Lines changed: 99 additions & 0 deletions

File tree

nested/build/base-packages/HTML/HTML.sublime-syntax

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,15 @@ contexts:
203203
scope: punctuation.definition.tag.end.html
204204
pop: true
205205
- include: tag-attributes
206+
- match: '(</?)(?=\${)'
207+
captures:
208+
'1': punctuation.definition.tag.begin.html
209+
push:
210+
- meta_scope: meta.tag.other.html
211+
- match: '(?: ?/)?>'
212+
scope: punctuation.definition.tag.end.html
213+
pop: true
214+
- include: tag-attributes
206215
- include: entities
207216
- match: <>
208217
scope: invalid.illegal.incomplete.html
@@ -259,6 +268,9 @@ contexts:
259268
scope: meta.attribute-with-value.html entity.other.attribute-name.html
260269
set:
261270
- meta_content_scope: meta.tag.style.begin.html meta.attribute-with-value.html
271+
- match: '=(?=\$\{)'
272+
scope: punctuation.separator.key-value.html
273+
pop: true
262274
- match: =
263275
scope: punctuation.separator.key-value.html
264276
set:
@@ -331,6 +343,9 @@ contexts:
331343
scope: meta.attribute-with-value.html entity.other.attribute-name.html
332344
set:
333345
- meta_content_scope: meta.tag.script.begin.html meta.attribute-with-value.html
346+
- match: '=(?=\$\{)'
347+
scope: punctuation.separator.key-value.html
348+
pop: true
334349
- match: =
335350
scope: punctuation.separator.key-value.html
336351
set:
@@ -399,6 +414,9 @@ contexts:
399414
- meta_scope: meta.attribute-with-value.html
400415
- include: immediately-pop
401416
tag-generic-attribute-equals:
417+
- match: '=(?=\$\{)'
418+
scope: punctuation.separator.key-value.html
419+
pop: true
402420
- match: =
403421
scope: punctuation.separator.key-value.html
404422
set: tag-generic-attribute-value
@@ -435,6 +453,9 @@ contexts:
435453
- meta_scope: meta.attribute-with-value.class.html
436454
- include: immediately-pop
437455
tag-class-attribute-equals:
456+
- match: '=(?=\$\{)'
457+
scope: punctuation.separator.key-value.html
458+
pop: true
438459
- match: =
439460
scope: punctuation.separator.key-value.html
440461
set: tag-class-attribute-value
@@ -473,6 +494,9 @@ contexts:
473494
- meta_scope: meta.attribute-with-value.id.html
474495
- include: immediately-pop
475496
tag-id-attribute-equals:
497+
- match: '=(?=\$\{)'
498+
scope: punctuation.separator.key-value.html
499+
pop: true
476500
- match: =
477501
scope: punctuation.separator.key-value.html
478502
set: tag-id-attribute-value
@@ -511,6 +535,9 @@ contexts:
511535
- meta_scope: meta.attribute-with-value.style.html
512536
- include: immediately-pop
513537
tag-style-attribute-equals:
538+
- match: '=(?=\$\{)'
539+
scope: punctuation.separator.key-value.html
540+
pop: true
514541
- match: =
515542
scope: punctuation.separator.key-value.html
516543
set: tag-style-attribute-value
@@ -553,6 +580,9 @@ contexts:
553580
- meta_scope: meta.attribute-with-value.event.html
554581
- include: immediately-pop
555582
tag-event-attribute-equals:
583+
- match: '=(?=\$\{)'
584+
scope: punctuation.separator.key-value.html
585+
pop: true
556586
- match: =
557587
scope: punctuation.separator.key-value.html
558588
set: tag-event-attribute-value

nested/src/syntax.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@ const fs = require('fs');
22
const yaml = require('js-yaml');
33
const jp = require('jsonpath');
44

5+
// -- rule for escaping interpolation element --
6+
const interp_escape_lookahead = () => ({
7+
// The first match here captures cases like this in ES tagged templates:
8+
//
9+
// <foo bar=${expression} baz=${expression}>
10+
//
11+
// If we did not treat this as a special case, ‘baz=’ would end up being seen
12+
// as an unquoted attribute value.
13+
//
14+
// Because there are various places where = is matched with special handling
15+
// for well-known attributes, this repeats a few times elsewhere.
16+
match: String.raw /* syntax: sublime-syntax.regex */ `=(?=\$\{)`,
17+
scope: 'punctuation.separator.key-value.html',
18+
pop: true,
19+
});
20+
521
// transforms for select syntaxes
622
const h_syntax_transforms = {
723
// the default markdown syntax embeds LOTS of contexts recursively.
@@ -19,6 +35,59 @@ const h_syntax_transforms = {
1935
},
2036
},
2137

38+
'text.html.basic': {
39+
'$.variables': (h_vars) => {
40+
h_vars.unquoted_attribute_value = String.raw /* syntax: sublime-syntax.regexp */ `(?:[^\s<>/''"]|/(?!>))+`;
41+
},
42+
43+
'$.contexts["style-type-attribute"][0].set': (a_rules) => {
44+
a_rules.splice(1, 0, interp_escape_lookahead());
45+
},
46+
47+
'$.contexts["script-type-attribute"][0].set': (a_rules) => {
48+
a_rules.splice(1, 0, interp_escape_lookahead());
49+
},
50+
51+
'$.contexts': (h_contexts) => {
52+
// each context
53+
for(let [si_context, a_rules] of Object.entries(h_contexts)) {
54+
// an attribute equals context
55+
if(si_context.endsWith('-attribute-equals')) {
56+
a_rules.unshift(interp_escape_lookahead());
57+
}
58+
}
59+
},
60+
61+
'$.contexts.main': (a_rules) => {
62+
a_rules.splice(-2, 0, {
63+
// Special case for handling ES tagged template where interpolation occurs in
64+
// tag name position:
65+
66+
// <${expression} attr=val>
67+
68+
// If we did not include this case, the ‘<’ would be scoped as ordinary
69+
// chardata.
70+
match: String.raw /* syntax: sublime-syntax.regexp */ `(</?)(?=\$\{)`,
71+
captures: {
72+
1: 'punctuation.definition.tag.begin.html',
73+
},
74+
push: [
75+
{
76+
meta_scope: 'meta.tag.other.html',
77+
},
78+
{
79+
match: `(?: ?/)?>`,
80+
scope: 'punctuation.definition.tag.end.html',
81+
pop: true,
82+
},
83+
{
84+
include: 'tag-attributes',
85+
},
86+
],
87+
});
88+
},
89+
},
90+
2291
// makes it nice and easy to code custom syntax injections
2392
'source.yaml.sublime.syntax': {
2493
'$.contexts.context_definition': (a_rules) => {

0 commit comments

Comments
 (0)