@willbooster/tree-sitter-markdown 0.0.0-stage → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +196 -2
- package/common/common.js +132 -0
- package/common/html_entities.json +2234 -0
- package/package.json +77 -4
- package/tree-sitter-markdown/grammar.js +611 -0
- package/tree-sitter-markdown/queries/highlights.scm +47 -0
- package/tree-sitter-markdown/queries/injections.scm +25 -0
- package/tree-sitter-markdown/src/node-types.json +957 -0
- package/tree-sitter-markdown-inline/grammar.js +474 -0
- package/tree-sitter-markdown-inline/queries/highlights.scm +56 -0
- package/tree-sitter-markdown-inline/queries/injections.scm +5 -0
- package/tree-sitter-markdown-inline/src/node-types.json +870 -0
- package/tree-sitter-markdown.wasm +0 -0
- package/tree-sitter-markdown_inline.wasm +0 -0
- package/tree-sitter.json +55 -0
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
// This grammar only concerns the inline structure according to the CommonMark Spec
|
|
2
|
+
// (https://spec.commonmark.org/0.30/#inlines)
|
|
3
|
+
// For more information see README.md
|
|
4
|
+
|
|
5
|
+
/// <reference types="tree-sitter-cli/dsl" />
|
|
6
|
+
|
|
7
|
+
const common = require('../common/common');
|
|
8
|
+
|
|
9
|
+
// Levels used for dynmic precedence. Ideally
|
|
10
|
+
// n * PRECEDENCE_LEVEL_EMPHASIS > PRECEDENCE_LEVEL_LINK for any n, so maybe the
|
|
11
|
+
// maginuted of these values should be increased in the future
|
|
12
|
+
const PRECEDENCE_LEVEL_EMPHASIS = 1;
|
|
13
|
+
const PRECEDENCE_LEVEL_LINK = 10;
|
|
14
|
+
const PRECEDENCE_LEVEL_HTML = 100;
|
|
15
|
+
|
|
16
|
+
// Punctuation characters as specified in
|
|
17
|
+
// https://github.github.com/gfm/#ascii-punctuation-character
|
|
18
|
+
const PUNCTUATION_CHARACTERS_REGEX = '!-/:-@\\[-`\\{-~';
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
// !!!
|
|
22
|
+
// Notice the call to `add_inline_rules` which generates some additional rules related to parsing
|
|
23
|
+
// inline contents in different contexts.
|
|
24
|
+
// !!!
|
|
25
|
+
module.exports = grammar(add_inline_rules({
|
|
26
|
+
name: 'markdown_inline',
|
|
27
|
+
|
|
28
|
+
externals: $ => [
|
|
29
|
+
// An `$._error` token is never valid and gets emmited to kill invalid parse branches. Concretely
|
|
30
|
+
// this is used to decide wether a newline closes a paragraph and together and it gets emitted
|
|
31
|
+
// when trying to parse the `$._trigger_error` token in `$.link_title`.
|
|
32
|
+
$._error,
|
|
33
|
+
$._trigger_error,
|
|
34
|
+
|
|
35
|
+
// Opening and closing delimiters for code spans. These are sequences of one or more backticks.
|
|
36
|
+
// An opening token does not mean the text after has to be a code span if there is no closing token
|
|
37
|
+
$._code_span_start,
|
|
38
|
+
$._code_span_close,
|
|
39
|
+
|
|
40
|
+
// Opening and closing delimiters for emphasis.
|
|
41
|
+
$._emphasis_open_star,
|
|
42
|
+
$._emphasis_open_underscore,
|
|
43
|
+
$._emphasis_close_star,
|
|
44
|
+
$._emphasis_close_underscore,
|
|
45
|
+
|
|
46
|
+
// For emphasis we need to tell the parser if the last character was a whitespace (or the
|
|
47
|
+
// beginning of a line) or a punctuation. These tokens never actually get emitted.
|
|
48
|
+
$._last_token_whitespace,
|
|
49
|
+
$._last_token_punctuation,
|
|
50
|
+
|
|
51
|
+
$._strikethrough_open,
|
|
52
|
+
$._strikethrough_close,
|
|
53
|
+
|
|
54
|
+
// Opening and closing delimiters for latex. These are sequences of one or more dollar signs.
|
|
55
|
+
// An opening token does not mean the text after has to be latex if there is no closing token
|
|
56
|
+
$._latex_span_start,
|
|
57
|
+
$._latex_span_close,
|
|
58
|
+
|
|
59
|
+
// Token emmited when encountering opening delimiters for a leaf span
|
|
60
|
+
// e.g. a code span, that does not have a matching closing span
|
|
61
|
+
$._unclosed_span
|
|
62
|
+
],
|
|
63
|
+
precedences: $ => [
|
|
64
|
+
// [$._strong_emphasis_star, $._inline_element_no_star],
|
|
65
|
+
[$._strong_emphasis_star_no_link, $._inline_element_no_star_no_link],
|
|
66
|
+
// [$._strong_emphasis_underscore, $._inline_element_no_underscore],
|
|
67
|
+
[$._strong_emphasis_underscore_no_link, $._inline_element_no_underscore_no_link],
|
|
68
|
+
[$.hard_line_break, $._whitespace],
|
|
69
|
+
[$.hard_line_break, $._text_base],
|
|
70
|
+
],
|
|
71
|
+
// More conflicts are defined in `add_inline_rules`
|
|
72
|
+
conflicts: $ => [
|
|
73
|
+
|
|
74
|
+
[$._closing_tag, $._text_base],
|
|
75
|
+
[$._open_tag, $._text_base],
|
|
76
|
+
[$._html_comment, $._text_base],
|
|
77
|
+
[$._processing_instruction, $._text_base],
|
|
78
|
+
[$._declaration, $._text_base],
|
|
79
|
+
[$._cdata_section, $._text_base],
|
|
80
|
+
|
|
81
|
+
[$._link_text_non_empty, $._inline_element],
|
|
82
|
+
[$._link_text_non_empty, $._inline_element_no_star],
|
|
83
|
+
[$._link_text_non_empty, $._inline_element_no_underscore],
|
|
84
|
+
[$._link_text_non_empty, $._inline_element_no_tilde],
|
|
85
|
+
[$._link_text, $._inline_element],
|
|
86
|
+
[$._link_text, $._inline_element_no_star],
|
|
87
|
+
[$._link_text, $._inline_element_no_underscore],
|
|
88
|
+
[$._link_text, $._inline_element_no_tilde],
|
|
89
|
+
|
|
90
|
+
[$._image_description, $._image_description_non_empty, $._text_base],
|
|
91
|
+
// [$._image_description, $._image_description_non_empty, $._text_inline],
|
|
92
|
+
// [$._image_description, $._image_description_non_empty, $._text_inline_no_star],
|
|
93
|
+
// [$._image_description, $._image_description_non_empty, $._text_inline_no_underscore],
|
|
94
|
+
|
|
95
|
+
[$._image_shortcut_link, $._image_description],
|
|
96
|
+
[$.shortcut_link, $._link_text],
|
|
97
|
+
[$.link_destination, $.link_title],
|
|
98
|
+
[$._link_destination_parenthesis, $.link_title],
|
|
99
|
+
|
|
100
|
+
[$.wiki_link, $._inline_element],
|
|
101
|
+
[$.wiki_link, $._inline_element_no_star],
|
|
102
|
+
[$.wiki_link, $._inline_element_no_underscore],
|
|
103
|
+
[$.wiki_link, $._inline_element_no_tilde],
|
|
104
|
+
],
|
|
105
|
+
extras: $ => [],
|
|
106
|
+
|
|
107
|
+
rules: {
|
|
108
|
+
inline: $ => seq(optional($._last_token_whitespace), $._inline),
|
|
109
|
+
|
|
110
|
+
...common.rules,
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
// A lot of inlines are defined in `add_inline_rules`, including:
|
|
114
|
+
//
|
|
115
|
+
// * collections of inlines
|
|
116
|
+
// * emphasis
|
|
117
|
+
// * textual content
|
|
118
|
+
//
|
|
119
|
+
// This is done to reduce code duplication, as some inlines need to be parsed differently
|
|
120
|
+
// depending on the context. For example inlines in ATX headings may not contain newlines.
|
|
121
|
+
|
|
122
|
+
code_span: $ => seq(
|
|
123
|
+
alias($._code_span_start, $.code_span_delimiter),
|
|
124
|
+
repeat(choice($._text_base, '[', ']', $._soft_line_break, $._html_tag)),
|
|
125
|
+
alias($._code_span_close, $.code_span_delimiter)
|
|
126
|
+
),
|
|
127
|
+
|
|
128
|
+
latex_block: $ => seq(
|
|
129
|
+
alias($._latex_span_start, $.latex_span_delimiter),
|
|
130
|
+
repeat(choice($._text_base, '[', ']', $._soft_line_break, $._html_tag, $.backslash_escape)),
|
|
131
|
+
alias($._latex_span_close, $.latex_span_delimiter),
|
|
132
|
+
),
|
|
133
|
+
|
|
134
|
+
// Different kinds of links:
|
|
135
|
+
// * inline links (https://github.github.com/gfm/#inline-link)
|
|
136
|
+
// * full reference links (https://github.github.com/gfm/#full-reference-link)
|
|
137
|
+
// * collapsed reference links (https://github.github.com/gfm/#collapsed-reference-link)
|
|
138
|
+
// * shortcut links (https://github.github.com/gfm/#shortcut-reference-link)
|
|
139
|
+
//
|
|
140
|
+
// Dynamic precedence is distributed as granular as possible to help the parser decide
|
|
141
|
+
// while parsing which branch is the most important.
|
|
142
|
+
//
|
|
143
|
+
// https://github.github.com/gfm/#links
|
|
144
|
+
_link_text: $ => prec.dynamic(PRECEDENCE_LEVEL_LINK, choice(
|
|
145
|
+
$._link_text_non_empty,
|
|
146
|
+
seq('[', ']')
|
|
147
|
+
)),
|
|
148
|
+
_link_text_non_empty: $ => seq('[', alias($._inline_no_link, $.link_text), ']'),
|
|
149
|
+
shortcut_link: $ => prec.dynamic(PRECEDENCE_LEVEL_LINK, $._link_text_non_empty),
|
|
150
|
+
full_reference_link: $ => prec.dynamic(2 * PRECEDENCE_LEVEL_LINK, seq(
|
|
151
|
+
$._link_text,
|
|
152
|
+
$.link_label
|
|
153
|
+
)),
|
|
154
|
+
collapsed_reference_link: $ => prec.dynamic(PRECEDENCE_LEVEL_LINK, seq(
|
|
155
|
+
$._link_text,
|
|
156
|
+
'[',
|
|
157
|
+
']'
|
|
158
|
+
)),
|
|
159
|
+
inline_link: $ => prec.dynamic(PRECEDENCE_LEVEL_LINK, seq(
|
|
160
|
+
$._link_text,
|
|
161
|
+
'(',
|
|
162
|
+
repeat(choice($._whitespace, $._soft_line_break)),
|
|
163
|
+
optional(seq(
|
|
164
|
+
choice(
|
|
165
|
+
seq(
|
|
166
|
+
$.link_destination,
|
|
167
|
+
optional(seq(
|
|
168
|
+
repeat1(choice($._whitespace, $._soft_line_break)),
|
|
169
|
+
$.link_title
|
|
170
|
+
))
|
|
171
|
+
),
|
|
172
|
+
$.link_title,
|
|
173
|
+
),
|
|
174
|
+
repeat(choice($._whitespace, $._soft_line_break)),
|
|
175
|
+
)),
|
|
176
|
+
')'
|
|
177
|
+
)),
|
|
178
|
+
|
|
179
|
+
wiki_link: $ => prec.dynamic(2 * PRECEDENCE_LEVEL_LINK, seq(
|
|
180
|
+
'[', '[',
|
|
181
|
+
alias($._wiki_link_destination, $.link_destination),
|
|
182
|
+
optional(seq(
|
|
183
|
+
'|',
|
|
184
|
+
alias($._wiki_link_text, $.link_text)
|
|
185
|
+
)),
|
|
186
|
+
']', ']'
|
|
187
|
+
)
|
|
188
|
+
),
|
|
189
|
+
|
|
190
|
+
_wiki_link_destination: $ => repeat1(choice(
|
|
191
|
+
$._word,
|
|
192
|
+
common.punctuation_without($, ['[',']', '|']),
|
|
193
|
+
$._whitespace,
|
|
194
|
+
)),
|
|
195
|
+
|
|
196
|
+
_wiki_link_text: $ => repeat1(choice(
|
|
197
|
+
$._word,
|
|
198
|
+
common.punctuation_without($, ['[',']']),
|
|
199
|
+
$._whitespace,
|
|
200
|
+
)),
|
|
201
|
+
|
|
202
|
+
// Images work exactly like links with a '!' added in front.
|
|
203
|
+
//
|
|
204
|
+
// https://github.github.com/gfm/#images
|
|
205
|
+
image: $ => choice(
|
|
206
|
+
$._image_inline_link,
|
|
207
|
+
$._image_shortcut_link,
|
|
208
|
+
$._image_full_reference_link,
|
|
209
|
+
$._image_collapsed_reference_link
|
|
210
|
+
),
|
|
211
|
+
_image_inline_link: $ => prec.dynamic(PRECEDENCE_LEVEL_LINK, seq(
|
|
212
|
+
$._image_description,
|
|
213
|
+
'(',
|
|
214
|
+
repeat(choice($._whitespace, $._soft_line_break)),
|
|
215
|
+
optional(seq(
|
|
216
|
+
choice(
|
|
217
|
+
seq(
|
|
218
|
+
$.link_destination,
|
|
219
|
+
optional(seq(
|
|
220
|
+
repeat1(choice($._whitespace, $._soft_line_break)),
|
|
221
|
+
$.link_title
|
|
222
|
+
))
|
|
223
|
+
),
|
|
224
|
+
$.link_title,
|
|
225
|
+
),
|
|
226
|
+
repeat(choice($._whitespace, $._soft_line_break)),
|
|
227
|
+
)),
|
|
228
|
+
')'
|
|
229
|
+
)),
|
|
230
|
+
_image_shortcut_link: $ => prec.dynamic(3 * PRECEDENCE_LEVEL_LINK, $._image_description_non_empty),
|
|
231
|
+
_image_full_reference_link: $ => prec.dynamic(PRECEDENCE_LEVEL_LINK, seq($._image_description, $.link_label)),
|
|
232
|
+
_image_collapsed_reference_link: $ => prec.dynamic(PRECEDENCE_LEVEL_LINK, seq($._image_description, '[', ']')),
|
|
233
|
+
_image_description: $ => prec.dynamic(3 * PRECEDENCE_LEVEL_LINK, choice($._image_description_non_empty, seq('!', '[', prec(1, ']')))),
|
|
234
|
+
_image_description_non_empty: $ => seq('!', '[', alias($._inline, $.image_description), prec(1, ']')),
|
|
235
|
+
|
|
236
|
+
// Autolinks. Uri autolinks actually accept protocolls of arbitrary length which does not
|
|
237
|
+
// align with the spec. This is because the binary for the grammar gets to large if done
|
|
238
|
+
// otherwise as tree-sitters code generation is not very concise for this type of regex.
|
|
239
|
+
//
|
|
240
|
+
// Email autolinks do not match every valid email (emails normally should not be parsed
|
|
241
|
+
// using regexes), but this is how they are defined in the spec.
|
|
242
|
+
//
|
|
243
|
+
// https://github.github.com/gfm/#autolinks
|
|
244
|
+
uri_autolink: $ => /<[a-zA-Z][a-zA-Z0-9+\.\-][a-zA-Z0-9+\.\-]*:[^ \t\r\n<>]*>/,
|
|
245
|
+
email_autolink: $ =>
|
|
246
|
+
/<[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*>/,
|
|
247
|
+
|
|
248
|
+
// Raw html. As with html blocks we do not emit additional information as this is best done
|
|
249
|
+
// by a proper html tree-sitter grammar.
|
|
250
|
+
//
|
|
251
|
+
// https://github.github.com/gfm/#raw-html
|
|
252
|
+
_html_tag: $ => choice($._open_tag, $._closing_tag, $._html_comment, $._processing_instruction, $._declaration, $._cdata_section),
|
|
253
|
+
_open_tag: $ => prec.dynamic(PRECEDENCE_LEVEL_HTML, seq('<', $._tag_name, repeat($._attribute), repeat(choice($._whitespace, $._soft_line_break)), optional('/'), '>')),
|
|
254
|
+
_closing_tag: $ => prec.dynamic(PRECEDENCE_LEVEL_HTML, seq('<', '/', $._tag_name, repeat(choice($._whitespace, $._soft_line_break)), '>')),
|
|
255
|
+
_tag_name: $ => seq($._word_no_digit, repeat(choice($._word_no_digit, $._digits, '-'))),
|
|
256
|
+
_attribute: $ => seq(repeat1(choice($._whitespace, $._soft_line_break)), $._attribute_name, repeat(choice($._whitespace, $._soft_line_break)), '=', repeat(choice($._whitespace, $._soft_line_break)), $._attribute_value),
|
|
257
|
+
_attribute_name: $ => /[a-zA-Z_:][a-zA-Z0-9_\.:\-]*/,
|
|
258
|
+
_attribute_value: $ => choice(
|
|
259
|
+
/[^ \t\r\n"'=<>`]+/,
|
|
260
|
+
seq("'", repeat(choice($._word, $._whitespace, $._soft_line_break, common.punctuation_without($, ["'"]))), "'"),
|
|
261
|
+
seq('"', repeat(choice($._word, $._whitespace, $._soft_line_break, common.punctuation_without($, ['"']))), '"'),
|
|
262
|
+
),
|
|
263
|
+
_html_comment: $ => prec.dynamic(PRECEDENCE_LEVEL_HTML, seq(
|
|
264
|
+
'<!--',
|
|
265
|
+
optional(seq(
|
|
266
|
+
choice(
|
|
267
|
+
$._word,
|
|
268
|
+
$._whitespace,
|
|
269
|
+
$._soft_line_break,
|
|
270
|
+
common.punctuation_without($, ['-', '>']),
|
|
271
|
+
seq(
|
|
272
|
+
'-',
|
|
273
|
+
common.punctuation_without($, ['>']),
|
|
274
|
+
)
|
|
275
|
+
),
|
|
276
|
+
repeat(prec.right(choice(
|
|
277
|
+
$._word,
|
|
278
|
+
$._whitespace,
|
|
279
|
+
$._soft_line_break,
|
|
280
|
+
common.punctuation_without($, ['-']),
|
|
281
|
+
seq(
|
|
282
|
+
'-',
|
|
283
|
+
choice(
|
|
284
|
+
$._word,
|
|
285
|
+
$._whitespace,
|
|
286
|
+
$._soft_line_break,
|
|
287
|
+
common.punctuation_without($, ['-']),
|
|
288
|
+
)
|
|
289
|
+
)
|
|
290
|
+
))),
|
|
291
|
+
)),
|
|
292
|
+
'-->'
|
|
293
|
+
)),
|
|
294
|
+
_processing_instruction: $ => prec.dynamic(PRECEDENCE_LEVEL_HTML, seq(
|
|
295
|
+
'<?',
|
|
296
|
+
repeat(prec.right(choice(
|
|
297
|
+
$._word,
|
|
298
|
+
$._whitespace,
|
|
299
|
+
$._soft_line_break,
|
|
300
|
+
common.punctuation_without($, []),
|
|
301
|
+
))),
|
|
302
|
+
'?>'
|
|
303
|
+
)),
|
|
304
|
+
_declaration: $ => prec.dynamic(PRECEDENCE_LEVEL_HTML, seq(
|
|
305
|
+
/<![A-Z]+/,
|
|
306
|
+
choice(
|
|
307
|
+
$._whitespace,
|
|
308
|
+
$._soft_line_break,
|
|
309
|
+
),
|
|
310
|
+
repeat(prec.right(choice(
|
|
311
|
+
$._word,
|
|
312
|
+
$._whitespace,
|
|
313
|
+
$._soft_line_break,
|
|
314
|
+
common.punctuation_without($, ['>']),
|
|
315
|
+
))),
|
|
316
|
+
'>'
|
|
317
|
+
)),
|
|
318
|
+
_cdata_section: $ => prec.dynamic(PRECEDENCE_LEVEL_HTML, seq(
|
|
319
|
+
'<![CDATA[',
|
|
320
|
+
repeat(prec.right(choice(
|
|
321
|
+
$._word,
|
|
322
|
+
$._whitespace,
|
|
323
|
+
$._soft_line_break,
|
|
324
|
+
common.punctuation_without($, []),
|
|
325
|
+
))),
|
|
326
|
+
']]>'
|
|
327
|
+
)),
|
|
328
|
+
|
|
329
|
+
// A hard line break.
|
|
330
|
+
//
|
|
331
|
+
// https://github.github.com/gfm/#hard-line-breaks
|
|
332
|
+
hard_line_break: $ => seq(choice('\\', $._whitespace_ge_2), $._soft_line_break),
|
|
333
|
+
_text: $ => choice($._word, common.punctuation_without($, []), $._whitespace),
|
|
334
|
+
|
|
335
|
+
// Whitespace is divided into single whitespaces and multiple whitespaces as wee need this
|
|
336
|
+
// information for hard line breaks.
|
|
337
|
+
_whitespace_ge_2: $ => /\t| [ \t]+/,
|
|
338
|
+
_whitespace: $ => seq(choice($._whitespace_ge_2, / /), optional($._last_token_whitespace)),
|
|
339
|
+
|
|
340
|
+
// Other than whitespace we tokenize into strings of digits, punctuation characters
|
|
341
|
+
// (handled by `common.punctuation_without`) and strings of any other characters. This way the
|
|
342
|
+
// lexer does not have to many different states, which makes it a lot easier to make
|
|
343
|
+
// conflicts work.
|
|
344
|
+
_word: $ => choice($._word_no_digit, $._digits),
|
|
345
|
+
_word_no_digit: $ => new RegExp('[^' + PUNCTUATION_CHARACTERS_REGEX + ' \\t\\n\\r0-9]+(_+[^' + PUNCTUATION_CHARACTERS_REGEX + ' \\t\\n\\r0-9]+)*'),
|
|
346
|
+
_digits: $ => /[0-9][0-9_]*/,
|
|
347
|
+
_soft_line_break: $ => seq($._newline_token, optional($._last_token_whitespace)),
|
|
348
|
+
|
|
349
|
+
_inline_base: $ => prec.right(repeat1(choice(
|
|
350
|
+
$.image,
|
|
351
|
+
$._soft_line_break,
|
|
352
|
+
$.backslash_escape,
|
|
353
|
+
$.hard_line_break,
|
|
354
|
+
$.uri_autolink,
|
|
355
|
+
$.email_autolink,
|
|
356
|
+
$.entity_reference,
|
|
357
|
+
$.numeric_character_reference,
|
|
358
|
+
(common.EXTENSION_LATEX ? $.latex_block : choice()),
|
|
359
|
+
$.code_span,
|
|
360
|
+
alias($._html_tag, $.html_tag),
|
|
361
|
+
$._text_base,
|
|
362
|
+
common.EXTENSION_TAGS ? $.tag : choice(),
|
|
363
|
+
$._unclosed_span,
|
|
364
|
+
))),
|
|
365
|
+
_text_base: $ => choice(
|
|
366
|
+
$._word,
|
|
367
|
+
common.punctuation_without($, ['[', ']']),
|
|
368
|
+
$._whitespace,
|
|
369
|
+
'<!--',
|
|
370
|
+
/<![A-Z]+/,
|
|
371
|
+
'<?',
|
|
372
|
+
'<![CDATA[',
|
|
373
|
+
),
|
|
374
|
+
_text_inline_no_link: $ => choice(
|
|
375
|
+
$._text_base,
|
|
376
|
+
$._emphasis_open_star,
|
|
377
|
+
$._emphasis_open_underscore,
|
|
378
|
+
$._unclosed_span,
|
|
379
|
+
),
|
|
380
|
+
|
|
381
|
+
...(common.EXTENSION_TAGS ? {
|
|
382
|
+
tag: $ => /#[0-9]*[a-zA-Z_\-\/][a-zA-Z_\-\/0-9]*/,
|
|
383
|
+
} : {}),
|
|
384
|
+
|
|
385
|
+
},
|
|
386
|
+
}));
|
|
387
|
+
|
|
388
|
+
// This function adds some extra inline rules. This is done to reduce code duplication, as some
|
|
389
|
+
// rules may not contain newlines, characters like '*' and '_', ... depending on the context.
|
|
390
|
+
//
|
|
391
|
+
// This is by far the most ugly part of this code and should be cleaned up.
|
|
392
|
+
function add_inline_rules(grammar) {
|
|
393
|
+
let conflicts = [];
|
|
394
|
+
for (let link of [true, false]) {
|
|
395
|
+
let suffix_link = link ? "" : "_no_link";
|
|
396
|
+
for (let delimiter of [false, "star", "underscore", "tilde"]) {
|
|
397
|
+
let suffix_delimiter = delimiter ? "_no_" + delimiter : "";
|
|
398
|
+
let suffix = suffix_delimiter + suffix_link;
|
|
399
|
+
grammar.rules["_inline_element" + suffix] = $ => {
|
|
400
|
+
let elements = [
|
|
401
|
+
$._inline_base,
|
|
402
|
+
alias($['_emphasis_star' + suffix_link], $.emphasis),
|
|
403
|
+
alias($['_strong_emphasis_star' + suffix_link], $.strong_emphasis),
|
|
404
|
+
alias($['_emphasis_underscore' + suffix_link], $.emphasis),
|
|
405
|
+
alias($['_strong_emphasis_underscore' + suffix_link], $.strong_emphasis),
|
|
406
|
+
];
|
|
407
|
+
if (common.EXTENSION_STRIKETHROUGH) {
|
|
408
|
+
elements.push(alias($['_strikethrough' + suffix_link], $.strikethrough));
|
|
409
|
+
}
|
|
410
|
+
if (delimiter !== "star") {
|
|
411
|
+
elements.push($._emphasis_open_star);
|
|
412
|
+
}
|
|
413
|
+
if (delimiter !== "underscore") {
|
|
414
|
+
elements.push($._emphasis_open_underscore);
|
|
415
|
+
}
|
|
416
|
+
if (delimiter !== "tilde") {
|
|
417
|
+
elements.push($._strikethrough_open);
|
|
418
|
+
}
|
|
419
|
+
if (link) {
|
|
420
|
+
elements = elements.concat([
|
|
421
|
+
$.shortcut_link,
|
|
422
|
+
$.full_reference_link,
|
|
423
|
+
$.collapsed_reference_link,
|
|
424
|
+
$.inline_link,
|
|
425
|
+
// (common.EXTENSION_WIKI_LINK && $.wiki_link),
|
|
426
|
+
seq(choice('[', ']'), optional($._last_token_punctuation)),
|
|
427
|
+
]);
|
|
428
|
+
if (common.EXTENSION_WIKI_LINK) {
|
|
429
|
+
elements.push($.wiki_link);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return choice(...elements);
|
|
433
|
+
};
|
|
434
|
+
grammar.rules["_inline" + suffix] = $ => repeat1($["_inline_element" + suffix]);
|
|
435
|
+
if (delimiter !== "star") {
|
|
436
|
+
conflicts.push(['_emphasis_star' + suffix_link, '_inline_element' + suffix_delimiter + suffix_link]);
|
|
437
|
+
conflicts.push(['_emphasis_star' + suffix_link, '_strong_emphasis_star' + suffix_link, '_inline_element' + suffix_delimiter + suffix_link]);
|
|
438
|
+
}
|
|
439
|
+
if (delimiter == 'star' || delimiter == 'underscore') {
|
|
440
|
+
conflicts.push(['_strong_emphasis_' + delimiter + suffix_link, '_inline_element_no_' + delimiter]);
|
|
441
|
+
}
|
|
442
|
+
if (delimiter !== "underscore") {
|
|
443
|
+
conflicts.push(['_emphasis_underscore' + suffix_link, '_inline_element' + suffix_delimiter + suffix_link]);
|
|
444
|
+
conflicts.push(['_emphasis_underscore' + suffix_link, '_strong_emphasis_underscore' + suffix_link, '_inline_element' + suffix_delimiter + suffix_link]);
|
|
445
|
+
}
|
|
446
|
+
if (delimiter !== "tilde") {
|
|
447
|
+
conflicts.push(['_strikethrough' + suffix_link, '_inline_element' + suffix_delimiter + suffix_link]);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (common.EXTENSION_STRIKETHROUGH) {
|
|
452
|
+
grammar.rules['_strikethrough' + suffix_link] = $ => prec.dynamic(PRECEDENCE_LEVEL_EMPHASIS, seq(alias($._strikethrough_open, $.emphasis_delimiter), optional($._last_token_punctuation), $['_inline' + '_no_tilde' + suffix_link], alias($._strikethrough_close, $.emphasis_delimiter)));
|
|
453
|
+
}
|
|
454
|
+
grammar.rules['_emphasis_star' + suffix_link] = $ => prec.dynamic(PRECEDENCE_LEVEL_EMPHASIS, seq(alias($._emphasis_open_star, $.emphasis_delimiter), optional($._last_token_punctuation), $['_inline' + '_no_star' + suffix_link], alias($._emphasis_close_star, $.emphasis_delimiter)));
|
|
455
|
+
grammar.rules['_strong_emphasis_star' + suffix_link] = $ => prec.dynamic(2 * PRECEDENCE_LEVEL_EMPHASIS, seq(alias($._emphasis_open_star, $.emphasis_delimiter), $['_emphasis_star' + suffix_link], alias($._emphasis_close_star, $.emphasis_delimiter)));
|
|
456
|
+
grammar.rules['_emphasis_underscore' + suffix_link] = $ => prec.dynamic(PRECEDENCE_LEVEL_EMPHASIS, seq(alias($._emphasis_open_underscore, $.emphasis_delimiter), optional($._last_token_punctuation), $['_inline' + '_no_underscore' + suffix_link], alias($._emphasis_close_underscore, $.emphasis_delimiter)));
|
|
457
|
+
grammar.rules['_strong_emphasis_underscore' + suffix_link] = $ => prec.dynamic(2 * PRECEDENCE_LEVEL_EMPHASIS, seq(alias($._emphasis_open_underscore, $.emphasis_delimiter), $['_emphasis_underscore' + suffix_link], alias($._emphasis_close_underscore, $.emphasis_delimiter)));
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
let old = grammar.conflicts
|
|
461
|
+
grammar.conflicts = $ => {
|
|
462
|
+
let cs = old($);
|
|
463
|
+
for (let conflict of conflicts) {
|
|
464
|
+
let c = [];
|
|
465
|
+
for (let rule of conflict) {
|
|
466
|
+
c.push($[rule]);
|
|
467
|
+
}
|
|
468
|
+
cs.push(c);
|
|
469
|
+
}
|
|
470
|
+
return cs;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
return grammar;
|
|
474
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
; From nvim-treesitter/nvim-treesitter
|
|
2
|
+
[
|
|
3
|
+
(code_span)
|
|
4
|
+
(link_title)
|
|
5
|
+
] @text.literal
|
|
6
|
+
|
|
7
|
+
[
|
|
8
|
+
(emphasis_delimiter)
|
|
9
|
+
(code_span_delimiter)
|
|
10
|
+
] @punctuation.delimiter
|
|
11
|
+
|
|
12
|
+
(emphasis) @text.emphasis
|
|
13
|
+
|
|
14
|
+
(strong_emphasis) @text.strong
|
|
15
|
+
|
|
16
|
+
[
|
|
17
|
+
(link_destination)
|
|
18
|
+
(uri_autolink)
|
|
19
|
+
] @text.uri
|
|
20
|
+
|
|
21
|
+
[
|
|
22
|
+
(link_label)
|
|
23
|
+
(link_text)
|
|
24
|
+
(image_description)
|
|
25
|
+
] @text.reference
|
|
26
|
+
|
|
27
|
+
[
|
|
28
|
+
(backslash_escape)
|
|
29
|
+
(hard_line_break)
|
|
30
|
+
] @string.escape
|
|
31
|
+
|
|
32
|
+
(image
|
|
33
|
+
[
|
|
34
|
+
"!"
|
|
35
|
+
"["
|
|
36
|
+
"]"
|
|
37
|
+
"("
|
|
38
|
+
")"
|
|
39
|
+
] @punctuation.delimiter)
|
|
40
|
+
|
|
41
|
+
(inline_link
|
|
42
|
+
[
|
|
43
|
+
"["
|
|
44
|
+
"]"
|
|
45
|
+
"("
|
|
46
|
+
")"
|
|
47
|
+
] @punctuation.delimiter)
|
|
48
|
+
|
|
49
|
+
(shortcut_link
|
|
50
|
+
[
|
|
51
|
+
"["
|
|
52
|
+
"]"
|
|
53
|
+
] @punctuation.delimiter)
|
|
54
|
+
|
|
55
|
+
; NOTE: extension not enabled by default
|
|
56
|
+
; (wiki_link ["[" "|" "]"] @punctuation.delimiter)
|