forked from nvim-neorg/norg-specs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
1.0-specification.norg
1822 lines (1506 loc) · 72.7 KB
/
1.0-specification.norg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
@document.meta
title: The 1.0 Norg Specification
authors: [
vhyrro
mrossinek
]
categories: specifications
version: 1.0
@end
* Norg File Format Specification
This file contains the formal file format specification of the Norg syntax version 1.0.
This document is written in the Norg format in its original form and, thus, attempts to be
self-documenting.
Please note that this is *not* a reference implementation - this is an established rule set that
should be strictly followed.
* Introduction
Before diving into the details we will start with an introduction. The Norg file format was
designed as part of the [Neorg]{https://github.com/nvim-neorg/neorg} plugin for Neovim which was
started by /Vhyrro (@vhyrro)/ in April 2021. Soon after starting this work, /Max Rossmannek
(@mrossinek)/ joined the development team, and, with the help of the [Neorg] community, the two
have shaped the Norg syntax to what it has become today.
** What is Norg?
The Norg syntax is a /structured/ plain-text file format which aims to be human-readable when
viewed standalone while also providing a suite of markup utilities for typesetting structured
documents. Compared to other plain-text file formats like e.g. Markdown, Org, RST or AsciiDoc, it
sets itself apart most notably by following a strict philosophy to abide by the following simple
rules:
~ *Consistency:* the syntax should be consistent. Even if you know only a part of the syntax,
learning new parts should not be surprising and rather feel predictable and intuitive.
~ *Unambiguity:* the syntax should leave _no_ room for ambiguity. This is especially motivated by
the use of [tree-sitter]{https://tree-sitter.github.io/tree-sitter/} for the original syntax
parser, which takes a strict left-to-right parsing approach and only has single-character
look-ahead.
~ *[Free-form]{https://en.wikipedia.org/wiki/Free-form_language}:* whitespace is _only_ used to
delimit tokens but has no other significance! This is probably the most contrasting feature to
other plain-text formats which often adhere to the
[off-side rule]{https://en.wikipedia.org/wiki/Off-side_rule}, meaning that the syntax relies on
whitespace-indentation to carry meaning.
Although built with [Neorg] in mind, Norg can be utilized in a wide range of applications,
from external note-taking plugins to even messaging applications. Thanks to its {* layers}[layer]
system one can choose the feature set they'd like to support and can ignore the higher levels.
* Preliminaries
First, we define some basic concepts which will be used in this specification.
** Characters
A Norg file is made up of /characters/.
A <character> is any Unicode [code point]{https://en.wikipedia.org/wiki/Code_point} or
[grapheme]{https://www.unicode.org/glossary/#grapheme}.
*** Whitespace
A {** characters}[character] is considered *whitespace* if it is any of the following:
- The regular space `U+0020`
- A tab `U+0009`
- Any code point in the
[Unicode Zs general category]{https://www.fileformat.info/info/unicode/category/Zs/list.htm}
Any combination of the above is also considered whitespace.
Tabs are not expanded to spaces and since whitespace has no semantic meaning there is no need
to define a default tab stop. However, if a parser must (for implementation reasons) define a
tab stop, we suggest setting it to 4 spaces.
*** Line Endings
Line endings in Norg serve as a termination character. They are used e.g. to terminate
{** paragraph segments}, {** paragraphs} and other elements like the endings of {** range-able
detached modifiers}. They are not considered {*** whitespace}.
The following chars are considered line endings:
- A line feed `U+000A`
- A form feed `U+000C`
- A carriage return `U+000D`
The following line ending combinations are permitted:
- A single line feed
- A single carriage return
- A carriage return immediately followed by a line feed
*** Punctuation
A {** characters}[character] is considered *punctuation* if it is any of the following:
- A standard ASCII punctuation character: `|!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~|`
- Anything in the general Unicode categories `Pc`, `Pd`, `Pe`, `Pf`, `Pi`, `Po` or `Ps`.
*** Escaping
A single {** characters}[character] can be escaped if it is immediately preceded by a backslash,
`|\|` (`U+005C`). Any {** characters}[character] may be escaped /apart from/ {** characters}
within free-form and ranged verbatim segments (see {** free-form attached modifiers} and
{*** verbatim ranged tags}).
For more information about precedence, take a look at the {* precedence} section.
*** Regular Characters
Any other character not described by the preceding sections is treated as a generic code
point/character.
** Words
The Norg format is designed to be parsed on a word-by-word basis from left-to-right through the
entire document /in a single pass/. This is possible because the language is [free-form], meaning
that whitespace has no semantic meaning, and because the markup follows strict rules which are
outlined in the later sections of this document.
A *word* is considered to be any combination of {** characters} which are neither
{*** whitespace} nor {*** punctuation} (see {*** regular characters}).
** Paragraph Segments
{** Words} are first combined into *paragraph segments*. A paragraph segment may then contain any
inline element of type:
- {* attached modifiers}
- {* linkables}
Usually, a {*** line endings}[line ending] terminates the paragraph segment.
This means that a paragraph segment is for the most part just a line of text:
|example
I am a paragraph segment.
I am another paragraph segment.
Together we form a paragraph.
|end
The exception to the rule is whenever a linkable or attached modifier within the paragraph
segment spans more than a single line, in which case the paragraph segment also spans that
distance. For example:
|example
I *am
a long paragraph segment!*
|end
** Paragraphs
Paragraphs are then formed of consecutive {** paragraph segments}. A paragraph is terminated by:
- A {$ paragraph break}
- Any of the {* detached modifiers}
- Any of the {** delimiting modifiers}
- Any of the {** ranged tags}
- Any of the {*** strong carryover tags}
$ Paragaph Break
A paragraph break is defined as an _empty line_. In the simplest case that means two consecutive
{*** line endings} but since Neorg is a /free-form/ markup language, a line which only contains
whitespace is also considered empty.
* Detached Modifiers
Norg has several detached modifiers. The name originates from their differentiation to the
{* attached modifiers}, which will be discussed later.
All detached modifiers must abide by the following rules:
- A detached modifier can _only_ occur at the beginning of the line (arbitrary {*** whitespace}
(but nothing else!) may precede it)
- A detached modifier must be immediately followed by {*** whitespace} or another detached modifier
of the same type
-- /NOTE/: The only exception to this is for the /closing/ modifier of the
{** range-able detached modifiers}.
The following table outlines all valid *detached modifiers*. It also adds various possible
properties to each category which will be explained in more detail below.
: . : Character
: > : Name
: > : Categories
: _ : `*`
: > : Headings
:: >
- Structural
- Nestable
::
: _ : `-`
: > : Unordered Lists
:: >
- Nestable
::
: _ : `~`
: > : Ordered Lists
:: >
- Nestable
::
: _ : `>`
: > : Quotes
:: >
- Nestable
::
: _ : `$`
: > : Definitions
:: >
- Range-able
::
: _ : `^`
: > : Footnotes
:: >
- Range-able
::
: _ : `:`
: > : Table cells
:: >
- Range-able
::
: _ : `%`
: > : Attributes
:: >
- Nestable
::
** Structural Detached Modifiers
The first detached modifier type is the /structural/ modifier type. As the name suggests,
modifiers under this category *structure* the Norg document in some form or another.
After a structural modifier, one {# paragraph segments}[paragraph segment] is consumed as the
/title/ of the modifier.
A property of structural detached modifiers is that they consume *all* other non-structural
detached modifiers, lower-level structural modifiers, inline markup and {** paragraphs};
they are the most important detached modifier in the hierarchy of modifiers.
To manually terminate a structural detached modifier (like a heading) you must use a
{** delimiting modifiers}[delimiting modifier]. Structural detached modifiers are automatically
closed when you use another structural modifier of the same or lower level.
*** Headings
|example
* Heading level 1
** Heading level 2
*** Heading level 3
**** Heading level 4
***** Heading level 5
****** Heading level 6
******* Heading level 7 (falls back to level 6 in the tree-sitter parser)
|end
Although headings are both structural /and/ nestable (see next section), the former takes
precedence over the latter, meaning that headings only affect a single
{** paragraph segments}[paragraph segment] as their title. This is for user convenience as it
does not require an empty line right below a heading. Because of this precedence, headings are
also non-{** grouping}.
Headings serve as a way to categorize and organize other elements into smaller chunks for better
readability. They are currently the /only/ structural detached modifier present in the Norg
syntax.
** Nestable Detached Modifiers
Nestable detached modifiers are a kind which may be repeated multiple times in order to produce a
_nested_ object of the given type. The nesting levels are capped at 6 in the [tree-sitter] parser
but longer repetitions of the same modifier are allowed, falling back to the sixth nesting level.
Other parsers may choose to support higher (or infinite) nesting levels.
Furthermore, in contrast to most other (standard) {* detached modifiers}, this detached modifier
type has /no/ title, and affects the following `paragraph` instead of only the next
{# paragraph segments}[paragraph segment]. Said paragraph then becomes the modifier's /content/.
This means that in order to terminate the detached modifier contents, you need an empty line (see
{$ paragraph break}).
Below you will find some examples of nestable detached modifiers.
*** Unordered Lists
|example
- Unordered list level 1
-- Unordered list level 2
--- Unordered list level 3
---- Unordered list level 4
----- Unordered list level 5
------ Unordered list level 6
------- Unordered list level 7 (falls back to level 6 in the tree-sitter parser)
- Unordered list level 1
This text is still part of the level 1 list item.
-- Unordered list level 2
This text is still part of the level 2 list item.
--- Unordered list level 3
This text is still part of the level 3 list item.
---- Unordered list level 4
This text is still part of the level 4 list item.
----- Unordered list level 5
This text is still part of the level 5 list item.
------ Unordered list level 6
This text is still part of the level 6 list item.
------- Unordered list level 7 (falls back to level 6 in the tree-sitter parser)
This text is still part of the level 7 list item.
|end
Unordered lists provide an easy way to enumerate items in an unordered fashion. Useful for data
that's categorically similar but doesn't need to follow a strict order.
*** Ordered Lists
|example
~ Ordered list level 1
~~ Ordered list level 2
~~~ Ordered list level 3
~~~~ Ordered list level 4
~~~~~ Ordered list level 5
~~~~~~ Ordered list level 6
~~~~~~~ Ordered list level 7 (falls back to level 6 in the tree-sitter parser)
~ Ordered list level 1
This text is still part of the level 1 list item.
~~ Ordered list level 2
This text is still part of the level 2 list item.
~~~ Ordered list level 3
This text is still part of the level 3 list item.
~~~~ Ordered list level 4
This text is still part of the level 4 list item.
~~~~~ Ordered list level 5
This text is still part of the level 5 list item.
~~~~~~ Ordered list level 6
This text is still part of the level 6 list item.
~~~~~~~ Ordered list level 7 (falls back to level 6 in the tree-sitter parser)
This text is still part of the level 7 list item.
|end
This list type is only useful for data that needs to be kept in sequence. In contrast to other
formats which may use a syntax like `1.`/`1)`, Norg counts the items automatically - this
reduces complexity and makes reordering items simple.
*** Quotes
|example
> Quote level 1
>> Quote level 2
>>> Quote level 3
>>>> Quote level 4
>>>>> Quote level 5
>>>>>> Quote level 6
>>>>>>> Quote level 7 (falls back to level 6 in the tree-sitter parser)
> Quote level 1
This text is still part of the level 1 quote.
>> Quote level 2
This text is still part of the level 2 quote.
>>> Quote level 3
This text is still part of the level 3 quote.
>>>> Quote level 4
This text is still part of the level 4 quote.
>>>>> Quote level 5
This text is still part of the level 5 quote.
>>>>>> Quote level 6
This text is still part of the level 6 quote.
>>>>>>> Quote level 7 (falls back to level 6 in the tree-sitter parser)
This text is still part of the level 7 quote.
|end
Quotes are rather self-explanatory - they allow you to cite e.g. a passage from another source.
*** Attributes
|example
% attrib1
%% attrib2
%%% attrib3
%%%% attrib4
%%%%% attrib5
%%%%%% attrib6
|end
Attributes are detached modifiers that exist solely for the purpose of having altered behavior
through {** carryover tags}. These can then be referenced within {** attached modifier extensions}
and the tags applied to the attribute will be applied to the attached modifier with said attribute.
These modifiers can be nested to create a hierarchy of attributes. Below is an example of this
in action:
|example
% color
+color #FF0000
%% red
+color #00FF00
%% green
+color #0000FF
%% blue
This will be /red/(color:red), /green/(color:green) and /blue/(color:blue).
|end
**** Limits
You can impose limits on where the attribute can be used through the `attribute-limits` tag,
which should be placed before the attribute definition. The tag takes in a list of the following
parameters:
- `none` - no limits
- `verbatim` - can be used only for the \`verbatim\` attached modifier
- `math` - can be only used on the \$mathematics\$ attached modifier
- `macro` - can be only used on the inline \¯o\& attached modifier
- `links` - can only be used on links (this includes anchors)
- `non-verbatim` - for all the other non-verbatim attached modifiers (bold, italic, subscript,
superscript, underline, the null modifier etc.)
These limits can be chained, i.e. `#attribute-limits links non-verbatim`.
*** Invalid Nestable Detached Modifier Examples
|example
>I am not a quote
some preceding text > I am also not a quote
>- I am not a valid detached modifier
> > I am only a level 1 quote
*
I am not a valid heading title.
|end
** Range-able Detached Modifiers
Range-able detached modifiers can occur in two forms:
- As a single detached modifier in which case they affect:
-- The next `paragraph_segment` which becomes the /title/
-- Any following paragraph which becomes the /content/
- As a pair of two detached modifiers in which case:
-- The next `paragraph_segment` also becomes the /title/
-- The content continues until the "closing" detached modifier is found
The closing modifier has the same rules as an opening detached modifier except it /must/ be
directly succeeded by a {*** line endings}[line ending] in contrast to the whitespace character which must follow the
opening modifier.
*** Definitions
Definitions are primarily of use to people who write technical documents.
They consist of a term, and then are followed by a definition of that term.
|example
$ Term
Definition content.
|end
To create longer definitions, use the ranged definition syntax instead:
|example
$$ Term
Content of the definition.
Which scans up to the closing modifier.
$$
|end
*** Footnotes
Footnotes allow the user to give supplementary information related to some text without
polluting the paragraph itself. Footnotes can be linked to using {* linkables}.
|example
^ Single Footnote
Optional footnote content.
|end
To create longer footnotes, use the ranged footnote syntax instead:
|example
^^ Ranged Footnote
Content of the footnote.
Which scans up to the closing modifier.
^^
|end
*** Table Cells
Table cells are used to, well, build up a table. Here are a few examples of table cells:
|example
: A1
Content of table cell at `A1`.
:: A2
> Content of table cell at `A2` (in a quote).
::
|end
Their semantics are described in more detail in the {:1.0-semantics:* Tables}[semantics] document,
which we recommend reading if you are interested in the behavior of objects as opposed to how
they are defined.
*NOTE*: In order to make tables more aesthetically pleasing, they're commonly mixed with the
{* intersecting modifiers}[intersecting modifier] syntax to produce the following:
|example
: A1 : Content of table cell at `A1`.
|end
** Grouping
Both nestable and range-able detached modifiers have a unique quality - when several consecutive
modifiers /of the same type/ are encountered (by consecutive we mean _NOT_ separated via a
{$ paragraph break}), they are treated as one whole <object>. This is crucial to understand as
it is required for the many types of {** carryover tags} to function.
*** Examples
|example
The following items naturally group because they are range-able, for example forming a
definition list:
$ Term 1
Definition 1!
$ Term 2
Definition 2!
|end
|example
Together, these form one whole unordered list:
- List item 1
- List item 2
|end
|example
- List item in one list
- This item is in another list, because we used a {$ paragraph break} to split these items
|end
** Delimiting Modifiers
In Norg, {** structural detached modifiers} and {*** indent segment}s may be terminated by a
delimiting modifier. This kind of modifier must abide by the following rules:
- A delimiting modifier can _only_ occur at the beginning of the line (arbitrary {*** whitespace}
(but nothing else!) may precede it)
- A delimiting modifier must consist of two or more consecutive modifiers of the same
type (a single character cannot be used to avoid false-positives /during/ the typing process;
plus a single character can look quite confusing/ugly when used like this...)
- A delimiting modifier must be followed by an immediate {*** line endings}[line ending] (without any extra
{*** whitespace}; this disambiguates them from nestable detached modifiers like for example an
unordered list item vs. the `--` delimiting modifier)
*** Weak Delimiting Modifier
This modifier uses the `-` character and immediately closes the /current/ nesting level
(decreases the current nesting level by one).
|example
* Heading level 1
Text under first level heading.
** Heading level 2
Text under second level heading.
---
Text under first level heading again.
|end
*** Strong Delimiting Modifier
This modifier uses the `=` character and immediately closes all nesting levels.
|example
* Heading level 1
Text under first level heading.
** Heading level 2
Text under second level heading.
===
Text belonging to no heading level (i.e. belonging to the document's root).
|end
*** Horizontal Rule
This modifier uses the `_` character and simply renders a horizontal line. It does _NOT_
affect the heading level but immediately terminates any {** paragraphs}[paragraph].
|example
* Heading level 1
Text under first level heading.
___
This is a new paragraph separated from the previous one by a horizontal line.
This text still belongs to the first level heading.
|end
** Detached Modifier Extensions
{* Detached modifiers} support extensions which must immediately follow the detached modifier
(or another extension). Note that {* detached modifiers} must be succeeded with {# whitespace},
therefore by "immediately followed" we mean /after/ the whitespace character in the detached
modifier, e.g. `- (x) List item`(lang:norg).
The syntax is as follows:
- An extension starts with a `(` char
- Immediately a special character must follow. This character determines the type of extension.
- Some extensions can support parameters - if this is the case, the special character must be
followed with {# whitespace} after which the parameters (a sequence of {** words} and/or
newlines) ensue.
Not all extensions support parameters and for good reason. There is no need to attach extra
metadata to a done or undone state for instance. Several extensions should be delimited with
the {* contextual `|` delimiter}.
- A `\|` character may be matched, which allows the user to chain many extensions together, e.g.
`(x|# A)`(lang:norg) (done with a priority of A).
- Finally a `)` char closes the extension.
NOTE: The whole detached modifier extension /must/ be followed by whitespace.
*** TODO Status Extension
The TODO item extension assigns a task status to a certain modifier. You probably know this
concept from Org where unordered lists can become tasks. In Norg we take this concept to
the next level because any detached modifier can be assigned a task status. This can for
example be useful for the author of a document to keep track of the status of certain sections.
The following characters are reserved for the TODO status extension:
-- `| |`: undone (a literal space)
-- `x`: done
-- `?`: needs further input/clarification
-- `!`: urgent
-- `+`: recurring (with an optional {**** timestamp extension}[timestamp])
-- `-`: in-progress/pending
-- `=`: on hold
-- `_`: put down/cancelled
Some examples include:
|example
- ( ) Undone
- (x) Done
- (# B| ) Undone with a priority of B
- (+) Recurring
- (+ 5th Jan) Recurring every 5th of January
|end
*** Advanced Detached Modifier Extensions
Apart from just being able to assign a TODO state it is also possible to apply more complex
states with parameters to certain indicators. Such examples are the {**** timestamp extension}
and the {**** priority extension}.
In the following sections you will find descriptions for a few other extensions supported within
Norg.
**** Timestamp Extension
The timestamp extension allows you to associate a {* detached modifiers}[detached modifier]
with a date/time.
The syntax for a timestamp is as {^ note to parser developers}[follows]:
`<day>?,? <day-of-month> <month> -?<year> <time> <timezone>`
- ::
The `<day>` value is reliant on the current locale, but the following alterations of that
value are permitted:
-- Full version (e.g. `Tuesday`, `Wednesday`)
-- An unambiguous shorthand (a shorthand that can uniquely identify the day), e.g. `Tue`, `We`,
`M` (Monday), `Frid`. Something like `T` is not allowed, as both `Tuesday` and `Thursday`
could satisfy the input.
The value may also be omitted if one chooses.
- The `,?` expression means that a `,` character may optionally exist in that location.
- The `<day-of-month>` value is simply a numeric value with at most 3 digits (to disambiguate
it from the `<year>` value).
- The `<month>` value is a word-based representation of the current month (i.e. `October`,
`January` etc.) dependent on the current locale. The same shorthand rules apply as in the
`<day>` value.
- The `<year>` value must be a numeric value with at least 4 digits (for dates before `1000`,
prefix the year with the appropriate amount of zeroes, so for example the year `200` should
be written as `0200`). The `<year>` value may also be prefixed with a `-` (negative) sign to
differentiate `B.C` from the default `A.D`.
- The `<time>` value must consist of this format (in regex): `|\d{1,2}:\d{2}(\.\d{1,2})?|`.
Some examples would be: `18:00`, `5:32`, `00:12.32`.
Obviously, you're not required to type the whole syntax out every time. Any of the elements in
angled brackets (`<>`) can be dropped/ignored, but the order of those values may not change!
Some examples of valid timestamps include:
- `Sat, 29 Oct 1994 19:43.31 GMT`
- `We 12th Jan 2022`
Apart from just being able to supply a timestamp, you are also permitted to provide a <range>.
The syntax is simple, and is contained within the extension:
|example
{@ 5th Aug 2022 - 20th August 2022}
{@ 5th Aug 2022-20th August 2022} <- Also valid
|end
You can even omit some fields from either one of the sides like so:
|example
{@ 5th - 20th August 2022}
|end
The matching fields will be automatically completed based on the information of the other half.
^ Note to Parser Developers
It should be mentioned that a parser of the Norg format is not required to perform any
timestamp analysis further than detecting what set of characters contain a timestamp.
The actual interpretation of its internal fields and the interpretation of a {# range} are the
responsibility of the *semantic analyzer* (see also the [semantics document]{:1.0-semantics:}).
**** Priority Extension
This extension allows you to specify a priority of your detached modifier extension.
Syntax:
|example
* (# A) This heading has priority A (highest priority)
|end
Note that Norg does not specify strict semantics for this detached modifier extension, and as
such there is no set-in-stone way to specify priorities. The most common (and recommended) way
to specify priorities is to go from `A-Z`, but many also prefer `0-9` or even named priorities
like `LOW`\/`MEDIUM`\/`HIGH`.
[Neorg]'s [GTD]{https://hamberg.no/gtd} implementation even repurposes the priority for use as
contexts, so yes, this detached modifier extension is very versatile.
**** Due Date Extension
As the name suggests, this extension marks something as "due before x", where x is a
{**** timestamp extension}[timestamp]. Especially useful in [GTD] and other forms of note-taking and time management applications.
Syntax:
|example
- (< Tue 5th Feb) Do this before the 5th of February.
|end
**** Start Date Extension
A counterpart to the {**** due date extension} - defines when a task *begins*, also useful in
[GTD].
Syntax:
|example
- (> Tue 5th Feb) This task starts after the 5th of February.
|end
** Detached Modifier Suffix
Since {# nestable detached modifiers} can only contain a {# paragraphs}[paragraph] this can
cause severe limitations because the insertion of e.g. code blocks is not possible. To alleviate
this deficiency, the {** detached modifier suffix} exists, which temporarily increases the
current indentation level to allow complex nested items within.
There are two variations of the indent segment, the {# slide} and the {# indent segment}.
*NOTE*: After a detached modifier suffix is matched (either `:` or `::`) a {*** line endings}[line ending] must
follow /instantly/.
*** Slide
The slide, denoted with a single `:`, allows for a set of contiguous /complex items/ below:
|example
- :
This is some text.
$ Term
And this is the term's definition.
|end
These <complex item>s may be any *non-{** structural detached modifiers}[structural]* detached
modifier, {* tags}[tag] or paragraph.
To terminate a slide, one of two conditions must be met:
- A {$ paragraph break} is encountered.
- If the slide is part of a {** nestable detached modifiers}[nestable detached modifier], when
an item of the same or lower level is encountered below.
**** Examples
***** Terminating via a {$ Paragraph Break}
|example
- :
This is part of the list item.
@code lua
print("This is also a part of the list item")
-- Despite the fact that there is a double newline dividing the `print` statement and this
-- comment, it is not a paragraph break, therefore it does not terminate the slide.
@end
$ Term
Here is a definition!
Now that there is a {$ paragraph break} between this paragraph and the previous item
this paragraph no longer belongs to the slide.
|end
***** Terminating as Part of a Nestable Detached Modifier
|example
-- :
Content of the slide.
- Because this item is a level lower than the item containing the slide above
the slide is terminated.
|end
*** Indent Segment
The indent segment, denoted with two colons (`::`), creates a ranged version of the slide.
This indent segment must be closed with any of the {** delimiting modifiers}, or an element of
the same type with the same or lower nesting level. By "lower" nesting level we mean higher up
in the hierarchy of nodes, or in other words `unordered_list_level_1` is "lower" than an
`unordered_list_level_2` item, because it is nested less.
The indent segment may contain an arbitrary amount of {# complex item}[complex items].
Examples:
|example
- ::
This is some content.
$ Term
Definition.
- This is the second item of the list.
The indent segment did not need to be terminated.
- ::
This is another list.
|details
*hello* world!
|end
-- This is a nested item in the indent segment
-- And so is this.
But you can still continue your content here.
---
Since there was no other item of the same type after the indent segment
it must be closed with `---` or `===`.
|end
* Tags
The main differentiator from simple markup formats and more complex ones is the ability to define
data and extensions for the format. Norg allows for you to extend its syntax and define data
within clear boundaries - it does this using tags.
*NOTE*: Tags are the /only/ way that extensions may be made to the format.
There are 6 different tag types, each with their own way of changing the way text in Norg is
interpreted. Before we discuss those, however, we should discuss the syntax rules for tags:
- A tag is similar to a {# detached modifiers}[detached modifier] in the sense that it must begin
at the beginning of a line with optional {*** whitespace} (but nothing else) preceding it.
- After that you will encounter a special tag character (`=`, `|`, `@`, `#`, `+` and `.`), /none/
of which are attached modifiers (see {^ disambiguating tags and attached modifiers}). The
special tag character is then /immediately/ followed by text, which becomes the /tag name/. Said
tag name can consist of any {# regular characters}[regular character] and/or `-` and `_`.
- Tags can have their names delimited by a `.` in order to create a "hierarchy", e.g.
`document.meta`.
- ::
After a {*** whitespace} character any number of parameters on the same line may follow:
|example
#tag-name.subtag parameter1 parameter2
|end
By default parameters are space-separated. In order to create multi-word parameters, you may
escape the space character with a backslash (`\`).
|example
#tag-name.subtag parameter1\ with\ spaces parameter2
|end
Parameters may consist of any character (apart from a {*** line endings}[line ending], of course).
---
^ Disambiguating tags and attached modifiers
If tag characters were attached modifier openers there would be no way to know whether the
character is an attached modifier opener or a tag opener until the whole line has been parsed;
in other words, such a scenario would entail a difficult to resolve ambiguity.
Norg provides several inbuilt tag names that are reserved, but their details are not explained
in this specification - this document strictly covers syntax - see the [semantics document] for a
list of the built-in tags. There is no restriction in regard to the length of a tag name, nor are
there any disallowed names that a parser should omit (unless they don't adhere to the above rules
regarding tag names).
** Ranged Tags
Ranged tags are a way to express custom information within a range.
They begin with the traditional tag declaration and are ended with an `end` statement.
The `end` statement has a simple rule set:
- Must be at the start of a line, may be preceded by any {*** whitespace} (but nothing else)
- Must use the same prefix as its parent (in the case of standard ranged tags: `|`; in the case
of verbatim tags: `@`; for macro tags: `=`)
- Must *immediately* be succeeded by a {*** line endings}[line ending].
*** Macro Tags
Macro tags (also known as /macro definitions/) are a tag type designed to declare and define
macros. Macros are templates that can be executed with parameters in order to place some
structured text into the document.
The content of the macro tag is /any/ Norg markup - this includes {** structural detached
modifiers} and nested {* tags}. The macro tag is closed with the `=end` statement.
Under the hood, all other {* tags}[tag] types are implemented as macros with special parameters
and contents.
The following is an example of a macro:
|example
=see url
(see {&url&})
=end
|end
It can then be invoked using any of the other tag types, for example the {** infirm tag}:
|example
This is a recipe for a cake
.see https://wikipedia.com/some-cool-cake-recipe
\- let's begin cooking!
|end
After macro expansion, this is what the document would look like:
|example
This is a recipe for a cake
(see {https://wikipedia.com/some-cool-cake-recipe})
\- let's begin cooking!
|end
Which, when reformatted, would look (and render) like so:
|example
This is a recipe for a cake (see {https://wikipedia.com/some-cool-cake-recipe}) - let's begin
cooking!
|end
*** Standard Ranged Tags
There are times when you may want to create an isolated block of Norg markup.
To do this you may use the standard ranged tag, which uses the `|` character.
Currently, it is only used for four tags, `comment`, `example`, `details` and `group`:
- The `comment` ranged tag is used for long strings of comments (versus the `%` null attached
modifier, which is mostly used for short comments).
- The `example` tag is a simple way to show an example of some Norg markup without it being
rendered and treated as physical markup (most commonly used throughout this very document to
show unrendered examples of Norg syntax).
- The `details` tag is a way to hide away markup (just like
{https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details}[`<details>`] in HTML).
- The `group` tag may be used to group together many elements and apply a global {*** strong
carryover tags}[strong carryover tag] to each one of them.
**** Examples
`\|example`:
|example
|example
* This is an example heading.
|end
|end
`\|comment`:
|example
|comment
This is a very long comment with some content
and with some markup!
* Heading
/italic/ and *bold*.
|end
|end
`\|details`:
|example
|details
* Here is some hidden markup!
Wowzers.
|end
|end
`\|group`:
|example
#color red
|group
This will be red.
So will this.
* So will this
And this.
|end
|end
**** Edge Cases and Semantic Interpretation
A commonly arising question is "how are these interpreted at parse time?" - can you link to
elements within `\|comment` tags? What governs the behavior of these differing tags?
The answer may be illustrated simply by showing how these tags are implemented.
As mentioned in the {*** macro tags} section, all tag types (apart from the macro tag) are a
macro invocation under the hood. Below are the implementations for `\|comment` and `\|group`,
respectively:
- :
|example
=comment ...
=end
|end
- :
|example
=group ...
&...&
=end
|end
The `\|comment` tag evaluates to /no value/. Anything that is placed within a comment during
invocation (the `...` parameter) is simply dropped. Because of this it is *not* possible to
link to elements within comment tags. The `\|group` tag returns everything that you give
it, because of this it *is* possible to freely link to any element within a `\|group`.
To summarize - the behavior of each individual standard ranged tag is fully governed by its
implementation - see the [semantics document] for more details.
*** Verbatim Ranged Tags
In other cases you may be more interested in an isolated block /without/ Norg markup (i.e. a
/verbatim/ block). A prime example of this is `@code`, which creates a code block - you
obviously don't want nested Norg syntax within that! Note how in the following example the
`@MyAnnotation` would clash with Norg's verbatim ranged tag syntax, but doesn't as no nested
markup is allowed within:
@code java
@MyAnnotation(name="someName", value="Hello World")
public class TheClass {
// ...
}
@end
This ranged tag type is the most commonly used one as it has the widest range of applications.
The {*** standard ranged tags}[standard ranged tag] is a much more niche syntax element targeted
at specific use cases.
** Carryover Tags
Carryover tags are a construct used to assign certain properties to the next item or whole
{# objects}[object].
/Note/: Internally, they are a type of {** macro tags}[macro tag], where the next element is given
as the last parameter to the macro. For more info see {*** macro tags} and the [semantics document].
There are two types of carryover tag, the {*** weak carryover tags}[weak carryover tag] and the
{*** strong carryover tags}[strong variant].
*** Weak Carryover Tags
The weak carryover tag affects the next element and next element /only/. It does not work with
whole collections of elements (see {*** strong carryover tags}).
Weak carryover tags only apply to the next element; their behavior is as follows:
- When the element has children, the weak carryover tag only applies to the single item (it does
not carry over to its children).
- When the element is part of an {# object}, no items other than the one below the weak
carryover tag is affected.
- An exception is made when a weak carryover tag is applied to an {# indent segment} or a
{** ranged tags}[ranged tag], in which case everything within that segment/tag is affected.
**** Examples
Only the second item is affected:
|example
- List item 1
+color red
- List item 2 (which is red)
- List item 3 (which is normal-colored)
|end
Only the `Heading 1` and `This is some content` text is highlighted:
|example
+color red
* Heading 1 (which is red)
This is some content. (which is still red)
** Heading 2 (which is normal-colored)
This is also some content. (which is normal-colored)
|end
Special behavior for indent segments:
|example
- List item 1
+color red