Skip to content

Commit 052e44f

Browse files
feat: Add support for footnotes
AI assisted: Copilot
1 parent 3633106 commit 052e44f

10 files changed

Lines changed: 54863 additions & 41965 deletions

File tree

examples/queries/highlights.scm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343

4444
; Like OrgProperty, easy to choose how the '[fn:LABEL] DESCRIPTION' are highlighted
4545
(fndef label: (expr) @OrgFootnoteLabel (description) @OrgFootnoteDescription) @OrgFootnoteDefinition
46+
(fnref label: (expr) @OrgFootnoteLabel) @OrgFootnoteReference
4647

4748
; Again like OrgProperty to change the styling of '#+' and ':'. Note that they
4849
; can also be added in the query directly as anonymous nodes to style differently.

grammar.js

Lines changed: 92 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ const org_grammar = {
1515
$._stars,
1616
$._sectionend,
1717
$._eof, // Basically just '\0', but allows multiple to be matched
18+
$._paragraph_continue,
19+
$._fndef_continue,
20+
$._fndef_stop,
1821
$._link_open,
1922
$.latex_math_single_dollar,
2023
$.text_dollar,
@@ -42,17 +45,18 @@ const org_grammar = {
4245

4346
[$._tag_expr_start, $.expr],
4447

45-
// _multiline_text • ':' …
48+
// inline multiline text • ':' …
4649
// Is the ':' continued multiline text or is it a drawer?
4750
[$.paragraph],
48-
[$.fndef],
4951
// ':' 'str' …
5052
// Continue the conflict from above
5153
[$.expr, $.drawer],
5254

5355
// headline 'entry_token1' ':' • '<' …
5456
[$.entry, $.expr],
55-
[$.entry, $._markup],
57+
[$.entry, $._inline_markup],
58+
[$.entry, $._paragraph_start_markup],
59+
[$._inline_markup, $._paragraph_start_markup],
5660
],
5761

5862
rules: {
@@ -63,7 +67,24 @@ const org_grammar = {
6367
),
6468

6569
// Set up to prevent lexing conflicts of having two paragraphs in a row
66-
body: $ => $._body_contents,
70+
body: $ => $._top_body_contents,
71+
72+
_top_body_contents: $ => choice(
73+
repeat1($._nl),
74+
seq(repeat($._nl), $._top_multis),
75+
seq(
76+
repeat($._nl),
77+
repeat1(seq(
78+
choice(
79+
seq($._top_multis, $._nl),
80+
seq($.fndef, $.fndef),
81+
seq(optional(choice(alias($._top_paragraph, $.paragraph), $.fndef)), $._element),
82+
),
83+
repeat($._nl),
84+
)),
85+
optional($._top_multis)
86+
),
87+
),
6788

6889
_body_contents: $ => choice(
6990
repeat1($._nl),
@@ -73,6 +94,7 @@ const org_grammar = {
7394
repeat1(seq(
7495
choice(
7596
seq($._multis, $._nl),
97+
seq($.fndef, $.fndef),
7698
seq(optional(choice($.paragraph, $.fndef)), $._element),
7799
),
78100
repeat($._nl),
@@ -81,6 +103,12 @@ const org_grammar = {
81103
),
82104
),
83105

106+
_top_multis: $ => choice(
107+
alias($._top_paragraph, $.paragraph),
108+
$._directive_list,
109+
$.fndef,
110+
),
111+
84112
link: $ => seq(
85113
alias($._link_open, '[['),
86114
field('url', repeat(alias($._expr_with_space, $.expr))),
@@ -172,9 +200,9 @@ const org_grammar = {
172200
),
173201

174202
item: $ => choice(
175-
seq($.expr, field('priority', $.priority), repeat1($._markup)),
176-
seq(field('priority', $.priority), repeat($._markup)),
177-
repeat1($._markup)
203+
seq($.expr, field('priority', $.priority), repeat1($._inline_markup)),
204+
seq(field('priority', $.priority), repeat($._inline_markup)),
205+
repeat1($._inline_markup)
178206
),
179207

180208
tag_list: $ => prec.dynamic(1, seq(
@@ -240,17 +268,24 @@ const org_grammar = {
240268
alias(prec(-1, /[^\[<\]>\p{Z}\t\n\r]+/), $.expr),
241269
),
242270

243-
paragraph: $ => seq(optional($._directive_list), $._multiline_text),
271+
paragraph: $ => seq(optional($._directive_list), $._inline_multiline_text),
272+
_top_paragraph: $ => seq(optional($._directive_list), $._top_paragraph_text),
244273

245-
fndef: $ => seq(
274+
fndef: $ => prec.dynamic(10, prec.right(1, seq(
246275
optional($._directive_list),
247276
seq(
248277
alias(/\[fn:/i, '[fn:'),
249278
field('label', alias(/[^\p{Z}\t\n\r\]]+/, $.expr)),
250279
']',
251280
),
252-
field('description', alias($._multiline_text, $.description))
253-
),
281+
optional(field('description', alias($._fndef_multiline_text, $.description)))
282+
))),
283+
284+
fnref: $ => prec(-1, seq(
285+
alias(/\[fn:/i, '[fn:'),
286+
field('label', alias(/[^\p{Z}\t\n\r\]]+/, $.expr)),
287+
']',
288+
)),
254289

255290
_directive_list: $ => repeat1(field('directive', $.directive)),
256291
directive: $ => seq(
@@ -393,13 +428,54 @@ const org_grammar = {
393428
_nl: _ => choice('\n', '\r'),
394429
_eol: $ => choice('\n', '\r', $._eof),
395430

396-
_expr_line: $ => repeat1($._markup),
397-
_multiline_text: $ => repeat1(seq(
398-
repeat1($._markup),
399-
$._eol
431+
_expr_line: $ => repeat1($._inline_markup),
432+
_inline_multiline_text: $ => repeat1(seq(
433+
repeat1($._inline_markup),
434+
$._eol,
400435
)),
436+
_top_paragraph_text: $ => prec.right(seq(
437+
repeat1($._paragraph_start_markup),
438+
repeat($._inline_markup),
439+
repeat(seq(
440+
$._paragraph_continue,
441+
repeat1($._inline_markup),
442+
)),
443+
$._eol,
444+
)),
445+
446+
_fndef_multiline_text: $ => seq(
447+
repeat1($._fndef_markup),
448+
repeat(seq(
449+
$._fndef_continue,
450+
repeat1($._fndef_markup),
451+
)),
452+
choice($._fndef_stop, $._eof),
453+
),
454+
455+
_inline_markup: $ => choice(
456+
$.expr,
457+
$.inline_code_block,
458+
$.inline_math_block,
459+
$.display_math_block,
460+
$.link,
461+
$.link_desc,
462+
$.fnref,
463+
$.timestamp,
464+
$.citation,
465+
),
466+
467+
_paragraph_start_markup: $ => choice(
468+
$.expr,
469+
$.inline_code_block,
470+
$.inline_math_block,
471+
$.display_math_block,
472+
$.link,
473+
$.link_desc,
474+
$.timestamp,
475+
$.citation,
476+
),
401477

402-
_markup: $ => choice(
478+
_fndef_markup: $ => choice(
403479
$.expr,
404480
$.inline_code_block,
405481
$.inline_math_block,

0 commit comments

Comments
 (0)