28 | # or any char that doesn't start string, comment or ending brace
29 | | [^"'`/\]]
30 | )*
31 | )
32 | # stop matching at EOL or comment
33 | ($|/[/*])
34 |
35 | decreaseIndentPattern: >-
36 | (?x)
37 | (
38 | ^ (
39 | # consume double-quoted string or single-quoted string
40 | "(?:[^"\\]|\\.)*" | '(?:[^'\\]|\\.)*'
41 | # or any char that doesn't start string, comment or opening indentation char on line
42 | | [^"'`/\{\(\[\n]
43 | )*
44 | # followed by any one of the indentation chars
45 | (
46 | \} [^\{]* |
47 | \) [^\(]* |
48 | \] [^\[]*
49 | )
50 | )$
51 |
52 | bracketIndentNextLinePattern: >-
53 | (?x)
54 | \b(
55 | ( do | else ) \s* |
56 | ( if | while | for ) \b .* \( .* \) [^;]*
57 | )$
--------------------------------------------------------------------------------
/ecmascript-indent.tmPreferences:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | name
6 | Indent
7 | scope
8 | source.es
9 | settings
10 |
11 | bracketIndentNextLinePattern
12 | (?x)
13 | \b(
14 | ( do | else ) \s* |
15 | ( if | while | for ) \b .* \( .* \) [^;]*
16 | )$
17 | decreaseIndentPattern
18 | (?x)
19 | (
20 | ^ (
21 | # consume double-quoted string or single-quoted string
22 | "(?:[^"\\]|\\.)*" | '(?:[^'\\]|\\.)*'
23 | # or any char that doesn't start string, comment or opening indentation char on line
24 | | [^"'`/\{\(\[\n]
25 | )*
26 | # followed by any one of the indentation chars
27 | (
28 | \} [^\{]* |
29 | \) [^\(]* |
30 | \] [^\[]*
31 | )
32 | )$
33 | increaseIndentPattern
34 | (?x)
35 | ^.* (
36 | # braces
37 | \{ (
38 | # consume double-quoted string or single-quoted string
39 | (?<string>"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')
40 | # or any char that doesn't start string, comment or ending brace
41 | | [^"'`/\}]
42 | )*
43 | # parens
44 | | \( (
45 | # consume double-quoted string or single-quoted string
46 | \k<string>
47 | # or any char that doesn't start string, comment or ending brace
48 | | [^"'`/\)]
49 | )*
50 | # brackets
51 | | \[ (
52 | # consume double-quoted string or single-quoted string
53 | \k<string>
54 | # or any char that doesn't start string, comment or ending brace
55 | | [^"'`/\]]
56 | )*
57 | )
58 | # stop matching at EOL or comment
59 | ($|/[/*])
60 |
61 | uuid
62 | 54754702-a030-4b65-af1b-45759e122b28
63 |
64 |
65 |
--------------------------------------------------------------------------------
/nested/build/base-packages/HTML/Miscellaneous.tmPreferences:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | name
5 | Miscellaneous
6 | scope
7 | text.html
8 | settings
9 |
10 | decreaseIndentPattern
11 | ]*+(?!html)[A-Za-z0-9-]+\b[^>]*> # optionally, anything that's not an angle bracket, followed by any valid HTML close tag except "html"
15 | | ( # closing comment punctuation, optionally preceded by an end "comment selector"
16 | | \} # a closing curly brace
17 | )
18 | ]]>
19 | increaseIndentPattern
20 | ) # comments that don't close themselves on the same line
25 | | .*<(?!\?|(?i:area|base|br|col|frame|hr|html|img|input|link|meta|param)\b|[^>]*/>) # skip self closing tags (tags that end with />, as well as known self closing tags)
26 | (?[A-Za-z0-9-]+)(?=\s|>)\b[^>]*>(?!.*\k\s*>) # a valid non-self-closing HTML tag that doesn't close itself on the same line
27 | )
28 | ]]>
29 | bracketIndentNextLinePattern
30 | )]]>
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Default.sublime-keymap:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "keys": ["enter"],
4 | "command": "insert_snippet",
5 | "args": {
6 | "contents": "\n\t$0\n"
7 | },
8 | "context": [
9 | {
10 | "key": "setting.auto_indent",
11 | "operator": "equal",
12 | "operand": true
13 | },
14 | {
15 | "key": "auto_complete_visible",
16 | "operator": "equal",
17 | "operand": false
18 | },
19 | {
20 | "key": "selection_empty",
21 | "operator": "equal",
22 | "operand": true,
23 | "match_all": true,
24 | },
25 | {
26 | "key": "preceding_text",
27 | "operator": "regex_contains",
28 | "operand": "[([`]$"
29 | },
30 | {
31 | "key": "following_text",
32 | "operator": "regex_contains",
33 | "operand": "^[)\\]`]",
34 | },
35 | {
36 | "key": "selector",
37 | "operator": "equal",
38 | "operand": "source.es & (meta.brace.square.js | meta.brace.round.js | string.interpolated.es)",
39 | "match_all": true,
40 | }
41 | ]
42 | },
43 | {
44 | "keys": ["primary+'"],
45 | "command": "toggle_nested_syntax",
46 | "args": {},
47 | "context": [
48 | {
49 | "key": "auto_complete_visible",
50 | "operator": "equal",
51 | "operand": false
52 | },
53 | {
54 | "key": "selector",
55 | "operator": "equal",
56 | "operand": "source.es & (string.interpolated.es | meta.interpolation.syntax)",
57 | "match_all": true,
58 | },
59 | {
60 | "key": "num_selections",
61 | "operator": "equal",
62 | "operand": 1
63 | },
64 | ]
65 | },
66 | {
67 | "keys": ["primary+'"],
68 | "command": "insert_nested_syntax",
69 | "args": {},
70 | "context": [
71 | {
72 | "key": "auto_complete_visible",
73 | "operator": "equal",
74 | "operand": false
75 | },
76 | {
77 | "key": "selector",
78 | "operator": "equal",
79 | "operand": "source.es & (meta.whitespace.es | punctuation.definition.arguments.end.es | punctuation.definition.array.end.es | invalid.illegal.token.es) - string.interpolated.es - meta.interpolation.syntax",
80 | "match_all": true,
81 | },
82 | {
83 | "key": "selection_empty",
84 | "operator": "equal",
85 | "operand": true,
86 | "match_all": true,
87 | }
88 | ]
89 | }
90 | ]
--------------------------------------------------------------------------------
/examples/nested-syntax-highlighting.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | /* syntax: bash */ `
4 | node $SCRIPT | grep '${find? find: '.'}' > out.txt 2>&1 \\
5 | && cat out.txt
6 | `;
7 |
8 | /* syntax: css */ `
9 | .window {
10 | color: rgba(231, 76, 60, ${transparency});
11 | }
12 | `;
13 |
14 | /* syntax: css.style */ `font-size: ${size}pt`;
15 |
16 | /* syntax: dot */ `
17 | digraph graph_name {
18 | a [label="apple"];
19 | b [label="${fruit.label}"]
20 | a -> b [color="${edge.color}"];
21 | }
22 | `;
23 |
24 | /* syntax: js */ `
25 | class example extends ${super_class} {
26 | constructor(input) {
27 | super(input+'\n');
28 | }
29 |
30 | get ${property}() {
31 | return this._${property}.toString();
32 | }
33 | }
34 | `;
35 |
36 | /* syntax: js.object-literal */ `
37 | color: 'yellow',
38 | taste: ${flavor},
39 | organic: true,
40 | `;
41 |
42 | /* syntax: js.value */ `.toString()`;
43 |
44 | /* syntax: js.method */ `
45 | anonymous() {
46 | return true;
47 | }
48 | `;
49 |
50 | new Regexp(/* syntax: js.regexp */ `(a+b[a-c]){2}`);
51 |
52 | /* syntax: json */ `
53 | {
54 | "name": "douglas",
55 | "score": 42,
56 | "info": ${JSON.stringify(info)}
57 | }
58 | `;
59 |
60 | /* syntax: lua */ `
61 | local function cleanup()
62 | for i, v in ipairs(${handler}) do
63 | pcall(v)
64 | end
65 |
66 | table.insert(${handler}, f)
67 | end
68 | `;
69 |
70 | // Requires a GLSL language, such as the "OpenGL Shading Language (GLSL)" plugin
71 | /* syntax: glsl */ `
72 | uniform float time;
73 | void main() {
74 | gl_FragColor = vec4((time % ${span}) / ${span});
75 | }
76 | `;
77 |
78 | /* syntax: html */ `
79 |
84 |
85 |
86 | content
87 |
88 |
89 |
97 | `;
98 |
99 | /* syntax: md */ `
100 | # README
101 |
102 | List of **${category} items** to buy:
103 | ${items.map(s => ` - ${s}`).join('\n')}
104 |
105 | > Notice: ${notice_message}
106 |
107 | ~~~js
108 | All code-fenced blocks in nested markdown are neutered
109 | ~~~
110 | `;
111 |
112 | /* syntax: sql */ `
113 | select * from ${table}
114 | where ${conditions.join(' and ')}
115 | `;
116 |
117 | /* syntax: xml */ `
118 |
119 | Ethereum
120 |
121 | `;
122 |
123 | /* syntax: yaml */ `
124 | env: development
125 | - label: ${this.label}
126 | - debug: true
127 | `;
128 |
--------------------------------------------------------------------------------
/nested/src/test/interp.js:
--------------------------------------------------------------------------------
1 | const mods = s_label => [
2 | `\${${s_label}}`,
3 | `pre_\${${s_label}}`,
4 | `\${${s_label}}_post`,
5 | `pre_\${${s_label}}_post`,
6 | `pre_\${${s_label}}_mid_\${mod}_post`,
7 | ];
8 |
9 | const gobble = (s_text, s_indent='') => {
10 | let m_pad = /^(\s+)/.exec(s_text.replace(/^([ \t]*\n)/, ''));
11 | if(m_pad) {
12 | return s_indent+s_text.replace(new RegExp(`\\n${m_pad[1]}`, 'g'), '\n'+s_indent.trim()).trim();
13 | }
14 | else {
15 | return s_indent+s_text.trim();
16 | }
17 | };
18 |
19 | const r_interp = /\$\{[^}]+}/g;
20 |
21 | function* permutate(s_label, f_texts) {
22 | let a_mods = mods(s_label);
23 | for(let s_mod of a_mods) {
24 | let a_texts = f_texts(s_mod, (s_mark, s_scopes) => {
25 | let s_pad = s_mark.replace(/^[\n\t]+\/\//, '').slice(0, -1);
26 | let a_parts = [];
27 | let i_prev = 0;
28 | for(let m_interp=r_interp.exec(s_mod); null!==m_interp; m_interp=r_interp.exec(s_mod)) {
29 | if(m_interp.index) a_parts.push(`${' '.repeat(i_prev)}^ ${s_scopes}`);
30 |
31 | let i_interp = m_interp.index;
32 | a_parts.push(...[
33 | `${' '.repeat(i_interp)}^ punctuation.definition.string.interpolated.element.begin.es`,
34 | `${' '.repeat(i_interp+2)}^ meta.interpolation.interpolated.es variable.other.readwrite.es`,
35 | ]);
36 |
37 | i_prev = m_interp.index+m_interp[0].length;
38 | }
39 |
40 | if(i_prev < s_mod.length) a_parts.push(`${' '.repeat(i_prev)}^ ${s_scopes}`);
41 |
42 | return a_parts.map(s => `//${s_pad}${s}`).join('\n');
43 | });
44 |
45 | for(let s_text of a_texts) {
46 | yield s_text.replace(/\n\t+/g, '\n').replace(/^\n/, '');
47 | }
48 | }
49 | }
50 |
51 |
52 | let s_out = [
53 | 'class test_method_signatures {',
54 | ...permutate('method', (s, ids) => [
55 | ...['get', 'set'].map(s_type => `
56 | ${s_type} ${s}() {}
57 | // ^ storage.type.accessor.js storage.modifier.accessor.${s_type}.es
58 | ${ids(`
59 | // ^`, `entity.name.method.js entity.name.accessor.${s_type}.es`)}
60 | `),
61 | `
62 | static ${s}() {}
63 | // ^ storage.modifier.static.es storage.type.js
64 | // ^ entity.name.method.js entity.name.method.static.es
65 | ${ids(`
66 | // ^`, `entity.name.method.js entity.name.method.async.es`)}
67 | `,
68 | `
69 | * ${s}() {}
70 | // ^ keyword.generator.asterisk.js storage.modifier.generator.asterisk.method.es
71 | ${ids(`
72 | // ^`, `entity.name.method.js entity.name.method.generator.es`)}
73 | `,
74 | `
75 | async ${s}() {}
76 | // ^ storage.modifier.async.method.es
77 | // ^ keyword.generator.asterisk.js storage.modifier.generator.asterisk.method.es
78 | ${ids(`
79 | // ^`, `entity.name.method.js entity.name.method.async.es`)}
80 | `,
81 | `
82 | async* ${s}() {}
83 | // ^ storage.modifier.async.method.es
84 | // ^ keyword.generator.asterisk.js storage.modifier.generator.asterisk.method.es
85 | ${ids(`
86 | // ^`, `entity.name.method.js entity.name.method.async.es`)}
87 | `,
88 | ]),
89 | '}',
90 | ].join('\n');
91 |
92 | process.stdout.write(`// SYNTAX TEST "Packages/User/ecmascript-sublime/ecmascript.sublime-syntax"
93 | /* eslint-disable */
94 |
95 | /* syntax: js */ \`
96 | ${s_out}
97 | \`;
98 | `);
99 |
--------------------------------------------------------------------------------
/nested/build/package-dev/Package/Sublime Text Syntax Definition/Oniguruma RegExp Indentation Rules.tmPreferences:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | scope
6 | (source.regexp, source.yaml.sublime.syntax.nested.es meta.expect-regexp) - comment
7 | settings
8 |
9 | comment
10 |
11 | Indent any unclosed groups
12 | (open paren that doesn't have a corresponding closing paren on the same line).
13 |
14 | Unindent when a closing paren is the first non-whitespace character on a line.
15 |
16 | Also apply to the `expect-regexp` meta scope,
17 | because otherwise a line like `- match: (?=\))` in a `.sublime-syntax` file
18 | would not have these rules applied to it
19 | because the `source.regexp` scope (correctly) doesn't cover the newline.
20 |
21 | Parens inside comments (whether YAML or Regex) are ignored.
22 |
23 | indentParens
24 |
25 | increaseIndentPattern
26 |
29 | [^\\()]++ # anything that isn't a slash or a paren
30 | | \\(?> # this is the "known_char_escape" variable from the syntax definition
31 | [tnrfae]
32 | | [0-7]{3}
33 | | x \h\h
34 | | x \{ \h{1,8} \}
35 | | c \d+
36 | | C- \d+
37 | | M- \d+
38 | | M-\\C- \d+
39 | )
40 | | \\. # a single escape character
41 | ){0}
42 | (?
43 | \( # an open paren
44 | ( # followed by either
45 | \g # ... anything that's not a group-related paren
46 | | \g # ... or a parens group (recursive)
47 | )*+
48 | \) # a closing paren
49 | ){0}
50 | (?
51 | (
52 | \g # anything that's not a group-related paren
53 | | \g # or a parens group (recursive)
54 | )*+
55 | ){0}
56 |
57 | # now the actual match
58 | ^ # start at the beginning of the line
59 | \g # the longest sequence of groups and non-group characters
60 | \( # followed by an unbalanced open paren
61 | ]]>
62 | decreaseIndentPattern
63 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/nested/build/base-packages/Graphviz/DOT.sublime-syntax:
--------------------------------------------------------------------------------
1 | %YAML 1.2
2 | ---
3 | name: Ecmascript nested syntax - Graphviz (DOT)
4 | scope: source.dot.nested.es
5 | contexts:
6 | main:
7 | - include: expressions
8 | expressions:
9 | - match: \b((sub|di)?graph)\b\s+((cluster)?\w+)\b
10 | captures:
11 | '1': storage.type.dot
12 | '3': entity.name.graph.dot
13 | '4': meta.annotation.dot variable.annotation.cluster.dot
14 | - match: \b(node|edge|graph|digraph|subgraph|strict)\b
15 | scope: storage.type.dot
16 | - match: >-
17 | \b(bottomlabel|color|comment|distortion|fillcolor|fixedsize|fontcolor|fontname|fontsize|group|height|label|layer|orientation|peripheries|regular|shape|shapefile|sides|skew|style|toplabel|URL|width|z)\b
18 | scope: support.constant.attribute.node.dot
19 | - match: >-
20 | \b(arrowhead|arrowsize|arrowtail|color|comment|constraint|decorate|dir|fontcolor|fontname|fontsize|headlabel|headport|headURL|label|labelangle|labeldistance|labelfloat|labelcolor|labelfontname|labelfontsize|layer|lhead|ltail|minlen|samehead|sametail|style|taillabel|tailport|tailURL|weight)\b
21 | scope: support.constant.attribute.edge.dot
22 | - match: >-
23 | \b(bgcolor|center|clusterrank|color|comment|compound|concentrate|fillcolor|fontname|fontpath|fontsize|label|labeljust|labelloc|layers|margin|mclimit|nodesep|nslimit|nslimit1|ordering|orientation|page|pagedir|quantum|rank|rankdir|ranksep|ratio|remincross|rotate|samplepoints|searchsize|size|style|URL)\b
24 | scope: support.constant.attribute.graph.dot
25 | - match: '-[->]'
26 | scope: punctuation.operator.relationship.dot
27 | - match: =
28 | scope: keyword.operator.assignment.dot
29 | - match: ;
30 | scope: punctuation.separator.statement.dot
31 | - match: '"'
32 | scope: punctuation.definition.string.begin.dot
33 | push:
34 | - meta_scope: string.quoted.double.dot
35 | - match: '"'
36 | scope: punctuation.definition.string.end.dot
37 | pop: true
38 | - match: \\.
39 | scope: constant.character.escape.dot
40 | - match: '[{}|]'
41 | scope: punctuation.separator.memory-block.dot
42 | - include: braces
43 | - include: brackets
44 | - include: embedded-html
45 | - include: comments
46 | embedded-html:
47 | - match: <
48 | scope: punctuation.section.embedded.begin.dot
49 | push:
50 | - meta_content_scope: source.dot.embedded.html
51 | - match: ((>)?\s*)(>)
52 | captures:
53 | '1': source.dot.embedded.html
54 | '2': meta.tag punctuation.definition.tag.end.html
55 | '3': punctuation.section.embedded.end.dot
56 | pop: true
57 | - match: ''
58 | embed: 'scope:text.html.basic.nested.es'
59 | escape: (?=>\s*>)
60 | braces:
61 | - match: '\{'
62 | scope: punctuation.definition.group.begin.dot
63 | push:
64 | - meta_scope: meta.group.dot
65 | - match: '\}'
66 | scope: punctuation.definition.group.end.dot
67 | pop: true
68 | - match: '[,;]'
69 | scope: punctuation.separator.dot
70 | - include: expressions
71 | brackets:
72 | - match: '\['
73 | scope: punctuation.definition.attributes.begin.dot
74 | push:
75 | - meta_scope: meta.attributes.dot
76 | - match: '\]'
77 | scope: punctuation.definition.attributes.end.dot
78 | pop: true
79 | - match: '[,;]'
80 | scope: punctuation.separator.dot
81 | - include: expressions
82 | comments:
83 | - match: //
84 | scope: punctuation.definition.comment.dot
85 | push:
86 | - meta_scope: comment.line.double-slash.dot
87 | - match: $\n?
88 | pop: true
89 | - match: '#'
90 | scope: punctuation.definition.comment.dot
91 | push:
92 | - meta_scope: comment.line.number-sign.dot
93 | - match: $\n?
94 | pop: true
95 | - match: /\*
96 | scope: punctuation.definition.comment.dot
97 | push:
98 | - meta_scope: comment.block.dot
99 | - match: \*/
100 | scope: punctuation.definition.comment.dot
101 | pop: true
102 | hidden: true
103 |
--------------------------------------------------------------------------------
/examples/nested-es-test.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | // identifier substituion tests
4 | /* syntax: js */ `
5 | let normal = 1;
6 |
7 | let ${decl} = 1;
8 |
9 | let pre_${decl} = 1;
10 |
11 | let ${decl}_post = 1;
12 |
13 | let pre_${decl}_post = 1;
14 |
15 | let pre_${decl}_mid_${mod}_post = 1;
16 |
17 |
18 | 'normal';
19 |
20 | '${string}';
21 |
22 | 'pre_${string}';
23 |
24 | '${string}_post';
25 |
26 | 'pre_${string}_post';
27 |
28 | 'pre_${string}_mid_${mod}_post';
29 |
30 |
31 | let thing = normal;
32 |
33 | let thing = ${value};
34 |
35 | let thing = pre_${value};
36 |
37 | let thing = ${value}_post;
38 |
39 | let thing = pre_${value}_post;
40 |
41 | let thing = pre_${value}_mid_${mod}_post;
42 |
43 |
44 | thing += normal;
45 |
46 | thing += ${value};
47 |
48 | thing += pre_${value};
49 |
50 | thing += ${value}_post;
51 |
52 | thing += pre_${value}_post;
53 |
54 | thing += pre_${value}_mid_${mod}_post;
55 |
56 |
57 | thing.normal();
58 |
59 | thing.${method}();
60 |
61 | thing.pre_${method}();
62 |
63 | thing.pre_${method}_post();
64 |
65 | thing.pre_${method}_mid_${mod}_post();
66 |
67 |
68 | normal.call();
69 |
70 | ${value}.call();
71 |
72 | pre_${value}.call();
73 |
74 | ${value}_post.call();
75 |
76 | pre_${value}_post.call();
77 |
78 | pre_${value}_mid_${mod}_post.call();
79 |
80 |
81 | function normal() {}
82 |
83 | function ${decl}() {}
84 |
85 | function pre_${decl}() {}
86 |
87 | function ${decl}_post() {}
88 |
89 | function pre_${decl}_post() {}
90 |
91 | function pre_${decl}_mid${mod}_post() {}
92 |
93 |
94 | function* normal() {}
95 |
96 | function* ${decl}() {}
97 |
98 | function* pre_${decl}() {}
99 |
100 | function* ${decl}_post() {}
101 |
102 | function* pre_${decl}_post() {}
103 |
104 | function* pre_${decl}_mid${mod}_post() {}
105 |
106 |
107 | class ${s_super} {
108 | constructor() {}
109 | }
110 |
111 | class ${s_class} extends ${s_super} {
112 | constructor() {}
113 |
114 |
115 | normal() {}
116 |
117 | ${method}() {}
118 |
119 | pre_${method}() {}
120 |
121 | ${method}_post() {}
122 |
123 | pre_${method}_post() {}
124 |
125 | pre_${method}_mid_${mod}_post() {}
126 |
127 |
128 | static normal() {}
129 |
130 | static ${method}() {}
131 |
132 | static pre_${method}() {}
133 |
134 | static ${method}_post() {}
135 |
136 | static pre_${method}_post() {}
137 |
138 | static pre_${method}_${mod}_post() {}
139 |
140 |
141 | get normal() {}
142 |
143 | get pre_${method}() {}
144 |
145 | get ${method}_post() {}
146 |
147 | get pre_${method}_post() {}
148 |
149 | get pre_${method}_mid_${mod}_post() {}
150 |
151 |
152 | set normal() {}
153 |
154 | set pre_${method}() {}
155 |
156 | set ${method}_post() {}
157 |
158 | set pre_${method}_post() {}
159 |
160 | set pre_${method}_mid_${mod}_post() {}
161 |
162 |
163 | async normal() {}
164 |
165 | async ${method}() {}
166 |
167 | async pre_${method}() {}
168 |
169 | async ${method}_post() {}
170 |
171 | async pre_${method}_post() {}
172 |
173 | async pre_${method}_mid_${mod}_post() {}
174 |
175 |
176 | * normal() {}
177 |
178 | * ${method}() {}
179 |
180 | * pre_${method}() {}
181 |
182 | * ${method}_post() {}
183 |
184 | * pre_${method}_post() {}
185 |
186 | * pre_${method}_mid_${mod}_post() {}
187 |
188 |
189 | async* normal() {}
190 |
191 | async* ${method}() {}
192 |
193 | async* pre_${method}() {}
194 |
195 | async* ${method}_post() {}
196 |
197 | async* pre_${method}_post() {}
198 |
199 | async* pre_${method}_mid_${mod}_post() {}
200 | }
201 | `;
202 |
203 |
204 | let script = `
205 | let vegetable = 'carrot';
206 |
207 | \`text\`;
208 | \`${fruit.name}\`;
209 | \`\${vegetable}\`;
210 | \`\\${fruit.color}\`;
211 | \`\\\${escaped text}\`;
212 |
213 | \`\n\`; // line-break
214 | \`\\n\`; // backslash, "n"
215 | \`\\\n\`; // backslash, line-break
216 | \`\\\\n\`; // backslash, backslash, "n"
217 | `;
218 |
219 | // the exact same string as above, but with js syntax highlighting:
220 | script == /* syntax: js */ `
221 | let vegetable = 'carrot';
222 |
223 | \`text\`;
224 | \`${fruit.name}\`;
225 | \`\${vegetable}\`;
226 | \`\\${fruit.color}\`;
227 | \`\\\${escaped text}\`;
228 |
229 | \`\n\`; // line-break
230 | \`\\n\`; // backslash, "n"
231 | \`\\\n\`; // backslash, line-break
232 | \`\\\\n\`; // backslash, backslash, "n"
233 | `;
--------------------------------------------------------------------------------
/commands.py:
--------------------------------------------------------------------------------
1 | import sublime, sublime_plugin
2 | import re
3 |
4 | ss_interp_element = 'punctuation.definition.string.interpolated.element'
5 | ss_template_literal = '(string.interpolated.es | meta.interpolation.syntax | entity.quasi.tag.name) - '+ss_interp_element+'.end.es'
6 |
7 | r_directive = r'(\s*syntax:\s*)([\w\.]*)(\s*)'
8 |
9 | class ToggleNestedSyntaxCommand(sublime_plugin.TextCommand):
10 | def behind(self, i_traverse, ss_behind, b_against=False):
11 | while i_traverse > 0 and self.view.match_selector(i_traverse, ss_behind): i_traverse -= 1
12 | if b_against: i_traverse += 1
13 | return i_traverse
14 |
15 | def over(self, i_traverse, ss_over):
16 | while self.view.match_selector(i_traverse, ss_over): i_traverse += 1
17 | return i_traverse
18 |
19 | def run(self, edit):
20 | d_view = self.view
21 |
22 | # ref selections
23 | a_sels = list(d_view.sel())
24 |
25 | # clear selections
26 | d_view.sel().clear()
27 |
28 | # cumulative gap
29 | c_gap = 0
30 |
31 | # each selection
32 | for y_cursor in a_sels:
33 | y_region = None
34 |
35 | # for multi-selection
36 | y_cursor.a += c_gap
37 | y_cursor.b += c_gap
38 |
39 | # traversal point
40 | i_traverse = i_cursor = y_cursor.begin()
41 |
42 | c_loops = 0
43 |
44 | # find beginning of interpolated string
45 | while d_view.match_selector(i_traverse, ss_template_literal):
46 | if c_loops > 15: break
47 | c_loops += 1
48 |
49 | # traverse beyond template literal
50 | i_traverse = self.behind(i_traverse, ss_template_literal)
51 |
52 | # reached bof
53 | if i_traverse == 0: break
54 |
55 | # boundary is interpolated element
56 | if d_view.match_selector(i_traverse, ss_interp_element+'.end.es'):
57 | # traverse over interpolated element
58 | while i_traverse > 0 and not d_view.match_selector(i_traverse, ss_interp_element+'.begin.es'):
59 | i_traverse -= 1
60 |
61 | # keep traversing
62 | continue
63 |
64 | # boundary is anything else; stop traversing
65 | else:
66 | break
67 |
68 | # start of template literal
69 | i_literal = i_traverse + 1
70 |
71 | # span whitespace and then block comment
72 | i_traverse = self.behind(i_traverse, 'meta.whitespace.es')
73 | i_traverse = self.behind(i_traverse, 'comment.block.es', True)
74 |
75 | # at block comment
76 | if d_view.match_selector(i_traverse, 'comment.block.es & meta.comment.border.es'):
77 | i_block = i_traverse
78 |
79 | # move forward past border
80 | i_traverse = self.over(i_traverse, 'meta.comment.border.es')
81 |
82 | # match syntax directive
83 | y_directive = d_view.find(r_directive, i_traverse)
84 | if y_directive is not None and not y_directive.empty() and y_directive.begin() < i_literal:
85 | # toggle off directive
86 | d_view.erase(edit, sublime.Region(i_block, i_literal))
87 |
88 | # calculate gap
89 | n_gap = i_literal - i_block
90 |
91 | # update cursor with offset
92 | y_cursor.a -= n_gap
93 | y_cursor.b -= n_gap
94 |
95 | c_gap -= n_gap
96 |
97 | # add cursor
98 | d_view.sel().add(y_cursor)
99 |
100 | # next selection
101 | continue;
102 |
103 | # pre region
104 | y_region_pre = sublime.Region(i_literal, i_cursor)
105 |
106 | # offset
107 | nl_offset = 0
108 |
109 | # pre text
110 | s_pre = d_view.substr(y_region_pre)
111 | nl_offset += len(s_pre)
112 | s_pre = re.sub(r'\$', r'\\$', s_pre);
113 |
114 | # selection
115 | s_sel = d_view.substr(y_cursor)
116 | nl_offset += len(s_sel)
117 | s_sel = "${0:"+re.sub(r'\$', r'\\$', s_sel)+"}"
118 |
119 | # auto-gobble upcoming insert_snippet's auto-indentation
120 | i_bol = d_view.expand_by_class(i_literal, sublime.CLASS_LINE_START).begin()
121 | s_line = d_view.substr(sublime.Region(i_bol, i_literal))
122 | m_gobble = re.match(r'^([ \t]*)', s_line)
123 | if m_gobble is not None:
124 | s_pre = re.sub(r'\n'+m_gobble.group(1), '\n', s_pre)
125 |
126 | # post text
127 | i_traverse = self.over(i_cursor, ss_template_literal)
128 |
129 | # update cursor
130 | y_cursor.b = y_cursor.end()
131 | y_cursor.a = i_literal
132 |
133 | # add cursor
134 | d_view.sel().add(y_cursor)
135 |
136 | # add directive
137 | s_dir = "/* syntax: ${1:language} */ "
138 | c_gap += len(s_dir) - 5
139 | s_snippet = s_dir+s_pre+s_sel
140 |
141 | # update cumulative gap
142 | c_gap += nl_offset
143 |
144 | # insert code
145 | d_view.run_command('insert_snippet', {"contents": s_snippet})
146 |
147 |
148 |
149 | class InsertNestedSyntaxCommand(sublime_plugin.TextCommand):
150 | def run(self, edit):
151 | d_view = self.view
152 |
153 | # ref selections
154 | a_sels = list(d_view.sel())
155 |
156 | # each selection
157 | for y_cursor in a_sels:
158 | y_region = None
159 |
160 | s_snippet = "/* syntax: ${1:language} */ `$0`"
161 | d_view.run_command('insert_snippet', {"contents": s_snippet})
162 |
--------------------------------------------------------------------------------
/nested/src/enhance-color-scheme.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const yaml = require('js-yaml');
3 | const plist = require('plist');
4 |
5 |
6 | const recurse_rule = (g_rule, a_path, f_scope) => {
7 | // rule has `set` action
8 | if(g_rule.set) recurse_context(g_rule.set, [...a_path, 'set'], f_scope);
9 |
10 | // rule has `push` action
11 | if(g_rule.push) g_rule.push = recurse_context(g_rule.push, [...a_path, 'push'], f_scope);
12 |
13 | // rule has `embed` action
14 | if(g_rule.embed) g_rule.embed = recurse_context(g_rule.embed, [...a_path, 'embed'], f_scope);
15 |
16 | // rule has `include` action
17 | if(g_rule.include) g_rule.include = recurse_context(g_rule.include, [...a_path, 'include'], f_scope);
18 |
19 | // rule has `with_prototype` action
20 | if(g_rule.with_prototype) g_rule.with_prototype = recurse_context(g_rule.with_prototype, [...a_path, 'with_prototype'], f_scope);
21 |
22 | // ways that scopes are applied
23 | if(g_rule.scope) f_scope(g_rule.scope, [...a_path, 'scope']);
24 | if(g_rule.meta_scope) f_scope(g_rule.meta_scope, [...a_path, 'meta_scope']);
25 | if(g_rule.captures) {
26 | // each capture
27 | for(let [s_index, s_capture] of Object.entries(g_rule.captures)) {
28 | f_scope(s_capture, [...a_path, 'captures', s_index]);
29 | }
30 | }
31 | };
32 |
33 | const recurse_context = (z_context, a_path, f_scope) => {
34 | // context is list of rules
35 | if(Array.isArray(z_context)) {
36 | let a_rules = z_context;
37 |
38 | // each rule
39 | for(let [s_index, g_rule] of Object.entries(a_rules)) {
40 | recurse_rule(g_rule, [...a_path, s_index], f_scope);
41 | }
42 | }
43 | };
44 |
45 | const collect_scopes = (p_file, s_syntax) => {
46 | // load ecmascript syntax file contents
47 | let s_syntax_contents = fs.readFileSync(p_file, 'utf8');
48 |
49 | // parse syntax def as yaml
50 | let g_syntax = yaml.safeLoad(s_syntax_contents, {
51 | filename: p_file,
52 | });
53 |
54 | let as_scopes = new Set();
55 |
56 | // each context in syntax
57 | for(let [si_context, z_context] of Object.entries(g_syntax.contexts)) {
58 | recurse_context(z_context, [si_context], s_scopes => s_scopes.split(/\s+/g)
59 | .forEach((s_scope) => {
60 | if(s_scope.endsWith(`.${s_syntax}`)) as_scopes.add(s_scope);
61 | }));
62 | }
63 |
64 | return as_scopes;
65 | };
66 |
67 | let a_mappings_common = [
68 | [/^entity\.other\.attribute/, 'variable.other.attribute.jsx'],
69 | [/^entity\.name\.tag/, 'entity.name.tag.jsx'],
70 | [/^string\.quoted/, 'string.text.jsx'],
71 | [/^(punctuation\.(definition\.(?!comment)|separator)|keyword\.operator)/, 'punctuation.definition.tag.begin.jsx'],
72 | ];
73 |
74 | // collect all XML-like syntax scopes
75 | const H_XML_SYNTAXES = {
76 | html: {
77 | scopes: collect_scopes('./build/base-packages/HTML/HTML.sublime-syntax', 'html'),
78 | mappings: new Map([
79 | // make