Skip to content

Commit e7c5565

Browse files
committed
feat: numbered listitems
1 parent 570dc10 commit e7c5565

File tree

6 files changed

+371
-282
lines changed

6 files changed

+371
-282
lines changed

README.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,25 @@ Overview
1414

1515
- `block` is the main top-level node, delimited by blank line(s) or any line
1616
starting with `<` (codeblock terminator).
17-
- contains `line` and `line_li` nodes.
17+
- Contains `line` and `line_li` nodes.
1818
- `line`:
19-
- contains atoms (words, tags, taglinks, …)
20-
- contains headings (`h1`, `h2`, `h3`, `column_heading`) because `codeblock`
19+
- Contains atoms (words, tags, taglinks, …)
20+
- Contains headings (`h1`, `h2`, `h3`, `column_heading`) because `codeblock`
2121
terminated by "implicit stop" (no terminating `<`) consumes blank lines, so
2222
`block` has no way to end.
2323
- `line_li` ("listitem")
24-
- lines starting with `-`/`` (_not_ `+`/`*`) are listitems.
25-
- consumes lines until blank line, codeblock, or next listitem.
26-
- nesting is ignored: indented listitems are parsed as siblings.
24+
- Lines starting with `-`/`` (_not_ `+`/`*`) are listitems.
25+
- Consumes lines until blank line, codeblock, or next listitem.
26+
- Nesting is ignored: indented listitems are parsed as siblings. Consumers can
27+
check leading whitespace to decide nesting.
2728
- `codeblock`:
28-
- contained by `line` or `line_li`, because ">" can start a codeblock at the
29+
- Contained by `line` or `line_li`, because ">" can start a codeblock at the
2930
end of any line.
30-
- contains `line` nodes without `word` nodes: it's just the full raw text
31+
- Contains `line` nodes without `word` nodes: it's just the full raw text
3132
line including whitespace. This is somewhat dictated by its "preformatted"
3233
nature; parsing the contents would require loading a "child" language
3334
(injection). See [#2](https://github.com/neovim/tree-sitter-vimdoc/issues/2).
34-
- the terminating `<` (and any following whitespace) is discarded (anonymous).
35+
- The terminating `<` (and any following whitespace) is discarded (anonymous).
3536
- `url` intentionally does not capture `.,)` at the end of the URL. See also [Known issues](#known-issues).
3637
- `h1` = "Heading 1": `======` followed by text and optional `*tags*`.
3738
- `h2` = "Heading 2": `------` followed by text and optional `*tags*`.

grammar.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313
// @ts-check
1414

1515
const _uppercase_word = /[A-Z0-9.()][-A-Z0-9.()_]+/;
16+
// List-item.
1617
const _li_token = /[-][ ]+/;
18+
// Numbered list-item.
19+
const _num_li_token = /[0-9]{1,3}\.[ ]+/;
1720

1821
module.exports = grammar({
1922
name: 'vimdoc',
@@ -49,9 +52,10 @@ module.exports = grammar({
4952
alias($.word_noli, $.word),
5053
$._atom_common,
5154
),
55+
// Word NOT matching (numbered) listitem.
5256
word_noli: ($) => choice(
53-
// Lines contained by line_li must not start with a listitem symbol.
54-
token(prec(-1, /[^-\n\t ][^(\[\n\t ]*/)),
57+
// Lines contained by line_li must not start with (numbered) listitem symbol.
58+
token(prec(-1, /(([^-\n\t ])|([^0-9\n\t ][^.\n\t ]))[^.(\[\n\t ]*/)),
5559
token(prec(-1, /[-][^\n\t ]+/)),
5660
$._word_common,
5761
),
@@ -132,7 +136,8 @@ module.exports = grammar({
132136
choice(
133137
repeat1($.line),
134138
repeat1($.line_li),
135-
seq(repeat1($.line), repeat1($.line_li)),
139+
repeat1($.line_li_num),
140+
seq(repeat1($.line), repeat1(choice($.line_li, $.line_li_num))),
136141
),
137142
choice(
138143
token.immediate('<'), // Treat codeblock-terminating "<" as whitespace.
@@ -171,6 +176,16 @@ module.exports = grammar({
171176
),
172177
repeat(alias($._line_noli, $.line)),
173178
)),
179+
// Numbered listitem: consumes prefixed line and all adjacent non-prefixed lines.
180+
line_li_num: ($) => prec.right(1, seq(
181+
optional(token.immediate('<')), // Treat codeblock-terminating "<" as whitespace.
182+
_num_li_token,
183+
choice(
184+
alias(seq(repeat1($._atom), /\n/), $.line),
185+
seq(alias(repeat1($._atom), $.line), $.codeblock),
186+
),
187+
repeat(alias($._line_noli, $.line)),
188+
)),
174189
// Codeblock lines: must be indented by at least 1 space/tab.
175190
// Line content (incl. whitespace) is captured as a single atom.
176191
line_code: () => choice(/\n/, /[\t ]+[^\n]+\n/),

test/corpus/arguments.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,16 @@ nvim_buf_detach_event[{buf}]
8686
(word))
8787
(word))
8888
(line
89+
(word)
90+
(word)
8991
(word)
9092
(word)
9193
(argument
9294
(word))
9395
(word))
9496
(line
97+
(word)
98+
(word)
9599
(word)
96100
(word)
97101
(argument

test/corpus/heading3-column_heading.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ column_heading should NOT parse atoms (links, tags, etc.) (FIXME)
187187
(delimiter))))
188188
(block
189189
(line
190+
(word)
190191
(word))))
191192

192193
================================================================================

test/corpus/line_block.txt

Lines changed: 0 additions & 270 deletions
Original file line numberDiff line numberDiff line change
@@ -77,273 +77,3 @@ block2 text text
7777
(word)
7878
(word))))
7979

80-
================================================================================
81-
listitems
82-
================================================================================
83-
- list1.a item1
84-
- - •
85-
• word,
86-
!foo! ~bar. word word
87-
'item' line3 |foo|
88-
- x 'list1.a' ~/foo/bar.txt
89-
li continues
90-
- {nested} here
91-
92-
• 'list2' item w3
93-
- *nested_li* word *tag2*
94-
• list2 item w3
95-
- nested_li-2
96-
foo
97-
foo
98-
99-
100-
--------------------------------------------------------------------------------
101-
102-
(help_file
103-
(block
104-
(line_li
105-
(line
106-
(word)
107-
(word)
108-
(word)
109-
(word))
110-
(line))
111-
(line_li
112-
(line
113-
(word)
114-
(word))
115-
(line))
116-
(line_li
117-
(line
118-
(word)
119-
(word))
120-
(line)
121-
(line
122-
(word)
123-
(word)
124-
(word)
125-
(word)
126-
(word)
127-
(word))
128-
(line
129-
(optionlink
130-
(word))
131-
(word)
132-
(taglink
133-
(word))))
134-
(line_li
135-
(line
136-
(word)
137-
(word)
138-
(word)
139-
(word)
140-
(word)
141-
(word)
142-
(word)
143-
(word))
144-
(line)
145-
(line
146-
(word)
147-
(word)))
148-
(line_li
149-
(line
150-
(argument
151-
(word))
152-
(word))
153-
(line)))
154-
(block
155-
(line_li
156-
(line
157-
(word)
158-
(word)
159-
(word))
160-
(line))
161-
(line_li
162-
(line
163-
(tag
164-
(word))
165-
(word)
166-
(tag
167-
(word)))
168-
(line))
169-
(line_li
170-
(line
171-
(word)
172-
(word)
173-
(word))
174-
(line))
175-
(line_li
176-
(line
177-
(word))
178-
(line)
179-
(line
180-
(word))
181-
(line
182-
(word)))))
183-
184-
================================================================================
185-
listitem with codeblock
186-
================================================================================
187-
188-
• list1.a item1 >
189-
foo
190-
< • list1.b item1
191-
• w1 w2
192-
w3 >
193-
code1 {
194-
code2
195-
}
196-
<• w1
197-
• w2 w3
198-
`item2` line2
199-
{item2} line3
200-
201-
202-
--------------------------------------------------------------------------------
203-
204-
(help_file
205-
(block
206-
(line_li
207-
(line
208-
(word)
209-
(word)
210-
(word)
211-
(word))
212-
(codeblock
213-
(code
214-
(line))))
215-
(line_li
216-
(line
217-
(word)
218-
(word)
219-
(word)
220-
(word))
221-
(line))
222-
(line_li
223-
(line
224-
(word)
225-
(word))
226-
(line)
227-
(line
228-
(word)
229-
(codeblock
230-
(code
231-
(line)
232-
(line)
233-
(line)))))
234-
(line_li
235-
(line
236-
(word))
237-
(line))
238-
(line_li
239-
(line
240-
(word)
241-
(word))
242-
(line)
243-
(line
244-
(codespan
245-
(word))
246-
(word))
247-
(line
248-
(argument
249-
(word))
250-
(word)))))
251-
252-
================================================================================
253-
listitems + lines without blank lines
254-
================================================================================
255-
256-
{lines} |readfile()|-style
257-
{type} behavior:
258-
• "b" |blockwise-visual|
259-
• "c" |charwise|
260-
• "l" |linewise|
261-
• "listitem"
262-
{consumes} adjacent
263-
264-
265-
--------------------------------------------------------------------------------
266-
267-
(help_file
268-
(block
269-
(line
270-
(argument
271-
(word))
272-
(taglink
273-
(word))
274-
(word))
275-
(line
276-
(argument
277-
(word))
278-
(word))
279-
(line_li
280-
(line
281-
(word)
282-
(taglink
283-
(word)))
284-
(line))
285-
(line_li
286-
(line
287-
(word)
288-
(taglink
289-
(word)))
290-
(line))
291-
(line_li
292-
(line
293-
(word)
294-
(taglink
295-
(word)))
296-
(line))
297-
(line_li
298-
(line
299-
(word))
300-
(line)
301-
(line
302-
(argument
303-
(word))
304-
(word)))))
305-
306-
================================================================================
307-
listitem tricky
308-
================================================================================
309-
310-
- x - x
311-
312-
-x -x
313-
314-
- - x -x
315-
- -x - x
316-
- -
317-
318-
319-
--------------------------------------------------------------------------------
320-
321-
(help_file
322-
(block
323-
(line_li
324-
(line
325-
(word)
326-
(word)
327-
(word))
328-
(line)))
329-
(block
330-
(line
331-
(word)
332-
(word)))
333-
(block
334-
(line_li
335-
(line
336-
(word)
337-
(word)
338-
(word))
339-
(line))
340-
(line_li
341-
(line
342-
(word)
343-
(word)
344-
(word))
345-
(line))
346-
(line_li
347-
(line
348-
(word))
349-
(line))))

0 commit comments

Comments
 (0)