Skip to content

Commit 87525af

Browse files
committed
fix: headings after implicitly-terminated codeblock
Problem: `block` has no way to terminate just after an implicitly-terminated `codeblock`, so the next line is always parsed as a plain `line` instead of a heading (h1/h2/h3). Because headings and `block` both are top-level forms, this prevents headings from being recognized in this case. Solution: Change headings (h1/h2/h3) to be contained by `line`. They are no longer top-level.
1 parent 443f2f5 commit 87525af

File tree

6 files changed

+104
-52
lines changed

6 files changed

+104
-52
lines changed

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ Overview
1818
- `block` is the main top-level node which contains `line` nodes.
1919
- ends at blank line(s) or a line starting with `<`.
2020
- `line`:
21-
- contains atoms (words, tags, taglinks, …).
21+
- contains atoms (words, tags, taglinks, …)
2222
- contains `codeblock` because `>` can start a codeblock at the end of a line.
23+
- contains headings (`h1`, `h2`, `h3`) because `codeblock` terminated by
24+
"implicit stop" (no terminating `<`) consumes blank lines, so `block` has
25+
no way to end.
2326
- contains `column_heading` because `<` (the `codeblock` terminating char)
24-
can appear at the start of a `column_heading`.
27+
can appear at the start of `column_heading`.
2528
- `codeblock`:
2629
- contains `line` nodes which do not contain `word` nodes, it's just the full
2730
raw text line including whitespace. This is somewhat dictated by its
@@ -39,8 +42,6 @@ Known issues
3942
- Spec requires that `codeblock` delimiter ">" must be preceded by a space
4043
(" >"), not a tab. But currently the grammar doesn't enforce this. Example:
4144
`:help lcs-tab`.
42-
- `codeblock` terminated by an "implicit stop" (no terminating `<`) consumes
43-
blank lines, preventing top-level forms like `h1` from being recognized.
4445
- `url` doesn't handle _surrounding_ parens. E.g. `(https://example.com/#yay)` yields `word`
4546
- `url` doesn't handle _nested_ parens. E.g. `(https://example.com/(foo)#yay)`
4647

corpus/codeblock.txt

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -93,20 +93,28 @@ text
9393
(word))))
9494

9595
================================================================================
96-
codeblock with implicit stop (FIXME)
96+
codeblock with implicit stop
9797
================================================================================
9898
>
9999
line1
100100
line2
101101

102-
-------------------------------
102+
===============================
103103
h1-headline *foo*
104104
line1
105105

106106
line2
107107

108+
>
109+
line1
110+
108111
-------------------------------
109-
h1-headline *foo*
112+
h2-headline *foo*
113+
114+
>
115+
line1
116+
117+
H3 HEADLINE *foo*
110118

111119
--------------------------------------------------------------------------------
112120

@@ -118,20 +126,35 @@ h1-headline *foo*
118126
(line)
119127
(line)))
120128
(line
121-
(word))
122-
(line
123-
(word)
124-
(tag
125-
(word)))
129+
(h1
130+
(word)
131+
(tag
132+
(word))))
126133
(line
127134
(word)))
128135
(block
129136
(line
130137
(word)))
131-
(h2
132-
(word)
133-
(tag
134-
(word))))
138+
(block
139+
(line
140+
(codeblock
141+
(line)
142+
(line)))
143+
(line
144+
(h2
145+
(word)
146+
(tag
147+
(word)))))
148+
(block
149+
(line
150+
(codeblock
151+
(line)
152+
(line)))
153+
(line
154+
(h3
155+
(uppercase_name)
156+
(tag
157+
(word))))))
135158

136159
================================================================================
137160
codeblock with empty lines

corpus/heading1_2.txt

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,24 @@ Text2
1515
--------------------------------------------------------------------------------
1616

1717
(help_file
18-
(h1
19-
(word)
20-
(tag
21-
(word)))
18+
(block
19+
(line
20+
(h1
21+
(word)
22+
(tag
23+
(word)))))
2224
(block
2325
(line
2426
(word)))
25-
(h2
26-
(word)
27-
(word)
28-
(tag
29-
(word))
30-
(tag
31-
(word)))
27+
(block
28+
(line
29+
(h2
30+
(word)
31+
(word)
32+
(tag
33+
(word))
34+
(tag
35+
(word)))))
3236
(block
3337
(line
3438
(word))))
@@ -50,19 +54,23 @@ Text
5054
--------------------------------------------------------------------------------
5155

