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