44// - Rule Order: Tree-sitter will prefer the token that appears earlier in the
55// grammar.
66//
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.
810// - Rules starting with underscore are hidden in the syntax tree.
911
1012/// <reference types="tree-sitter-cli/dsl" />
@@ -16,6 +18,11 @@ const _li_token = /[-•][ ]+/;
1618module . exports = grammar ( {
1719 name : 'vimdoc' ,
1820
21+ conflicts : $ => [
22+ [ $ . _line_noli , $ . _column_heading ] ,
23+ [ $ . _column_heading ] ,
24+ ] ,
25+
1926 extras : ( ) => [ / [ \t ] / ] ,
2027
2128 // inline: ($) => [
@@ -135,14 +142,14 @@ module.exports = grammar({
135142 '>' ,
136143 choice (
137144 alias ( token . immediate ( / [ a - z 0 - 9 ] + \n / ) , $ . language ) ,
138- token . immediate ( '\n' ) ) ,
145+ token . immediate ( / \n / ) ) ,
139146 alias ( repeat1 ( alias ( $ . line_code , $ . line ) ) , $ . code ) ,
140147 // Codeblock ends if a line starts with non-whitespace.
141148 // Terminating "<" is consumed in other rules.
142149 ) ) ,
143150
144151 // Lines.
145- _blank : ( ) => field ( 'blank' , '\n' ) ,
152+ _blank : ( ) => field ( 'blank' , / \n / ) ,
146153 line : ( $ ) => choice (
147154 $ . column_heading ,
148155 $ . h1 ,
@@ -156,18 +163,18 @@ module.exports = grammar({
156163 optional ( token . immediate ( '<' ) ) , // Treat codeblock-terminating "<" as whitespace.
157164 _li_token ,
158165 choice (
159- alias ( seq ( repeat1 ( $ . _atom ) , '\n' ) , $ . line ) ,
166+ alias ( seq ( repeat1 ( $ . _atom ) , / \n / ) , $ . line ) ,
160167 seq ( alias ( repeat1 ( $ . _atom ) , $ . line ) , $ . codeblock ) ,
161168 ) ,
162169 repeat ( alias ( $ . _line_noli , $ . line ) ) ,
163170 ) ) ,
164171 // Codeblock lines: must be indented by at least 1 space/tab.
165172 // 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 / ) ,
167174 _line_noli : ( $ ) => seq (
168175 choice ( $ . _atom_noli , $ . _uppercase_words ) ,
169176 repeat ( $ . _atom ) ,
170- choice ( $ . codeblock , '\n' )
177+ choice ( $ . codeblock , / \n / )
171178 ) ,
172179
173180 // Modeline: must start with "vim:" (optionally preceded by whitespace)
@@ -177,31 +184,38 @@ module.exports = grammar({
177184 // Intended for table column names per `:help help-writing`.
178185 // TODO: children should be $.word (plaintext), not $.atom.
179186 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 / ) ,
183190 ) ,
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+ ) ) ,
184196
185197 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+ ) ) ,
191204
192205 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+ ) ) ,
198212
199213 // Heading 3: UPPERCASE NAME, followed by optional *tags*.
200214 h3 : ( $ ) =>
201215 seq (
202- field ( 'name' , $ . uppercase_name ) ,
216+ alias ( $ . uppercase_name , $ . heading ) ,
203217 optional ( seq ( $ . tag , repeat ( $ . _atom ) ) ) ,
204- '\n' ,
218+ / \n / ,
205219 ) ,
206220
207221 tag : ( $ ) => _word ( $ ,
0 commit comments