5256
(help_file
53-
(h1
54-
(tag
55-
(word))
56-
(word)
57-
(word))
57+
(block
58+
(line
59+
(h1
60+
(tag
61+
(word))
62+
(word)
63+
(word))))
5864
(block
5965
(line
6066
(word)))
61-
(h2
62-
(tag
63-
(word))
64-
(word)
65-
(word))
67+
(block
68+
(line
69+
(h2
70+
(tag
71+
(word))
72+
(word)
73+
(word))))
6674
(block
6775
(line
6876
(word))))

corpus/heading3-column_heading.txt

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ Text
1010
--------------------------------------------------------------------------------
1111

1212
(help_file
13-
(h3
14-
(uppercase_name))
13+
(block
14+
(line
15+
(h3
16+
(uppercase_name))))
1517
(block
1618
(line
1719
(word)))
@@ -31,8 +33,10 @@ HELLO WORLD
3133
--------------------------------------------------------------------------------
3234

3335
(help_file
34-
(h3
35-
(uppercase_name))
36+
(block
37+
(line
38+
(h3
39+
(uppercase_name))))
3640
(block
3741
(line
3842
(word))))
@@ -46,10 +50,12 @@ Test
4650
--------------------------------------------------------------------------------
4751

4852
(help_file
49-
(h3
50-
(uppercase_name)
51-
(tag
52-
(word)))
53+
(block
54+
(line
55+
(h3
56+
(uppercase_name)
57+
(tag
58+
(word)))))
5359
(block
5460
(line
5561
(word))))

corpus/optionlink.txt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,29 @@ number: '04' 'ISO-10646-1' 'python3'
8787
(word))))
8888

8989
================================================================================
90-
NOT optionlink (FIXME)
90+
NOT optionlink 2 (FIXME)
9191
================================================================================
9292

9393
'{a-z} `{a-z} Jump to the mark.
94+
x
9495

9596
--------------------------------------------------------------------------------
9697

9798
(help_file
9899
(ERROR))
100+
101+
================================================================================
102+
NOT optionlink 3 (FIXME)
103+
================================================================================
104+
foo '"\ '. Notice
105+
|foo|
106+
107+
--------------------------------------------------------------------------------
108+
109+
(help_file
110+
(block
111+
(line
112+
(word)
113+
(word
114+
(ERROR)
115+
(MISSING "'")))))

grammar.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ module.exports = grammar({
1818
repeat(/[\t ]*\n/), // Eat whitespace at top of file.
1919
repeat(choice(
2020
$.block,
21-
$.h1,
22-
$.h2,
23-
$.h3,
2421
)),
2522
// Last block may not be followed by a blank line or EOL.
2623
optional(alias($.block_end, $.block)),
@@ -123,15 +120,13 @@ module.exports = grammar({
123120
token.immediate(field('delimiter', /============+[\t ]*\n/)),
124121
repeat1($._atom),
125122
'\n',
126-
repeat($._blank),
127123
),
128124

129125
h2: ($) =>
130126
seq(
131127
token.immediate(field('delimiter', /------------+[\t ]*\n/)),
132128
repeat1($._atom),
133129
'\n',
134-
repeat($._blank),
135130
),
136131

137132
// Heading 3: UPPERCASE NAME, followed by optional *tags*.
@@ -140,7 +135,6 @@ module.exports = grammar({
140135
field('name', $.uppercase_name),
141136
repeat($.tag),
142137
'\n',
143-
repeat($._blank),
144138
),
145139

146140
tag: ($) => _word($,
@@ -187,6 +181,9 @@ function _line($, require_eol) {
187181
const eol = require_eol ? '\n' : optional('\n');
188182
return choice(
189183
$.column_heading,
184+
$.h1,
185+
$.h2,
186+
$.h3,
190187
seq(optional($.uppercase_words), repeat($._atom), $.codeblock),
191188
seq(optional($.uppercase_words), repeat1($._atom), choice($.codeblock, eol)),
192189
);

0 commit comments

Comments
 (0)