3
3
// the grammar as a String instead of a RegExp.
4
4
// - Rule Order: Tree-sitter will prefer the token that appears earlier in the
5
5
// grammar.
6
- //
6
+ // - Visibility: Prefer JS regex (/\n/) over literals ('\n') unless it should be
7
+ // exposed to queries as an anonymous node.
7
8
// https://tree-sitter.github.io/tree-sitter/creating-parsers
8
9
// - Rules starting with underscore are hidden in the syntax tree.
9
10
@@ -16,6 +17,11 @@ const _li_token = /[-•][ ]+/;
16
17
module . exports = grammar ( {
17
18
name : 'vimdoc' ,
18
19
20
+ conflicts : $ => [
21
+ [ $ . _line_noli , $ . _column_heading ] ,
22
+ [ $ . _column_heading ] ,
23
+ ] ,
24
+
19
25
extras : ( ) => [ / [ \t ] / ] ,
20
26
21
27
// inline: ($) => [
@@ -135,14 +141,14 @@ module.exports = grammar({
135
141
'>' ,
136
142
choice (
137
143
alias ( token . immediate ( / [ a - z 0 - 9 ] + \n / ) , $ . language ) ,
138
- token . immediate ( '\n' ) ) ,
144
+ token . immediate ( / \n / ) ) ,
139
145
alias ( repeat1 ( alias ( $ . line_code , $ . line ) ) , $ . code ) ,
140
146
// Codeblock ends if a line starts with non-whitespace.
141
147
// Terminating "<" is consumed in other rules.
142
148
) ) ,
143
149
144
150
// Lines.
145
- _blank : ( ) => field ( 'blank' , '\n' ) ,
151
+ _blank : ( ) => field ( 'blank' , / \n / ) ,
146
152
line : ( $ ) => choice (
147
153
$ . column_heading ,
148
154
$ . h1 ,
@@ -156,18 +162,18 @@ module.exports = grammar({
156
162
optional ( token . immediate ( '<' ) ) , // Treat codeblock-terminating "<" as whitespace.
157
163
_li_token ,
158
164
choice (
159
- alias ( seq ( repeat1 ( $ . _atom ) , '\n' ) , $ . line ) ,
165
+ alias ( seq ( repeat1 ( $ . _atom ) , / \n / ) , $ . line ) ,
160
166
seq ( alias ( repeat1 ( $ . _atom ) , $ . line ) , $ . codeblock ) ,
161
167
) ,
162
168
repeat ( alias ( $ . _line_noli , $ . line ) ) ,
163
169
) ) ,
164
170
// Codeblock lines: must be indented by at least 1 space/tab.
165
171
// Line content (incl. whitespace) is captured as a single atom.
166
- line_code : ( ) => choice ( '\n' , / [ \t ] + [ ^ \n ] + \n / ) ,
172
+ line_code : ( ) => choice ( / \n / , / [ \t ] + [ ^ \n ] + \n / ) ,
167
173
_line_noli : ( $ ) => seq (
168
174
choice ( $ . _atom_noli , $ . _uppercase_words ) ,
169
175
repeat ( $ . _atom ) ,
170
- choice ( $ . codeblock , '\n' )
176
+ choice ( $ . codeblock , / \n / )
171
177
) ,
172
178
173
179
// Modeline: must start with "vim:" (optionally preceded by whitespace)
@@ -177,31 +183,38 @@ module.exports = grammar({
177
183
// Intended for table column names per `:help help-writing`.
178
184
// TODO: children should be $.word (plaintext), not $.atom.
179
185
column_heading : ( $ ) => seq (
180
- field ( 'name' , seq ( choice ( $ . _atom_noli , $ . _uppercase_words ) , repeat ( $ . _atom ) ) ) ,
181
- '~' ,
182
- token . immediate ( '\n' ) ,
186
+ alias ( $ . _column_heading , $ . heading ) ,
187
+ alias ( '~' , $ . delimiter ) ,
188
+ token . immediate ( / \n / ) ,
183
189
) ,
190
+ // aliasing a seq exposes every item separately: create hidden rule and alias that
191
+ _column_heading : $ => prec . dynamic ( 1 , seq (
192
+ choice ( $ . _atom_noli , $ . _uppercase_words ) ,
193
+ repeat ( $ . _atom )
194
+ ) ) ,
184
195
185
196
h1 : ( $ ) =>
186
- seq (
187
- token . immediate ( field ( 'delimiter' , / = = = = = = = = = = = = + [ \t ] * \n / ) ) ,
188
- repeat1 ( $ . _atom ) ,
189
- '\n' ,
190
- ) ,
197
+ prec ( 1 , seq (
198
+ alias ( token . immediate ( / = = = = = = = = = = = = + [ \t ] * \n / ) , $ . delimiter ) ,
199
+ alias ( repeat1 ( $ . _atom ) , $ . heading ) ,
200
+ optional ( seq ( $ . tag , repeat ( $ . _atom ) ) ) ,
201
+ / \n / ,
202
+ ) ) ,
191
203
192
204
h2 : ( $ ) =>
193
- seq (
194
- token . immediate ( field ( 'delimiter' , / - - - - - - - - - - - - + [ \t ] * \n / ) ) ,
195
- repeat1 ( $ . _atom ) ,
196
- '\n' ,
197
- ) ,
205
+ prec ( 1 , seq (
206
+ alias ( token . immediate ( / - - - - - - - - - - - - + [ \t ] * \n / ) , $ . delimiter ) ,
207
+ alias ( repeat1 ( $ . _atom ) , $ . heading ) ,
208
+ optional ( seq ( $ . tag , repeat ( $ . _atom ) ) ) ,
209
+ / \n / ,
210
+ ) ) ,
198
211
199
212
// Heading 3: UPPERCASE NAME, followed by optional *tags*.
200
213
h3 : ( $ ) =>
201
214
seq (
202
- field ( 'name' , $ . uppercase_name ) ,
215
+ alias ( $ . uppercase_name , $ . heading ) ,
203
216
optional ( seq ( $ . tag , repeat ( $ . _atom ) ) ) ,
204
- '\n' ,
217
+ / \n / ,
205
218
) ,
206
219
207
220
tag : ( $ ) => _word ( $ ,
0 commit comments