cortav  Check-in [c0bdfa46df]

Overview
Comment:various updates fuck man idr what all i did
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: c0bdfa46dfc5d4df9190c39199318c0e8ee03faaad4976703da8a9e0bcda6ac3
User & Date: lexi on 2022-04-17 21:16:05
Other Links: manifest | tags
Context
2022-09-05
18:49
add blockquote support for html, subdocument mechanisms, mode to generate epub-compatible XHTML5; various fixes and improvements check-in: 35ea3c5797 user: lexi tags: trunk
2022-04-17
21:16
various updates fuck man idr what all i did check-in: c0bdfa46df user: lexi tags: trunk
2021-12-29
12:19
continue iterating on groff renderer; add headings, basic formatting, beginnings of a footnote and link system, colors check-in: 7ba2577283 user: lexi tags: trunk
Changes

Modified cortav.ct from [7b2c420807] to [2cc3a528df].

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
..
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
...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
...
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
...
193
194
195
196
197
198
199






































200
201
202
203
204
205
206
...
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
...
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
...
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
...
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
...
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
...
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
...
951
952
953
954
955
956
957
958




959
960
961
962
963
964
965
* [*headings]: cortav uses almost the same syntax for headings that markdown does, except it only allows the "ATX style" headings, with one or more hash characters at the start of the line. the only differences from markdown are:
** you can use the unicode section character [`§] instead of [`#] if you're feeling snobby
** you must put a space between the control sequence (the sequence of hashes or section symbols, in this case) and the title text. [`# title] creates a section with the heading text "title", but [`#title] creates a new section with no heading at all; instead, it gives the anonymous section the ID [`title]. and of course, you can combine the two: [`#ttl title] creates a section with the heading text "title" and the ID [`ttl]. what are IDs for? we'll get to that in a little bit
* [*paragraphs] are mostly the same as in markdown, except that a paragraph break occurs after every newline character, not every blank line. paragraphs can be indented by however many spaces you like; such indentation will be ignored. (tabs have a special meaning, however). in cortav, you can also explicitly mark a line of text as a paragraph by preceding it with a period character ([`.]), which is useful if you want to start a paragraph with text that would otherwise be interpreted specially.
* [*italic text] -- or rather, [!emphasized] text -- is written as [`\[!my spiffy italic text\]]. in cortav, these spans can be nested within other spans (or titles, or table cells, or…), and the starting and ending point is unambiguous.
* [*bold text] -- or rather, [*strong] text -- is written as [`\[*my commanding bold text\]].
* [*bold-italic text] -- or rather, [![*emphasized strong text]] -- has no specific notation. rather, you create it by nesting one span within the other, for instance: [`\[*[!my ostentatious bold-italic text\]]].
* [*links] are quite different from their markdown equivalents. cortav does not have inline links, as it is intended to be easily readable in both formatted and plain-text format, and long URLs rather disrupt the flow of reading. rather, a link tag is written with the notation [`\[>nifty-link my nifty link\]], where the word [`nifty-link] immediately following the arrow is an [!identifier] indicating the destination of the link. (instead of a greater-than sign, you can also use the unicode arrow symbol [`→].) if the identifier is the same as one you've assigned to a section, cortav produces a link within the document to that section. otherwise, it will look for a [!reference] to tell it the URI for the link. a reference is a key-value pair created by adding a line like [`nifty-link: https://zombo.com] [!indented by exactly one tab]. you can place this reference anywhere you like so long as it's in the same section; if you want to name a reference in another section, you have to prefix it with that section's ID, e.g. [`\[>spiffy-section.nifty-link my nifty link declared in a spiffy section\]].
* [*lists] use a different syntax from markdown. you can start a line with a [`*] to create an unordered list, or [`:] to create an ordered list; indentation doesn't matter. if you want to nest list items, instead of putting two spaces before the child item, you just add another star or colon. and of course, you can nest lists of different kinds within one another.
* [*horizontal rules] use roughly the same syntax: three or more hyphens on a line of their own ([`\---]). underlines also work ([`___], [`-_-], [`__-__-__] etc).
* some markdown implementations support [*tables]. cortav does too, using a very simple notation.
* [*underlines] are supported by some markdown implementations. in cortav, you can apply them with the notation [`\[_my underlined text\]] -- please just use them sparingly when you render to HTML!
* [*strikethrough] is supported by some extended versions of markdown. cortav uses the notation [`\[~my deleted text\]], with the intended semantics of text that is being removed by some revision of a document. (you can also denote text that is being [!added] by using a plus sign instead of a tilde)
* [*images] are a bit more complicated. see the section on [>rsrc resources] for an explanation.
* [*smart quotes] and [*em dashes] are inserted automatically, just as in markdown, provided you have the [>tsmog transmogrify] extension available. (it is part of the reference implementation and defined by the spec, but not required.) in fact, you can insert longer dashes than em dashes just by increasing the number of hyphens. the reference implementation's transmogrifier also translates ascii arrows like [`\-->] into their unicode equivalents ([`→]).
* [*literals] (also known as [*code text]) can be inserted with the [`\[`int main(void);] syntax. note however that literals are not protected from the transmogrifier, and are parsed like any other span, which may cause problems if the source code you're quoting makes use of such forbidden runes. in this case, you'll want to wrap the code span in a raw span. the syntax for this is [`\[`[\\int main(void);\]]], but since this is a bit unwieldy it can also be abbreviated as [`\[`\\int main(void);\]].

of course, this is only a small taste of what cortav can do, not even touching on key features like macros, footnotes, or equation formatting. read the sections on [>onblocks blocks] and [>onspans spans] for all the gory details.

## encoding
a cortav document is made up of a sequence of codepoints. UTF-8 must be supported, but other encodings (such as UTF-32 or C6B) may be supported as well. lines will be derived by splitting the codepoints at the linefeed character or equivalent. note that unearthly encodings like C6B or EBCDIC will need to select their own control sequences.
................................................................................

three more extensions are reserved for identifying a cortav intent file.
* [`ctc] is the shorthand extension
* [`cortavcun] is the canonical disambiguation extension
* [`] is the canonical Corran extension, a byte sequence comprising the unicode codepoints [`U+E3CE U+E3BD U+E3CE]. where the filesystem in question does not specify a filename encoding, the bytes should be expressed in UTF-8.

on systems which use metadata to encode filetype, two values are defined to identify cortav source files
* [`text/x-cortav] should be used when strings or arbitrary byte sequences are supported
* [`CTAV] (that is, the byte sequence [`0x43 54 41 56]) should be used on systems that support only 32-bit file types/4-character type codes like Classic Mac OS.

two more values are defined to identify cortav intent files.
* [`text/x-cortav-intent]
* [`CTVC] (the byte sequence [`0x43 54 56 43])

on systems which do not define a canonical way of encoding the filetype but support extended attributes of some kind, such as linux, an attribute named [$mime] may be created and given the value [`text/x-cortav] or [`text/x-cortav-intent]; alternatively, extensions may be used.

it is also possible to indicate the nature of a cortav file without using filesystem metadata. this is done by prefixing the file with a magic byte sequence. the sequence used depends on the encoding.
* for UTF-8 and ASCII plain text files, [`%ct[!\\n]] (that is, the byte sequence [`0x25 63 74 0A]) should be used
* for C6B+PS files (parastream), the file should begin with the paragraph [`], which equates to the byte sequence [` 0x3E 2E 14 0C 01 04 00 00 00 03 07 3E 2D], including the parastream header).
consequently, this sequence should be ignored by a cortav parser at the start of a file (except as an indication of file format).

for FreeDesktop-based systems, the [`build/velartrill-cortav.xml] file included in the repository supplies mappings for the extensions and magic byte sequences. a script is also included which can be registered with xdg-open so that double-clicking on a cortav file will render it out and open it in your default web browser. [`$ make install] will generate the necessary FreeDesktop XML files and register them, as well as install the script and the [`cortav] executable itself. for more information see [>refimpl-build building the reference implementation].










##onblocks structure
cortav is based on an HTML-like block model, where a document consists of sections, which are made up of blocks, which may contain a sequence of spans. flows of text are automatically conjoined into spans, and blocks are separated by one or more newlines. this means that, unlike in markdown, a single logical paragraph [*cannot] span multiple ASCII lines. the primary purpose of this was to ensure ease of parsing, but also, both markdown and cortav are supposed to be readable from within a plain text editor. this is the 21st century. every reasonable text editor supports soft word wrap, and if yours doesn't, that's entirely your own damn fault.

the first character(s) of every line (the "control sequence") indicates the role of that line. if no control sequence is recognized, the line is treated as a paragraph. the currently supported control sequences are listed below. some control sequences have alternate forms, in order to support modern, readable unicode characters as well as plain ascii text.

* [*paragraphs] ([`.] [` ¶] [`❡]): a paragraph is a simple block of text. the period control sequence is only necessary if the paragraph text starts with text that would be interpreted as a control sequence otherwise
* newlines [` \\]: inserts a line break into previous paragraph and attaches the following text. mostly useful for poetry or lyrics
* [*section starts] [`#] [`§]: starts a new section. all sections have an associated depth, determined by the number of sequence repetitions (e.g. "###" indicates depth-three"). sections may have headers and IDs; both are optional. IDs, if present, are a sequence of raw-text immediately following the hash marks. if the line has one or more space character followed by styled-text, a header will be attached. the character immediately following the hashes can specify a particular type of section. e.g.:
** [`#] is a simple section break.
** [`#anchor] opens a new section with the ID [`anchor].
** [`# header] opens a new section with the title "header".
** [`#anchor header] opens a new section with both the ID [`anchor] and the title "header".
* [*nonprinting sections] ([`^]): sometimes, you'll want to create a namespace without actually adding a visible new section to the document. you can achieve this by creating a [!nonprinting section] and defining resources within it. nonprinting sections can also be used to store comments, notes, or other information that is useful to have in the source file without it becoming a part of the output
* [*resource] ([`@]): defines a [!resource]. a resource is an file or object that exists outside of the document but which will be included in the document somehow. common examples of resources include images, videos, iframes, or headers/footers. see [>rsrc resources] for more information.
* [*lists] ([`*] [`:]): these are like paragraph nodes, but list nodes that occur next to each other will be arranged so as to show they compose a sequence. depth is determined by the number of stars/colons. like headers, a list entry may have an ID that can be used to refer back to it; it is indicated in the same way. if colons are used, this indicates that the order of the items is signifiant. :-lists and *-lists may be intermixed; however, note than only the last character in the sequence actually controls the depth type.
* [*directives] ([`%]): a directive issues a hint to the renderer in the form of an arbitrary string. directives are normally ignored if they are not supported, but you may cause a warning to be emitted where the directive is not supported with [`%!] or mark a directive critical with [`%!!] so that rendering will entirely fail if it cannot be parsed.
* [*comments] ([`%%]): a comment is a line of text that is simply ignored by the renderer.
* [*asides] ([`!]): indicates text that diverges from the narrative, and can be skipped without interrupting it. think of it like block-level parentheses. asides which follow one another are merged as paragraphs of the same aside, usually represented as a sort of box. if the first line of an aside contains a colon, the stretch of styled-text from the beginning to the aside to the colon will be treated as a "type heading," e.g. "Warning:"
* [*code] ([`~~~]): a line beginning with ~~~ begins or terminates a block of code. code blocks are by default not parsed, but parsing can be activated by preceding the code block with an [`%[*expand]] directive. the opening line should look like one of the below
** [`~~~]
** [`~~~ language] (markdown-style shorthand syntax)
** [`~~~ \[language\] ~~~] (cortav syntax)
** [`~~~ \[language\] #id ~~~]
................................................................................
** [`~~~ title ~~~]
** [`~~~ title \[language\] ~~~]
** [`~~~ \[language\] title ~~~]
** [`~~~ title \[language\] #id ~~~]
*[*reference] (tab): a line beginning with a tab is treated as a "reference." references hold out-of-line metadata for preceding text like links and footnotes. a reference consists of an identifier followed by a colon and an arbitrary number of spaces or tabs, followed by text. whether this text is interpreted as raw-text or styled-text depends on the context in which the reference is used. in encodings without tab characters, two preceding blanks can be used instead.
* [*quotation] ([`<]): a line of the form [`<[$name]> [$quote]] denotes an utterance by [$name].
* [*blockquote] ([`>]): alternate blockquote syntax. can be nested by repeating the [`>] character.
* [*subtitle] ([`--]): attaches a subtitle to the previous header
* [*embed] ([`&]): embeds a referenced object. can be used to show images or repeat previously defined objects like lists or tables, optionally with a caption.
** [`&$[$macro] [$arg1]|[$arg2]|[$argn]…] invokes a block-level macro with the supplied arguments
*** [`&$mymacro arg 1|arg 2|arg 3]
** [`&[$image]] embeds an image or other block-level object. [!image] can be a reference with a url or file path, or it can be an embed section (e.g. for SVG files)
***[`&myimg All that remained of the unfortunate blood magic pageant contestants and audience (police photo)]
** [`&-[$section] [$styled-text]] embeds a closed disclosure element. in interactive outputs, this will display as a block [!section] which can be clicked on to view the full contents of the referenced section; if [$styled-text] is present, it overrides the title of the section you are embedding. in static outputs, the disclosure object will display as an enclosed box with [$styled-text] as the title text
*** [`&-ex-a Prosecution Exhibit A (GRAPHIC CONTENT)]
** [`&+[$section] [$styled-text]] is like the above, but the disclosure element is open by default
* [*horizontal rule] ([`\---]): inserts a horizontal rule or other context break; does not end the section. must be followed by newline. underlines can also be used in place of dashes.
* [*page break] ([`\^^]): for formats that support pagination, like HTML (when printed), indicates that the rest of the current page should be blank. for formats that do not, extra margins will be inserted. does not create a new section
* [*page rule] ([`\^-^]): inserts a page break for formats that support them, and a horizontal rule for formats that do not. does not create a new section
* [*table cells] ([`+ |]): see [>ex.tab table examples].
* [*equations] ([`=]) block-level equations can be inserted with the [`=]

* [*empty lines] (that is, lines consisting of nothing but whitespace) constitute a [!break], which terminates multiline objects that do not have a dedicated termination sequence, for example lists and asides.

##onspans styled text
most blocks contain a sequence of spans. these spans are produced by interpreting a stream of [*styled-text] following the control sequence. styled-text is a sequence of codepoints potentially interspersed with escapes. an escape is formed by an open square bracket [`\[] followed by a [*span control sequence], and arguments for that sequence like more styled-text. escapes can be nested.

* strong {obj *|styled-text}: causes its text to stand out from the narrative, generally rendered as bold or a brighter color.
* emphatic {obj !|styled-text}: indicates that its text should be spoken with emphasis, generally rendered as italics
................................................................................
* literal {obj `|styled-text}: indicates that its text is a reference to a literal sequence of characters or other discrete token. generally rendered in monospace
* variable {obj $|styled-text}: indicates that its text is a stand-in that will be replaced with what it names. generally rendered in italic monospace, ideally of a different color
* underline {obj _|styled-text}: underlines the text. use sparingly on text intended for webpages -- underlined text  [!is] distinct from links, but underlining non-links is still a violation of convention.
* strikeout {obj ~|styled-text}: indicates that its text should be struck through or otherwise indicated for deletion
* insertion {obj +|styled-text}: indicates that its text should be indicated as a new addition to the text body.
** consider using a macro definition [`\edit: [~[#1]][+[#2]]] to save typing if you are doing editing work
* link \[>[!ref] [!styled-text]\]: produces a hyperlink or cross-reference denoted by [$ref], which may be either a URL specified with a reference or the name of an object like an image or section elsewhere in the document. the unicode characters [`→] and [`🔗] can also be used instead of [`>] to denote a link.
* footnote {span ^|ref|[$styled-text]}: annotates the text with a defined footnote. in interactive output media [`\[^citations.qtheo Quantum Theosophy: A Neophyte's Catechism]] will insert a link with the next [`Quantum Theosophy: A Neophyte's Catechism] that, when clicked, causes a footnote to pop up on the screen. for static output media, the text will simply have a superscript integer after it denoting where the footnote is to be found.
* superscript {obj '|[$styled-text]}
* subscript {obj ,|[$styled-text]}
* raw {obj \\ |[$raw-text]}: causes all characters within to be interpreted literally, without expansion. the only special characters are square brackets, which must have a matching closing bracket, and backslashes.
* raw literal \[$\\[!raw-text]\]: shorthand for [\[$[\…]]]
* macro [`\{[!name] [!arguments]\}]: invokes a [>ex.mac macro], specified with a reference
* argument {obj #|var}: in macros only, inserts the [$var]-th argument. otherwise, inserts a context variable provided by the renderer.
* raw argument {obj ##|var}: like above, but does not evaluate [$var].
* term {obj &|name}, {span &|name|[$expansion]}: quotes a defined term with a link to its definition, optionally with a custom expansion of the term (for instance, to expand the first use of an acronym)
* inline image {obj &@|name}: shows a small image or other object inline. the unicode character [`🖼] can also be used instead of [`&@].
* unicode codepoint {obj U+|hex-integer}: inserts an arbitrary UCS codepoint in the output, specified by [$hex-integer]. lowercase [`u] is also legal.
* math mode {obj =|equation}: activates additional transformations on the span to format it as a mathematical equation; e.g. [`*] becomes [`×] and [`/] --> [`÷].
* extension {span %|ext|…}: invokes extension named in [$ext]. [$ext] will usually be an extension name followed by a symbol (often a period) and then an extension-specific directive, although for some simple extensions it may just be the plain extension name. further syntax and semantics depend on the extension. this syntax can also be used to apply formatting specific to certain renderers, such as assigning a CSS class in the [`html] renderer ([`\[%html.myclass my [!styled] text]]).
................................................................................

##ident identifiers
any identifier (including a reference) that is defined within a named section must be referred to from outside that section as [`[!sec].[!obj]], where [$sec] is the ID of the containing section and [$obj] is the ID of the object one wishes to reference.

##rsrc resources
a [!resource] represents content that is not encoded directly into the source file, but which is embedded by some means in the output. resources can either be [!embedded], in which case they are compiled into the final document itself, or they can be [!linked], in which case the final document only contains a URI or similar tag referencing the resource. not all render backends support both linking and embedding embedding, nor do all backends support all object types (for instance, [`groff] does not support video embedding.)

a resource definition is begun by line consisting of an [`@] sign and an [>ident identifier]. this line is followed by any number of parameters. a parameter is a line beginning with a single tab, a keyword, a colon, and a then a value. additional lines can be added to a parameter by following it with a line that consists of two tabs followed by the text you wish to add. (this is the same syntax used by references.) a resource definition is terminated by a break, or any line that does not begin with a tab

a resource definition in use looks like this:

~~~
this is a demonstration of resources
@smiley
	src: link image/webp http://cdn.example.net/img/smile.webp
		  link image/png file:img/smile.png
		  embed image/gif file img/smile.gif
	desc: the Smiling Man would like to see you in his office
here is the resource in span context [&smiley]
and here it is in block context:
&smiley
~~~

rendered as HTML, this might produce the following:

~~~
<style>
	.res-smiley {
		content: image-set(
			url(http://cdn.example.net/img/smile.webp) type(image/webp),
			url(img/smile.png) type(image/png),
			url(data:image/gif;base64,/* … */) type(image/gif)
		); /* this will actually be repeated with a -webkit- prefix */
................................................................................
<p>this is a demonstration of resources</p>
<p>here is the resource in span context: <span class="res-smiley"></span></p>
<p>and here it is in block context:</p>
<div class=".res-smiley"></div>
~~~

note that empty elements with CSS classes are used in the output, to avoid repeating long image definitions (especially base64 inline encoded ones!)







































inline resources are defined a bit differently:

~~~cortav
@smiling-man-business-card text/plain {
	THE SMILING MAN  | tel. 0-Ω00-666█
	if you can read this | email: nameless@smiles.gov
................................................................................
@smiling-man-business-card image/png;base64 {
	%% incomprehensible gibbering redacted
}
~~~

for an inline resource, the identifier is followed by a MIME type and an opening bracket. the opening bracket may be any of the characters [`\{][`\[][`(][`<], and can optionally be followed by additional characters to help disambiguate the closing bracket. the closing bracket is determined by "flipping" the opening bracket, producing bracket pairs like the following:
* [`\{:][`:}]
* [`<!--] [`--!>]
* [`(*<][`>*)]
* [`<>][`<>] [!(disables nesting!)]
if the open and closing brackets are distinguishable, they will nest appropriately, meaning that [`{][`}] alone is very likely to be a safe choice to escape a syntactically correct C program (that doesn't abuse macros too badly). brackets are searched for during parsing; encoded resources are not decoded until a later stage, so a closing bracket character in a base64-encoded text file cannot break out of its escaping.

as a convenience, if the first line of the resource definition begins with a single tab, one tab will be dropped from every following line in order to allow legible indentation. similarly, if an opening bracket is followed immediately by a newline, this newline is discarded.

text within a resource definition body is not expanded unless the resource definition is preceded with an [`%[*expand]] directive. if an expand directive is found, the MIME type will be used to try and determine an appropriate type of formatting, potentially invoking a separate renderer. for example, [`text/html] will invoke the [`html] backend, and [`application/x-troff] will invoke the [`groff] backend. if no suitable renderer is available, expansions will generate only plain text.

two suffixes are accepted: [`;base64] and [`;hex]. the former will decode the presented strings using the base64 algorithm to obtain the resources data; the second will ignore all characters but ASCII hexadecimal digits and derive the resource data byte-by-byte by reading in hexadecimal pairs. for instance, the following sections are equivalent:

~~~
@propaganda text/plain {
	WORLDGOV SAYS
	“don't waste time with unproductive thoughts
	 your wages will be docked accordingly”
}
~~~
~~~
@propaganda text/plain;hex {
	574f 524c 4447 4f56 2053 4159 530a e280 9c64 6f6e 2774 2077 6173
	7465 2074 696d 6520 7769 7468 2075 6e70 726f 6475 6374 6976 6520
	7468 6f75 6768 7473 0a20 796f 7572 2077 6167 6573 2077 696c 6c20
	6265 2064 6f63 6b65 6420 6163 636f 7264 696e 676c 79e2 809d 0a
}
~~~
~~~
@propaganda text/plain;base64 {
	V09STERHT1YgU0FZUwrigJxkb24ndCB3YXN0ZSB0aW1lIHdpdGggdW5wcm9kdWN0aXZlIHRob3Vn
	aHRzCiB5b3VyIHdhZ2VzIHdpbGwgYmUgZG9ja2VkIGFjY29yZGluZ2x54oCdCg==
}
~~~

inline resources can also be (ab)used for multiline macros:
~~~
@def text/x-cortav {
	* [*[#1]] [!([#2])
	*: [#3]
}
&def nuclear bunker|n|that which will not protect you from the Smiling Man
~~~
to make this usage simpler, resources with a type of [`text/x-cortav] can omit the MIME type field.











### supported parameters
* [`src] (all): specifies where to find the file, what it is, and how to embed it. each line of [`src] should consist of three whitespace-separated words: embed method, MIME type, and URI.
** embed methods

*** [`local]: loads the resource at build time and embeds it into the output file. not all implementations may allow loading remote network resources at build time.
*** [`remote]: only embeds a reference to the location of the resource. use this for e.g. live iframes, dynamic images, or images hosted by a CDN.
*** [`auto]: embeds a reference in file formats where that's practical, and use a remote reference otherwise.
** MIME types: which file types are supported depends on the individual implementation and renderer backend; additionally, extensions can add support for extra types. MIME-types that have no available handler will, where possible, result in an attachment that can be extracted by the user, usually by clicking on a link. however, the following should be usable with all compliant implementations
*** [`image/*] (graphical outputs only)
*** [`video/*] (interactive outputs only)
*** [`image/svg+xml] is handled specially for HTML files, and may or may not be compatible with other renderer backends.
*** [`font/*] can be used with the HTML backend to reference a web font
*** [`font/woff2] can be used with the HTML backend to reference a web font
*** [`text/plain] (will be inserted as a preformatted text block)
*** [`text/css] (can be used when producing HTML files to link in an extra stylesheet, either by embedding it or referencing it from the header)
*** [`text/x-cortav] (will be parsed and inserted as a formatted text block; context variables can be passed to the file with [`ctx.[$var]] parameters)
*** [`application/x-troff] can be used to supply sections of text written in raw [`groff] syntax. these are ignored by other renderers.
*** [`text/html] can be used to supply sections of text written in raw HTML.
*** any MIME-type that matches the type of file being generated by the renderer can be used to include a block of data that will be passed directly to the renderer.
** URI types: additional URI types can be added by extensions or different implementations, but every compliant implementation must support these URIs.
*** [`http], [`https]: accesses resources over HTTP. add a [`file] fallback if possible for the benefit of renderers/viewers that do not have internet access abilities.
*** [`file]: references local files. absolute paths should begin [`file:/]; the slash should be omitted for relative paths. note that this doesn't have quite the same meaning as in HTML -- [`file] can (and usually should be) used with HTML outputs to refer to resources that reside on the same server. a cortav URI of [`file:/etc/passwd] will actually result in the link [`/etc/passwd], not [`file:///etc/passwd] when converted to HTML. generally, you only should use [`http] when you're referring to a resource that exists on a different domain.
*** [`name]: a special URI used generally for referencing resources that are already installed on a target system and do not need to be embedded or linked, the name and type are enough for a renderer on another machine to locate the correct resource. this is useful mostly for [>fonts fonts], where it's more typical to refer to fonts that are installed on your system rather than providing paths to font files.
*** [`gemini]: accesses resources over the gemini protocol. currently you should really only use this for [`local] resources unless you're using the gemtext renderer backend, since nothing but gemini browsers are liable to support this protocol.

* [`desc]: supplies a narrative description of the resources, for use as an "alt-text" when the image cannot be loaded and for screenreaders.
* [`detail]: supplies extra narrative commentary that is displayed contextually, e.g. when the user hovers her mouse cursor over the embedded object. also used for [`desc] if [`desc] is not supplied.

note that in certain cases, full MIME types do not need to be used. say you're defining a font with the [`name] URI -- you can't necessary know what file type the system fonts on another computer are going to be. in this case, you can just write [`font] instead of [`font/ttf] or [`font/woff2] or similar. all cortav needs to know in this case is what abstract kind of object you're referencing. [`groff] fonts (referenced with the [`dit] URI) don't have a specific MIME type either.


##ctxvar context variables
................................................................................

when a document parse begins, the font stack is empty (unless a default font has already been loaded by an intent file).
when the font stack is empty, cortav does not include font specifications in its output, and thus will use whatever the default of the various rendering programs is.

to use fonts, we first have to define the fonts as [>rsrc resources].

~~~cortav
%% first, we create a new section to namespace the fonts
#^fonts
%% we then define each font as a resource
@serif
	src: auto font name:Alegreya
		embed  font/ttf file:project-fonts/alegreya.ttf
		link font/woff2 file:/assets/font/alegreya.woff2
		auto font name:Times New Roman
		auto font dit:TR/bold=TRB/italic=TRI/bold,italic=TRBI
@sans
................................................................................
	font-family: "fontdef-sans";
	src: local("Alegreya Sans"),
		local("Open Sans"),
		local("sans-serif");
}
~~~

there are two things that aren't super clear from the CSS, however. notice how we used [`auto] on a couple of those specs? this means it's up to the renderer to decide whether to link or embed the font. in HTML, a font specified by name can't really be embedded, but for some file formats, it can be. [`auto] lets us produce valid HTML while still taking advantage of font embedding in other formats.

now that we have our font families defined, we can use their identifiers with the [`%[*font]] directive to control the font stack. the first thing we need to do is push a new font context. there's two ways we can do this:
	fnd: [`%[*font] [#1]]
* {fnd dup} will create a copy of the current font context, allowing us to make some changes and then revert later with the {fnd pop} command. this isn't useful in our case, however, because right now the stack is empty; there's nothing to duplicate.
* {fnd new} will create a brand new empty context for us to work with and push it to the stack. this can also be used to temporarily revert to the system default fonts, and then switch back with {fnd pop}.
* {fnd set} changes one or more entries in the current font context. it can take a space-separated list of arguments in the form [`[$entry]=[$font-id]]. the supported entries are:
** [`body]: the fallback font. if only this is set in a given font context, it will be used for everything
** [`paragraph]: the font used for normal paragraphs
** [`header]: the font used in headers
................................................................................
* {d include} transcludes another file
* {d import} reads in the contents of another file as an embeddable section
* {d quote} transcludes another file, without expanding the text except for paragraphs 
* {d embed}, where possible, embeds another file as an object within the current one. in HTML this could be accomplished with e.g. an iframe.
* {d expand} causes the next object (usually a code block) to be fully expanded when it would otherwise not be
* {d font} controls the font stack, for outputs that support changing fonts. see [>fonts fonts] for more information.
* {d lang} changes the current language, which is used by extensions to e.g. control typographical conventions, and may be encoded into the output by certain renderers (e.g. HTML). note that quotes and blockquotes can be set to a separate language with a simpler syntax. the language should be notated using IETF language tags
** {d lang is x-ranuir-Cent-CR8} sets the current language to Ranuir as spoken in the Central Worlds, written in Corran and encoded using UTF-8. this might be used at the top of a document to set its primary language.
** {d lang push gsw-u-sd-chzh} temporarily switches to Zürich German, e.g. to quote a German passage in an otherwise Ranuir document
** {d lang sec en-US} switches to American English for the duration of a section. does not affect the language stack.
** {d lang pop} drops the current language off the language stack, returning to whatever was pushed or set before it. this would be used, for instance, at the end of a passage
* {d pragma} supplies semantic data about author intent, the kind of information the document contains and hints about how it should be displayed to the user. think of them like offhand remarks to the renderer -- there's no guarantee that it'll pay any attention, but if it does, your document will look better. pragmas have no scope; they affect the entire document. the pragma function exists primarily as a means to allow parameters that would normally need to be specified on e.g. the command line to be encoded in the document instead in a way that multiple implementations can understand. a few standard pragmas are defined.
** {d pragma layout} gives a hint on how the document should be layed out. the first hint that is understood will be applied; all others will be discarded. standard hints include:
*** [`essay]
*** [`narrative]
................................................................................

	corran: http://ʞ.cc/fic/spirals/society
	tengwar: https://en.wikipedia.org/wiki/Tengwar

###refimpl-switches switches
[`cortav.lua] offers various switches to control its behavior.
+ long                      + short + function                                    +
| [`--out [!file]]              :|:[`-o]:| sets the output file (default stdout)       |
| [`--log [!file]]              :|:[`-l]:| sets the log file (default stderr)          |
| [`--define [!var] [!val]]     :|:[`-d]:| sets the context variable [$var] to [$val]  |
| [`--mode-set [!mode]]         :|:[`-y]:| activates the [>refimpl-mode mode] with ID [!mode]
| [`--mode-clear [!mode]]       :|:[`-n]:| disables the mode with ID [!mode]           |
| [`--mode [!id] [!val]]        :|:[`-m]:| configures mode [!id] with the value [!val] |
| [`--mode-set-weak [!mode]]    :|:[`-Y]:| activates the [>refimpl-mode mode] with ID [!mode] if the source file does not specify otherwise
| [`--mode-clear-weak [!mode]]  :|:[`-N]:| disables the mode with ID [$mode] if the source file does not specify otherwise
| [`--mode-weak [!id] [!val]]   :|:[`-M]:| configures mode [$id] with the value [$val] if the source file does not specify otherwise
| [`--help]                     :|:[`-h]:| display online help                         |
| [`--version]                  :|:[`-V]:| display the interpreter version             |

###refimpl-mode modes
most of [`cortav.lua]'s implementation-specific behavior is controlled by use of [!modes]. these are namespaced options which may have a boolean, string, or numeric value. boolean modes are set with the [`-y] [`-n] flags; other modes use the [`-m] flags.

most modes are defined by the renderer backend. the following modes affect the behavior of the frontend:

+ ID                 + type   + effect
................................................................................
if the [`toc] extension is active but [`%[*toc]] directive is provided, the table of contents will be given its own section at the start of the document (after the title page, if any).

## further directions

### additional backends
it is eventually intended to support to following backends, if reasonably practicable.
* [*html]: emit HTML and CSS code to typeset the document. [!in progress]
* [*svg]: emit SVG, taking advantage of its precise layout features to produce a nicely formatted and paginated document. pagination can be accomplished through emitting multiple files or by assigning one layer to each page. [!long term]
* [*groff]: the most important output backend, rivalling [*html]. will allow the document to be typeset in a wide variety of formats, including PDF and manpage. [!short term]
* [*gemtext]: essentially a downrezzing of cortav to make it readable to Gemini clients
* [*ast]: produces a human- and/or machine-readable dump of the document's syntax tree, to aid in debugging or for interoperation with systems that do not support `cortav` direcly. mode [`ast:repr] wil allow selecting formats for the dump. [`ast:rel] can be [`tree] (the default) to emit a hierarchical representation, or [`flat] to emit an array of nodes that convey hierarchy [^flatdoc by naming one another], rather than being placed inside one another. [`tree] is easier for humans to parse; [`flat] is easier for computers. origin information can be included for each node with the flag [`ast:debug-syms], but be aware this will greatly increase file size.
** [`tabtree] [!(default)]: a hierarchical tree view, with the number of tabs preceding an item showing its depth in the tree
** [`sexp]
** [`binary]: emit a raw binary format that is easier for programs to read. maybe an lmdb or cdb file?
** [`json]

	flatdoc: ~~~flat sexp example output [scheme]~~~
		(nodes
			(section (id . "section1")
				(anchor "introduction")
				(kind . "ordinary")
				(label . "section1-heading")
................................................................................
### LCH support
right now, the use of color in the HTML renderer is very unsatisfactory. the accent mechanism operates on the basis of the CSS HSL function, which is not perceptually uniform; different hues will present different mixes of brightness and some (yellows?) may be ugly or unreadable.

the ideal solution would be to simply switch to using LCH based colors. unfortunately, only Safari actually supports the LCH color function right now, and it's unlikely (unless Lea Verou and her husband manage to work a miracle) that Colors Level 4 is going to be implemented very widely any time soon.

this leaves us in an awkward position. we can of course do the math ourselves, working in LCH to implement the internal [`@tone] macro, and then "converting" these colors to HSL. unfortunately, you can't actually convert from LCH to HSL; it's like converting from pounds to kilograms. LCH can represent any color the human visual system can perceive; sRGB can't, and CSS HSL is implemented in sRGB. however, we could at least approximate something that would allow for perceptually uniform brightness, which would be an improvement, and this is probably the direction to go in, unless a miracle occurs and [`lch()] or [`color()] pop up in Blink.

it may be possible to do a more reasonable job of handling colors in the postscript and TeX outputs. unsure about SVG but i assume it suffers the same problems HTML/CSS do. does groff even support color??





### intent files
there's currently no standard way to describe the intent and desired formatting of a document besides placing pragmata in the source file itself. this is extremely suboptimal, as when generating collections of documents, it's ideal to be able to keep all formatting information in one place. users should also be able to specify their own styling overrides that describe the way they prefer to read [`cortav] files, especially for uses like gemini or gopher integration.

at some point soon [`cortav] needs to address this by adding intent files that can be activated from outside the source file, such as with a command line flag or a configuration file setting. these will probably consist of lines that are interpreted as pragmata. in addition to the standard intent format however, individual implementations should feel free to provide their own ways to provide intent metadata; e.g. the reference implementation, which has a lua interpreter available, should be able to take a lua script that runs after the parse stage and generates . this will be particularly useful for the end-user who wishes to specify a particular format she likes reading her files in without forcing that format on everyone she sends the compiled document to, as it will be able to interrogate the document and make intelligent decisions about what pragmata to apply.

intent files should also be able to define [>rsrc resources], [>ctxvar context variables], and macros.







|

|
|


|







 







|



|


|

|

<




>
>
>
>
>
>
>
>
>

|





|




|
|
|
|







 







|





|


|
|
|

|
>







 







|




|







 







|



|













|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|


|



|



|






|







|






|
|
|





|

>
>
>
>
>
>
>
>
>
>

|
<
>
|
|
|








|

|


|
|


>







 







|
|
|







 







|

|







 







|







 







|
|
|
|
|
|
|
|
|
|
|







 







|
|





|







 







|
>
>
>
>







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
..
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
...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
...
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
...
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
...
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
...
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
...
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
...
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
...
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
...
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
....
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
* [*headings]: cortav uses almost the same syntax for headings that markdown does, except it only allows the "ATX style" headings, with one or more hash characters at the start of the line. the only differences from markdown are:
** you can use the unicode section character [`§] instead of [`#] if you're feeling snobby
** you must put a space between the control sequence (the sequence of hashes or section symbols, in this case) and the title text. [`# title] creates a section with the heading text "title", but [`#title] creates a new section with no heading at all; instead, it gives the anonymous section the ID [`title]. and of course, you can combine the two: [`#ttl title] creates a section with the heading text "title" and the ID [`ttl]. what are IDs for? we'll get to that in a little bit
* [*paragraphs] are mostly the same as in markdown, except that a paragraph break occurs after every newline character, not every blank line. paragraphs can be indented by however many spaces you like; such indentation will be ignored. (tabs have a special meaning, however). in cortav, you can also explicitly mark a line of text as a paragraph by preceding it with a period character ([`.]), which is useful if you want to start a paragraph with text that would otherwise be interpreted specially.
* [*italic text] -- or rather, [!emphasized] text -- is written as [`\[!my spiffy italic text\]]. in cortav, these spans can be nested within other spans (or titles, or table cells, or…), and the starting and ending point is unambiguous.
* [*bold text] -- or rather, [*strong] text -- is written as [`\[*my commanding bold text\]].
* [*bold-italic text] -- or rather, [![*emphasized strong text]] -- has no specific notation. rather, you create it by nesting one span within the other, for instance: [`\[*[!my ostentatious bold-italic text\]]].
* [*links] are quite different from their markdown equivalents. cortav does not have inline links, as it is intended to be easily readable in both formatted and plain-text format, and long URLs rather disrupt the flow of reading. rather, a link tag is written with the notation [`\[>nifty-link my nifty link\]], where the word [`nifty-link] immediately following the arrow is an [!identifier] indicating the destination of the link. (instead of a greater-than sign, you can also use the unicode arrow symbol [`→].) if the identifier is the same as one you've assigned to a document object, such as a section, cortav produces a link within the document to that object. otherwise, it will look for a [!reference] (or failing that, a [>rsrc resource]) to tell it the URI for the link. if nothing in the document matches the ID, an error will result and compilation will be aborted. (a reference is a key-value pair created by adding a line like [`nifty-link: https://zombo.com] [!indented by exactly one tab]. you can place this reference anywhere you like so long as it's in the same section; if you want to name a reference in another section, you have to prefix it with that section's ID, e.g. [`\[>spiffy-section.nifty-link my nifty link declared in a spiffy section\]].)
* [*lists] use a different syntax from markdown. you can start a line with a [`*] to create an unordered list, or [`:] to create an ordered list; indentation doesn't matter. if you want to nest list items, instead of putting two spaces before the child item, you just add another star or colon. and of course, you can nest lists of different kinds within one another.
* [*horizontal rules] use roughly the same syntax: three or more hyphens on a line of their own ([`\---]). underlines also work ([`___], [`-_-], [`__-__-__] etc), as do horizontal unicode box drawing characters ([`─ ━ ┈] etc).
* some markdown implementations support [*tables]. cortav does too, using a very simple notation similar to the usual notation used in markdown. a key difference, however, is that cortav table cells can contain any formatting a paragraph can.
* [*underlines] are supported by some markdown implementations. in cortav, you can apply them with the notation [`\[_my underlined text\]] -- please just use them sparingly when you render to HTML!
* [*strikethrough] is supported by some extended versions of markdown. cortav uses the notation [`\[~my deleted text\]], with the intended semantics of text that is being removed by some revision of a document. (you can also denote text that is being [!added] by using a plus sign instead of a tilde)
* [*images] are a bit more complicated, but much more versatile. see the section on [>rsrc resources] for an explanation.
* [*smart quotes] and [*em dashes] are inserted automatically, just as in markdown, provided you have the [>tsmog transmogrify] extension available. (it is part of the reference implementation and defined by the spec, but not required.) in fact, you can insert longer dashes than em dashes just by increasing the number of hyphens. the reference implementation's transmogrifier also translates ascii arrows like [`\-->] into their unicode equivalents ([`→]).
* [*literals] (also known as [*code text]) can be inserted with the [`\[`int main(void);] syntax. note however that literals are not protected from the transmogrifier, and are parsed like any other span, which may cause problems if the source code you're quoting makes use of such forbidden runes. in this case, you'll want to wrap the code span in a raw span. the syntax for this is [`\[`[\\int main(void);\]]], but since this is a bit unwieldy it can also be abbreviated as [`\[`\\int main(void);\]].

of course, this is only a small taste of what cortav can do, not even touching on key features like macros, footnotes, or equation formatting. read the sections on [>onblocks blocks] and [>onspans spans] for all the gory details.

## encoding
a cortav document is made up of a sequence of codepoints. UTF-8 must be supported, but other encodings (such as UTF-32 or C6B) may be supported as well. lines will be derived by splitting the codepoints at the linefeed character or equivalent. note that unearthly encodings like C6B or EBCDIC will need to select their own control sequences.
................................................................................

three more extensions are reserved for identifying a cortav intent file.
* [`ctc] is the shorthand extension
* [`cortavcun] is the canonical disambiguation extension
* [`] is the canonical Corran extension, a byte sequence comprising the unicode codepoints [`U+E3CE U+E3BD U+E3CE]. where the filesystem in question does not specify a filename encoding, the bytes should be expressed in UTF-8.

on systems which use metadata to encode filetype, two values are defined to identify cortav source files
* [`text/x.cortav] should be used when strings or arbitrary byte sequences are supported
* [`CTAV] (that is, the byte sequence [`0x43 54 41 56]) should be used on systems that support only 32-bit file types/4-character type codes like Classic Mac OS.

two more values are defined to identify cortav intent files.
* [`text/x.cortav-intent]
* [`CTVC] (the byte sequence [`0x43 54 56 43])

on systems which do not define a canonical way of encoding the filetype but support extended attributes of some kind, such as linux, an attribute named [$mime] may be created and given the value [`text/x.cortav] or [`text/x.cortav-intent]; alternatively, extensions may be used.

it is also possible to indicate the nature of a cortav file without using filesystem metadata. this is done by prefixing the file with a magic byte sequence. the sequence used depends on the encoding. currently, only sequences for UTF-8 and ASCII are defined, as these are the only encodings supported by the reference implementation. in the event that other implementations add support for other encodings, their sequences will be standardized here.
* for UTF-8 and ASCII plain text files, [`%ct[!\\n]] (that is, the byte sequence [`0x25 63 74 0A]) should be used

consequently, this sequence should be ignored by a cortav parser at the start of a file (except as an indication of file format).

for FreeDesktop-based systems, the [`build/velartrill-cortav.xml] file included in the repository supplies mappings for the extensions and magic byte sequences. a script is also included which can be registered with xdg-open so that double-clicking on a cortav file will render it out and open it in your default web browser. [`$ make install] will generate the necessary FreeDesktop XML files and register them, as well as install the script and the [`cortav] executable itself. for more information see [>refimpl-build building the reference implementation].

##levels levels
not all of cortav's features make sense in every context. for this reason, cortav defines N [!levels] of compliance. for example, a social media platform that enables simple paragraph styling and linking using cortav syntax may claim to be "cortav level 1 compliant". every level [=N] is a strict superset of level [=N-1].
* level 1: [*styling]. simple inline formatting sequences like strong, emphatic, literal, links, etc. math equation styling need not be supported. paragraphs, lists, and references are the only block elements supported. suitable for styling tweets and other very short content.
* level 2: [*layout]. implements header, paragraph, newline, directive, and reference block elements. supports resources at least for remote or attached images. suitable for longer social media posts.
* level 3: [*publishing]. implements all currently standardized core behavior, including zero or more extensions.
* level 4: [*reference]. implements all currently standardized behavior, including [!all] standardized extensions.

! note that which translators are implemented is not specified by level, as this is, naturally, implementation-dependent. (it would make rather little sense for the blurb parser of a cortav-enabled blog engine to support generating PDFs, after all.) level encodes only which features of the cortav [!language] are supported.

##onblocks structure
cortav is based on an HTML-like block model, where a document consists of sections, which are made up of blocks, which may contain a sequence of spans. flows of text are automatically conjoined into spans, and blocks are separated by one or more newlines. this means that, unlike in markdown, a single logical paragraph [*cannot] span multiple ASCII lines. the primary purpose of this was to ensure ease of parsing, but also, both markdown and cortav are supposed to be readable from within a plain text editor. this is the 21st century. every reasonable text editor supports soft word wrap, and if yours doesn't, that's entirely your own damn fault. hard-wrapping lines is incredibly user-hostile, especially to users on mobile devices with small screens. cortav does not allow it.

the first character(s) of every line (the "control sequence") indicates the role of that line. if no control sequence is recognized, the line is treated as a paragraph. the currently supported control sequences are listed below. some control sequences have alternate forms, in order to support modern, readable unicode characters as well as plain ascii text.

* [*paragraphs] ([`.] [` ¶] [`❡]): a paragraph is a simple block of text. the period control sequence is only necessary if the paragraph text starts with text that would be interpreted as a control sequence otherwise
* newlines [` \\]: inserts a line break into previous paragraph and attaches the following text. mostly useful for poetry or lyrics
* [*section starts] [`#] [`§]: starts a new section. all sections have an associated depth, determined by the number of sequence repetitions (e.g. "###" indicates depth three). sections may have headers and IDs; both are optional. IDs, if present, are a sequence of raw-text immediately following the hash marks. if the line has one or more space character followed by styled-text, a header will be attached. the character immediately following the hashes can specify a particular type of section. e.g.:
** [`#] is a simple section break.
** [`#anchor] opens a new section with the ID [`anchor].
** [`# header] opens a new section with the title "header".
** [`#anchor header] opens a new section with both the ID [`anchor] and the title "header".
* [*nonprinting sections] ([`^]): sometimes, you'll want to create a namespace without actually adding a visible new section to the document. you can achieve this by creating a [!nonprinting section] and defining resources within it. nonprinting sections can also be used to store comments, notes, to-dos, or other meta-information that is useful to have in the source file without it becoming a part of the output. nonprinting sections can be used for a sort of "literate markup," where resource and reference definitions can intermingle with human-readable narrative about those definitions.
* [*resource] ([`@]): defines a [!resource]. a resource is a file or object that exists outside of the document but which will are to be included in the document somehow. common examples of resources include images, videos, iframes, or headers/footers. see [>rsrc resources] for more information.
* [*lists] ([`*] [`:]): these are like paragraph nodes, but list nodes that occur next to each other will be arranged so as to show they compose a sequence. depth is determined by the number of stars/colons. like headers, a list entry may have an ID that can be used to refer back to it; it is indicated in the same way. if colons are used, this indicates that the order of the items is signifiant. [`:]-lists and [`*]-lists may be intermixed; however, note than only the last character in the sequence actually controls the type. a blank line terminates the current list.
* [*directives] ([`%]): a directive issues a hint to the renderer in the form of an arbitrary string. directives are normally ignored if they are not supported, but you may cause a warning to be emitted where the directive is not supported with [`%!] or mark a directive critical with [`%!!] so that rendering will entirely fail if it cannot be obeyed.
* [*comments] ([`%%]): a comment is a line of text that is simply ignored by the renderer.
* [*asides] ([`!]): indicates text that diverges from the narrative, and can be skipped without interrupting it. think of it like block-level parentheses. asides which follow one another are merged as paragraphs of the same aside, usually represented as a sort of box. if the first line of an aside contains a colon, the stretch of styled-text from the beginning to the aside to the colon will be treated as a "type heading," e.g. "Warning:"
* [*code] ([`~~~]): a line beginning with ~~~ begins or terminates a block of code. code blocks are by default not parsed, but parsing can be activated by preceding the code block with an [`%[*expand]] directive. the opening line should look like one of the below
** [`~~~]
** [`~~~ language] (markdown-style shorthand syntax)
** [`~~~ \[language\] ~~~] (cortav syntax)
** [`~~~ \[language\] #id ~~~]
................................................................................
** [`~~~ title ~~~]
** [`~~~ title \[language\] ~~~]
** [`~~~ \[language\] title ~~~]
** [`~~~ title \[language\] #id ~~~]
*[*reference] (tab): a line beginning with a tab is treated as a "reference." references hold out-of-line metadata for preceding text like links and footnotes. a reference consists of an identifier followed by a colon and an arbitrary number of spaces or tabs, followed by text. whether this text is interpreted as raw-text or styled-text depends on the context in which the reference is used. in encodings without tab characters, two preceding blanks can be used instead.
* [*quotation] ([`<]): a line of the form [`<[$name]> [$quote]] denotes an utterance by [$name].
* [*blockquote] ([`>]): alternate blockquote syntax. can be nested by repeating the [`>] character.
* [*subtitle/caption] ([`\--]): attaches a subtitle to the previous header, or caption to the previous object
* [*embed] ([`&]): embeds a referenced object. can be used to show images or repeat previously defined objects like lists or tables, optionally with a caption.
** [`&$[$macro] [$arg1]|[$arg2]|[$argn]…] invokes a block-level macro with the supplied arguments
*** [`&$mymacro arg 1|arg 2|arg 3]
** [`&[$image]] embeds an image or other block-level object. [!image] can be a reference with a url or file path, or it can be an embed section (e.g. for SVG files)
***[`&myimg All that remained of the unfortunate blood magic pageant contestants and audience (police photo)]
** [`&-[$ident] [$styled-text]] embeds a closed disclosure element containing the text of the named object (a nonprinting section or cortav resource should usually be used to store the content; it can also name an image or video, of course). in interactive outputs, this will display as a block which can be clicked on to view the full contents of the referenced object [$ident]; if [$styled-text] is present, it overrides the title of the section you are embedding (if any). in static outputs, the disclosure object will display as an enclosed box with [$styled-text] as the title text
*** [`&-ex-a Prosecution Exhibit A (GRAPHIC CONTENT)]
** [`&+[$section] [$styled-text]] is like the above, but the disclosure element is open by default
* [*horizontal rule] ([`\---]): inserts a horizontal rule or other context break; does not end the section. must be followed by newline. underlines can also be used in place of dashes ([`___], [`-_-], [`__-__-__] etc), as can horizontal unicode box drawing characters ([`─ ━ ┈] etc).
* [*page break] ([`\^^]): for formats that support pagination, like EPUB or HTML (when printed), indicates that the rest of the current page should be blank. for formats that do not, extra margins will be inserted. does not create a new section
* [*page rule] ([`\^-^]): inserts a page break for formats that support them, and a horizontal rule for formats that do not. does not create a new section. comprised of any number of horizontal rule characters surrounded by a pair of carets (e.g. [`^-^] [`^_^] [`^----^] [`^__--^] [`^┈┈┈┈┈^])
* [*table cells] ([`+ |]): see [>ex.tab table examples].
* [*equations] ([`=]): block-level equations can be inserted with the [`=] sequence
* [*cross-references] ([`=>] [`⇒]): inserts a block-level link. uses the same syntax as span links ([`⇒[$ident] [$styled-text]]). can be followed by a caption to add a longer descriptive text. especially useful for gemtext output. ident can be omitted to cross-reference, for example, a physical book.
* [*empty lines] (that is, lines consisting of nothing but whitespace) constitute a [!break], which terminates multiline objects that do not have a dedicated termination sequence, for example lists and asides.

##onspans styled text
most blocks contain a sequence of spans. these spans are produced by interpreting a stream of [*styled-text] following the control sequence. styled-text is a sequence of codepoints potentially interspersed with escapes. an escape is formed by an open square bracket [`\[] followed by a [*span control sequence], and arguments for that sequence like more styled-text. escapes can be nested.

* strong {obj *|styled-text}: causes its text to stand out from the narrative, generally rendered as bold or a brighter color.
* emphatic {obj !|styled-text}: indicates that its text should be spoken with emphasis, generally rendered as italics
................................................................................
* literal {obj `|styled-text}: indicates that its text is a reference to a literal sequence of characters or other discrete token. generally rendered in monospace
* variable {obj $|styled-text}: indicates that its text is a stand-in that will be replaced with what it names. generally rendered in italic monospace, ideally of a different color
* underline {obj _|styled-text}: underlines the text. use sparingly on text intended for webpages -- underlined text  [!is] distinct from links, but underlining non-links is still a violation of convention.
* strikeout {obj ~|styled-text}: indicates that its text should be struck through or otherwise indicated for deletion
* insertion {obj +|styled-text}: indicates that its text should be indicated as a new addition to the text body.
** consider using a macro definition [`\edit: [~[#1]][+[#2]]] to save typing if you are doing editing work
* link \[>[!ref] [!styled-text]\]: produces a hyperlink or cross-reference denoted by [$ref], which may be either a URL specified with a reference or the name of an object like an image or section elsewhere in the document. the unicode characters [`→] and [`🔗] can also be used instead of [`>] to denote a link.
* footnote {span ^|ref|[$styled-text]}: annotates the text with a defined footnote. in interactive output media [`\[^citations.qtheo Quantum Theosophy: A Neophyte's Catechism]] will insert a link with the text [`Quantum Theosophy: A Neophyte's Catechism] that, when clicked, causes a footnote to pop up on the screen. for static output media, the text will simply have a superscript integer after it denoting where the footnote is to be found.
* superscript {obj '|[$styled-text]}
* subscript {obj ,|[$styled-text]}
* raw {obj \\ |[$raw-text]}: causes all characters within to be interpreted literally, without expansion. the only special characters are square brackets, which must have a matching closing bracket, and backslashes.
* raw literal \[$\\[!raw-text]\]: shorthand for [\[$[\…]]]
* macro [` \{[!name] [!arguments]}]: invokes a [>ex.mac macro], specified with a reference
* argument {obj #|var}: in macros only, inserts the [$var]-th argument. otherwise, inserts a context variable provided by the renderer.
* raw argument {obj ##|var}: like above, but does not evaluate [$var].
* term {obj &|name}, {span &|name|[$expansion]}: quotes a defined term with a link to its definition, optionally with a custom expansion of the term (for instance, to expand the first use of an acronym)
* inline image {obj &@|name}: shows a small image or other object inline. the unicode character [`🖼] can also be used instead of [`&@].
* unicode codepoint {obj U+|hex-integer}: inserts an arbitrary UCS codepoint in the output, specified by [$hex-integer]. lowercase [`u] is also legal.
* math mode {obj =|equation}: activates additional transformations on the span to format it as a mathematical equation; e.g. [`*] becomes [`×] and [`/] --> [`÷].
* extension {span %|ext|…}: invokes extension named in [$ext]. [$ext] will usually be an extension name followed by a symbol (often a period) and then an extension-specific directive, although for some simple extensions it may just be the plain extension name. further syntax and semantics depend on the extension. this syntax can also be used to apply formatting specific to certain renderers, such as assigning a CSS class in the [`html] renderer ([`\[%html.myclass my [!styled] text]]).
................................................................................

##ident identifiers
any identifier (including a reference) that is defined within a named section must be referred to from outside that section as [`[!sec].[!obj]], where [$sec] is the ID of the containing section and [$obj] is the ID of the object one wishes to reference.

##rsrc resources
a [!resource] represents content that is not encoded directly into the source file, but which is embedded by some means in the output. resources can either be [!embedded], in which case they are compiled into the final document itself, or they can be [!linked], in which case the final document only contains a URI or similar tag referencing the resource. not all render backends support both linking and embedding embedding, nor do all backends support all object types (for instance, [`groff] does not support video embedding.)

a resource definition is begun by line consisting of an [`@] sign and an [>ident identifier].  this line is followed by any number of parameters. a parameter is a line beginning with a single tab, a keyword, a colon, and a then a value. additional lines can be added to a parameter by following it with a line that consists of two tabs followed by the text you wish to add. (this is the same syntax used by references.) a resource definition is terminated by a break, or any line that does not begin with a tab

a resource definition in use looks like this:

~~~cortav
this is a demonstration of resources
@smiley
	src: link image/webp http://cdn.example.net/img/smile.webp
		  link image/png file:img/smile.png
		  embed image/gif file img/smile.gif
	desc: the Smiling Man would like to see you in his office
here is the resource in span context [&smiley]
and here it is in block context:
&smiley
~~~

rendered as HTML, this might produce the following:

~~~html
<style>
	.res-smiley {
		content: image-set(
			url(http://cdn.example.net/img/smile.webp) type(image/webp),
			url(img/smile.png) type(image/png),
			url(data:image/gif;base64,/* … */) type(image/gif)
		); /* this will actually be repeated with a -webkit- prefix */
................................................................................
<p>this is a demonstration of resources</p>
<p>here is the resource in span context: <span class="res-smiley"></span></p>
<p>and here it is in block context:</p>
<div class=".res-smiley"></div>
~~~

note that empty elements with CSS classes are used in the output, to avoid repeating long image definitions (especially base64 inline encoded ones!)

in the opening line of a resource declaration, the identifier can be omitted. in this case, rather than registering a new resource in the current section, the resource will be inserted as a block at the position where it is defined. this is a shorthand for resources that are only used once. for resources used inline or multiple times, an identifier must be defined.

as an additional shortcut, a resource with only one source file can place its source specification on the opening line, separated by whitespace from the opening sequence. this means that the following are identical.

~~~cortav
@smiley link image/webp file:smile.webp
	desc: the Smiling Man would like to see you in his office

@smiley
	src: link image/webp file:smile.webp
	desc: the Smiling Man would like to see you in his office
~~~

this can be combined with ID omission for a very concise block-level image syntax.

~~~cortav
@smiley
	src: link image/webp file:smile.webp
&smiley

%% is the same as

@smiley link image/webp file:smile.webp
&smiley

%% is the same as

@ link image/webp file:smile.webp

%% is almost the same as

@ image/webp;base64 (*
	%% inhuman gurgling in textual form
*)

%% (except that the last wil require embedding)
~~~

inline resources are defined a bit differently:

~~~cortav
@smiling-man-business-card text/plain {
	THE SMILING MAN  | tel. 0-Ω00-666█
	if you can read this | email: nameless@smiles.gov
................................................................................
@smiling-man-business-card image/png;base64 {
	%% incomprehensible gibbering redacted
}
~~~

for an inline resource, the identifier is followed by a MIME type and an opening bracket. the opening bracket may be any of the characters [`\{][`\[][`(][`<], and can optionally be followed by additional characters to help disambiguate the closing bracket. the closing bracket is determined by "flipping" the opening bracket, producing bracket pairs like the following:
* [`\{:][`:}]
* [`\<!--] [`\--!>]
* [`(*<][`>*)]
* [`<>][`<>] [!(disables nesting!)]
if the open and closing brackets are distinguishable, they will nest appropriately, meaning that [`\{][`\}] alone is very likely to be a safe choice to escape a syntactically correct C program (that doesn't abuse macros too badly). brackets are searched for during parsing; encoded resources are not decoded until a later stage, so a closing bracket character in a base64-encoded text file cannot break out of its escaping.

as a convenience, if the first line of the resource definition begins with a single tab, one tab will be dropped from every following line in order to allow legible indentation. similarly, if an opening bracket is followed immediately by a newline, this newline is discarded.

text within a resource definition body is not expanded unless the resource definition is preceded with an [`%[*expand]] directive or the resource MIME type is [`text/x.cortav]. if an expand directive is found, the MIME type will be used to try and determine an appropriate type of formatting, potentially invoking a separate renderer. for example, [`text/html] will invoke the [`html] backend, and [`application/x-troff] will invoke the [`groff] backend. if no suitable renderer is available, expansions will generate only plain text.

two suffixes are accepted: [`;base64] and [`;hex]. the former will decode the presented strings using the base64 algorithm to obtain the resources data; the second will ignore all characters but ASCII hexadecimal digits and derive the resource data byte-by-byte by reading in hexadecimal pairs. for instance, the following sections are equivalent:

~~~cortav
@propaganda text/plain {
	WORLDGOV SAYS
	“don't waste time with unproductive thoughts
	 your wages will be docked accordingly”
}
~~~
~~~cortav
@propaganda text/plain;hex {
	574f 524c 4447 4f56 2053 4159 530a e280 9c64 6f6e 2774 2077 6173
	7465 2074 696d 6520 7769 7468 2075 6e70 726f 6475 6374 6976 6520
	7468 6f75 6768 7473 0a20 796f 7572 2077 6167 6573 2077 696c 6c20
	6265 2064 6f63 6b65 6420 6163 636f 7264 696e 676c 79e2 809d 0a
}
~~~
~~~cortav
@propaganda text/plain;base64 {
	V09STERHT1YgU0FZUwrigJxkb24ndCB3YXN0ZSB0aW1lIHdpdGggdW5wcm9kdWN0aXZlIHRob3Vn
	aHRzCiB5b3VyIHdhZ2VzIHdpbGwgYmUgZG9ja2VkIGFjY29yZGluZ2x54oCdCg==
}
~~~

inline resources can also offer a cleaner syntax for complex multiline macros.
~~~cortav
@def text/x.cortav {
	* [*[#1]] [!([#2])
	*: [#3]
}
&def nuclear bunker|n|that which will not protect you from the Smiling Man
~~~
to make this usage simpler, resources with a type of [`text/x.cortav] can omit the MIME type field.

inline resources are a great way to extend cortav with implementation-dependent features. say you want mathtex in your cortav renderer -- all you have to do is support a new MIME type [`text/x.mathtex], and then the users can embed their math equations like so:

~~~cortav
and as we see from the value of κ below, Bose-Fleischer-Kincaid entities of Carlyle subtype γ lack interaction with the putative "Higgs field" of Athabaskan Windchime Theory, seemingly ruling out any possibility of direct interaction with the spacetime metric, and consequently removing the maximal density "limitations" that exist for bosonic matter.
@ text/x.mathtex {>
	%% divide subtract differentiate blah blah blah i don't know math
<}
given the selective cross-interaction of γ-BFKs, we conclude that, under the prevailing cosmocelestial paradigm, the answer to the age-old question of how many angels can dance on the head of a pin is "as many as would like to."
~~~

### supported parameters
* [`src] (all): specifies where to find the file, what it is, and how to embed it. each line of [`src] should consist of two  whitespace-separated words: MIME type and URI. the specification can also be prefixed with an extra word, [`auto], [`link], or [`embed], to control how the resource will be referenced from the output file.

** reference mode: the optional first word; if the requested reference mode is not applicable or valid for the output format or URI given, the source line will be skipped over.
*** [`embed]: loads the resource at build time and embeds it into the output file. not all implementations may allow loading remote network resources at build time.
*** [`link]: only embeds a reference to the location of the resource. use this for e.g. live iframes, dynamic images, or images hosted by a CDN.
*** [`auto]: embeds a reference in file formats where that's practical, and use a remote reference otherwise. [`auto] is the default if the first word is omitted.
** MIME types: which file types are supported depends on the individual implementation and renderer backend; additionally, extensions can add support for extra types. MIME-types that have no available handler will, where possible, result in an attachment that can be extracted by the user, usually by clicking on a link. however, the following should be usable with all compliant implementations
*** [`image/*] (graphical outputs only)
*** [`video/*] (interactive outputs only)
*** [`image/svg+xml] is handled specially for HTML files, and may or may not be compatible with other renderer backends.
*** [`font/*] can be used with the HTML backend to reference a web font
*** [`font/woff2] can be used with the HTML backend to reference a web font
*** [`text/plain] (will be inserted as a preformatted text block)
*** [`text/css] (can be used when producing HTML files to link in an extra stylesheet, either by embedding it or referencing it from the header)
*** [`text/x.cortav] (will be parsed and inserted as a formatted text block; context variables can be passed to the file by setting [`ctx.[$var]] parameters on the resource, e.g. [`ctx.recipient-name: Mr. Winthrop])
*** [`application/x-troff] can be used to supply sections of text written in raw [`groff] syntax. these are ignored by other renderers.
*** [`text/html] can be used to supply sections of text written in raw HTML. these are ignored by non-HTML outputs.
*** any MIME-type that matches the type of file being generated by the renderer can be used to include a block of data that will be passed directly to the renderer.
** URI types: additional URI types can be added by extensions or different implementations, but every compliant implementation must support these URIs.
*** [`http], [`https]/[`http+tls]: accesses resources over HTTP. add a [`file] fallback if possible for the benefit of renderers/viewers that do not have internet access abilities.
*** [`file]: references local files. (the meaning of "local" varies depending on the translation format.) absolute paths should begin [`file:/]; the slash should be omitted for relative paths. note that this doesn't have quite the same meaning as in HTML -- [`file] can (and usually should be) used with HTML outputs to refer to resources that reside on the same server. a cortav URI of [`file:/etc/passwd] will actually result in the link [`/etc/passwd], not [`file:///etc/passwd] when converted to HTML. generally, you only should use [`http] when you're referring to a resource that exists on a different domain.
*** [`name]: a special URI used generally for referencing resources that are already installed on a target system and do not need to be embedded or linked, the name and type are enough for a renderer on another machine to locate the correct resource. this is useful mostly for [>fonts fonts], where it's more typical to refer to fonts that are installed on your system rather than providing paths to font files.
*** [`gemini]: accesses resources over the gemini protocol. currently you should really only use this for [`local] resources unless you're using the gemtext renderer backend, since nothing but gemini browsers are liable to support this protocol.
*** [`role]: specifies an abstract resource determined by context, e.g. [`role:backdrop], [`role:body-font]. for use by translators to formats which make provisions for viewer control. a [`role] URI is special in that it is never embedded; it always depends on context — user preferences, environment variables, system stylesheets, what have you — at the time the output file is viewed, rather than the time of the input file being rendered.
* [`desc]: supplies a narrative description of the resources, for use as an "alt-text" when the image cannot be loaded and for screenreaders.
* [`detail]: supplies extra narrative commentary that is displayed contextually, e.g. when the user hovers her mouse cursor over the embedded object. also used for [`desc] if [`desc] is not supplied.

note that in certain cases, full MIME types do not need to be used. say you're defining a font with the [`name] URI -- you can't necessary know what file type the system fonts on another computer are going to be. in this case, you can just write [`font] instead of [`font/ttf] or [`font/woff2] or similar. all cortav needs to know in this case is what abstract kind of object you're referencing. [`groff] fonts (referenced with the [`dit] URI) don't have a specific MIME type either.


##ctxvar context variables
................................................................................

when a document parse begins, the font stack is empty (unless a default font has already been loaded by an intent file).
when the font stack is empty, cortav does not include font specifications in its output, and thus will use whatever the default of the various rendering programs is.

to use fonts, we first have to define the fonts as [>rsrc resources].

~~~cortav
%% first, we create a new nonprinting section to namespace the fonts
^fonts
we then define each font as a resource:
@serif
	src: auto font name:Alegreya
		embed  font/ttf file:project-fonts/alegreya.ttf
		link font/woff2 file:/assets/font/alegreya.woff2
		auto font name:Times New Roman
		auto font dit:TR/bold=TRB/italic=TRI/bold,italic=TRBI
@sans
................................................................................
	font-family: "fontdef-sans";
	src: local("Alegreya Sans"),
		local("Open Sans"),
		local("sans-serif");
}
~~~

there are two things that aren't super clear from the CSS, however. notice how we used [`auto] on a couple of those specs? this means it's up to the renderer to decide whether to link or embed the font. [!in HTML], a font specified by name can't really be embedded, but for some translation formats such as PDF or PostScript, a system font can be selected by name and then embedded into the output. [`auto] lets us produce valid HTML while still taking advantage of font embedding in other formats.

now that we have our font families defined, we can use their identifiers with the [`%[*font]] directive to control the font stack. the first thing we need to do is push a new font context, as the stack starts out empty. there's two ways we can do this:
	fnd: [`%[*font] [#1]]
* {fnd dup} will create a copy of the current font context, allowing us to make some changes and then revert later with the {fnd pop} command. this isn't useful in our case, however, because right now the stack is empty; there's nothing to duplicate.
* {fnd new} will create a brand new empty context for us to work with and push it to the stack. this can also be used to temporarily revert to the system default fonts, and then switch back with {fnd pop}.
* {fnd set} changes one or more entries in the current font context. it can take a space-separated list of arguments in the form [`[$entry]=[$font-id]]. the supported entries are:
** [`body]: the fallback font. if only this is set in a given font context, it will be used for everything
** [`paragraph]: the font used for normal paragraphs
** [`header]: the font used in headers
................................................................................
* {d include} transcludes another file
* {d import} reads in the contents of another file as an embeddable section
* {d quote} transcludes another file, without expanding the text except for paragraphs 
* {d embed}, where possible, embeds another file as an object within the current one. in HTML this could be accomplished with e.g. an iframe.
* {d expand} causes the next object (usually a code block) to be fully expanded when it would otherwise not be
* {d font} controls the font stack, for outputs that support changing fonts. see [>fonts fonts] for more information.
* {d lang} changes the current language, which is used by extensions to e.g. control typographical conventions, and may be encoded into the output by certain renderers (e.g. HTML). note that quotes and blockquotes can be set to a separate language with a simpler syntax. the language should be notated using IETF language tags
** {d lang is x-ranuir-Cent-CR8} sets the current language to Ranuir as spoken in the Central Worlds, written in Corran and encoded using C6B+U8L (which can also be interpreted as UTF-8, albeit with some lost semantics). this might be used at the top of a document to set its primary language.
** {d lang push gsw-u-sd-chzh} temporarily switches to Zürich German, e.g. to quote a German passage in an otherwise Ranuir document
** {d lang sec en-US} switches to American English for the duration of a section. does not affect the language stack.
** {d lang pop} drops the current language off the language stack, returning to whatever was pushed or set before it. this would be used, for instance, at the end of a passage
* {d pragma} supplies semantic data about author intent, the kind of information the document contains and hints about how it should be displayed to the user. think of them like offhand remarks to the renderer -- there's no guarantee that it'll pay any attention, but if it does, your document will look better. pragmas have no scope; they affect the entire document. the pragma function exists primarily as a means to allow parameters that would normally need to be specified on e.g. the command line to be encoded in the document instead in a way that multiple implementations can understand. a few standard pragmas are defined.
** {d pragma layout} gives a hint on how the document should be layed out. the first hint that is understood will be applied; all others will be discarded. standard hints include:
*** [`essay]
*** [`narrative]
................................................................................

	corran: http://ʞ.cc/fic/spirals/society
	tengwar: https://en.wikipedia.org/wiki/Tengwar

###refimpl-switches switches
[`cortav.lua] offers various switches to control its behavior.
+ long                      + short + function                                    +
| [`\--out [!file]]              :|:[`-o]:| sets the output file (default stdout)       |
| [`\--log [!file]]              :|:[`-l]:| sets the log file (default stderr)          |
| [`\--define [!var] [!val]]     :|:[`-d]:| sets the context variable [$var] to [$val]  |
| [`\--mode-set [!mode]]         :|:[`-y]:| activates the [>refimpl-mode mode] with ID [!mode]
| [`\--mode-clear [!mode]]       :|:[`-n]:| disables the mode with ID [!mode]           |
| [`\--mode [!id] [!val]]        :|:[`-m]:| configures mode [!id] with the value [!val] |
| [`\--mode-set-weak [!mode]]    :|:[`-Y]:| activates the [>refimpl-mode mode] with ID [!mode] if the source file does not specify otherwise
| [`\--mode-clear-weak [!mode]]  :|:[`-N]:| disables the mode with ID [$mode] if the source file does not specify otherwise
| [`\--mode-weak [!id] [!val]]   :|:[`-M]:| configures mode [$id] with the value [$val] if the source file does not specify otherwise
| [`\--help]                     :|:[`-h]:| display online help                         |
| [`\--version]                  :|:[`-V]:| display the interpreter version             |

###refimpl-mode modes
most of [`cortav.lua]'s implementation-specific behavior is controlled by use of [!modes]. these are namespaced options which may have a boolean, string, or numeric value. boolean modes are set with the [`-y] [`-n] flags; other modes use the [`-m] flags.

most modes are defined by the renderer backend. the following modes affect the behavior of the frontend:

+ ID                 + type   + effect
................................................................................
if the [`toc] extension is active but [`%[*toc]] directive is provided, the table of contents will be given its own section at the start of the document (after the title page, if any).

## further directions

### additional backends
it is eventually intended to support to following backends, if reasonably practicable.
* [*html]: emit HTML and CSS code to typeset the document. [!in progress]
* [*svg]: emit SVG, taking advantage of its precise layout features to produce a nicely formatted and paginated document. pagination can perhaps be accomplished through emitting multiple files (somewhat problematic) or by assigning one layer to each page. [!long term]
* [*groff]: the most important output backend, rivalling [*html]. will allow the document to be typeset in a wide variety of formats, including PDF and manpage. [!in progress]
* [*gemtext]: essentially a downrezzing of cortav to make it readable to Gemini clients
* [*ast]: produces a human- and/or machine-readable dump of the document's syntax tree, to aid in debugging or for interoperation with systems that do not support `cortav` direcly. mode [`ast:repr] wil allow selecting formats for the dump. [`ast:rel] can be [`tree] (the default) to emit a hierarchical representation, or [`flat] to emit an array of nodes that convey hierarchy [^flatdoc by naming one another], rather than being placed inside one another. [`tree] is easier for humans to parse; [`flat] is easier for computers. origin information can be included for each node with the flag [`ast:debug-syms], but be aware this will greatly increase file size.
** [`tabtree] [!(default)]: a hierarchical tree view, with the number of tabs preceding an item showing its depth in the tree
** [`sexp]
** [`binary]: emit a raw binary format that is easier for programs to read. maybe an lmdb or cdb file?
** [`json]: obligatory, alas

	flatdoc: ~~~flat sexp example output [scheme]~~~
		(nodes
			(section (id . "section1")
				(anchor "introduction")
				(kind . "ordinary")
				(label . "section1-heading")
................................................................................
### LCH support
right now, the use of color in the HTML renderer is very unsatisfactory. the accent mechanism operates on the basis of the CSS HSL function, which is not perceptually uniform; different hues will present different mixes of brightness and some (yellows?) may be ugly or unreadable.

the ideal solution would be to simply switch to using LCH based colors. unfortunately, only Safari actually supports the LCH color function right now, and it's unlikely (unless Lea Verou and her husband manage to work a miracle) that Colors Level 4 is going to be implemented very widely any time soon.

this leaves us in an awkward position. we can of course do the math ourselves, working in LCH to implement the internal [`@tone] macro, and then "converting" these colors to HSL. unfortunately, you can't actually convert from LCH to HSL; it's like converting from pounds to kilograms. LCH can represent any color the human visual system can perceive; sRGB can't, and CSS HSL is implemented in sRGB. however, we could at least approximate something that would allow for perceptually uniform brightness, which would be an improvement, and this is probably the direction to go in, unless a miracle occurs and [`lch()] or [`color()] pop up in Blink.

it may be possible to do a more reasonable job of handling colors in the postscript and TeX outputs. unsure about SVG but i assume it suffers the same problems HTML/CSS do. groff lets us choose between [`rgb] and [`cmyk] for specifying color, with no explanation of what those mean.

currently all internal colors are expressed and stored as HSL, and we're using code borrowed from my Minetest mod [`[>sorcrep sorcery]] & written by glowpelt for converting that into RGB for non-HTML outputs like groff. probably what should be done is to switch to LCH internally, accept both HSL and LCH input, and "downres" to the best representation each format can support. that's probably going to have to wait until someone who knows a bit more about color theory and math than me can do it (paging Lea Verou)

	sorcrep: https://c.hale.su/sorcery

### intent files
there's currently no standard way to describe the intent and desired formatting of a document besides placing pragmata in the source file itself. this is extremely suboptimal, as when generating collections of documents, it's ideal to be able to keep all formatting information in one place. users should also be able to specify their own styling overrides that describe the way they prefer to read [`cortav] files, especially for uses like gemini or gopher integration.

at some point soon [`cortav] needs to address this by adding intent files that can be activated from outside the source file, such as with a command line flag or a configuration file setting. these will probably consist of lines that are interpreted as pragmata. in addition to the standard intent format however, individual implementations should feel free to provide their own ways to provide intent metadata; e.g. the reference implementation, which has a lua interpreter available, should be able to take a lua script that runs after the parse stage and generates . this will be particularly useful for the end-user who wishes to specify a particular format she likes reading her files in without forcing that format on everyone she sends the compiled document to, as it will be able to interrogate the document and make intelligent decisions about what pragmata to apply.

intent files should also be able to define [>rsrc resources], [>ctxvar context variables], and macros.

Modified cortav.lua from [bf3719fe9a] to [c52f4282f5].

1148
1149
1150
1151
1152
1153
1154



1155
1156
1157
1158
1159
1160
1161
....
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290






1291
1292
1293
1294
1295
1296
1297
	{fn = insert_paragraph};
}

function ct.parse_line(l, ctx, dest)
	local newspan
	local job = ctx.doc.stage.job
	job:hook('line_read',ctx,l)



	if ctx.mode then
		if ctx.mode.kind == 'code' then
			if l and l:match '^~~~%s*$' then
				job:hook('block_listing_end',ctx,ctx.mode.listing)
				job:hook('mode_switch', c, nil)
				ctx.mode = nil
			else
................................................................................
				local lines = ss.str.breaklines(ctx.doc.enc, r.props.src)
				local srcs = {}
				for i,l in ipairs(lines) do
					local args = ss.str.breakwords(ctx.doc.enc, l, 2, {escape=true})
					if #args < 3 then
						r.origin:fail('invalid syntax for resource %s', t.ref)
					end
					local mimebreak = function(s)
						local wds = ss.str.split(ctx.doc.enc, s, '/', 1, {escape=true})
						return wds
					end
					local mime = mimebreak(args[2]);
					local mimeclasses = {
						['application/svg+xml'] = 'image';
					}
					local class = mimeclasses[mime]
					table.insert(srcs, {
						mode = args[1];
						mime = mime;
						uri = args[3];
						class = class or mime[1];
					})
				end
				 --ideally move this into its own mimetype lib
				local kind = r.props.as or srcs[1].class
				r.class = kind
				r.srcs = srcs






			end
		end
	end
	ctx.doc.stage = nil
	ctx.doc.docjob:hook('meddle_ast')
	return ctx.doc
end







>
>
>







 







<
<
<
<
|
<
<
<









<
<

>
>
>
>
>
>







1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
....
1267
1268
1269
1270
1271
1272
1273




1274



1275
1276
1277
1278
1279
1280
1281
1282
1283


1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
	{fn = insert_paragraph};
}

function ct.parse_line(l, ctx, dest)
	local newspan
	local job = ctx.doc.stage.job
	job:hook('line_read',ctx,l)
	if l then
		l = l:gsub("^ +","") -- trim leading spaces
	end
	if ctx.mode then
		if ctx.mode.kind == 'code' then
			if l and l:match '^~~~%s*$' then
				job:hook('block_listing_end',ctx,ctx.mode.listing)
				job:hook('mode_switch', c, nil)
				ctx.mode = nil
			else
................................................................................
				local lines = ss.str.breaklines(ctx.doc.enc, r.props.src)
				local srcs = {}
				for i,l in ipairs(lines) do
					local args = ss.str.breakwords(ctx.doc.enc, l, 2, {escape=true})
					if #args < 3 then
						r.origin:fail('invalid syntax for resource %s', t.ref)
					end




					local mime = ss.mime(args[2]);



					local class = mimeclasses[mime]
					table.insert(srcs, {
						mode = args[1];
						mime = mime;
						uri = args[3];
						class = class or mime[1];
					})
				end
				 --ideally move this into its own mimetype lib


				r.srcs = srcs
				-- note that resources do not themselves have kinds. when a
				-- document requests to insert a resource, the renderer must
				-- iterate through the sources and find the first source it
				-- is capable of emitting. this allows constructions like
				-- emitting a video for HTML outputs, a photo for printers,
				-- and a screenplay for tty/plaintext outputs.
			end
		end
	end
	ctx.doc.stage = nil
	ctx.doc.docjob:hook('meddle_ast')
	return ctx.doc
end

Modified makefile from [9ea6c48a8b] to [fbd94cf6db].

94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

$(build)/cortav.html: cortav.ct $(build)/$(executable) | $(build)/
	$(build)/$(executable) $< -o $@ -m render:format html -y html:fossil-uv

.PHONY: syncdoc
syncdoc: $(build)/cortav.html
	fossil uv add $< --as cortav.html
	fossil uv sync

# clean is written in overly cautious fashion to minimize damage,
# just in case it ever gets invoked in a bad way
.PHONY: clean
clean:
	rm -f $(build)/*.{html,lc,sh,txt,desktop} \
	      $(build)/$(executable){,.bin}







|







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

$(build)/cortav.html: cortav.ct $(build)/$(executable) | $(build)/
	$(build)/$(executable) $< -o $@ -m render:format html -y html:fossil-uv

.PHONY: syncdoc
syncdoc: $(build)/cortav.html
	fossil uv add $< --as cortav.html
	fossil uv sync --all

# clean is written in overly cautious fashion to minimize damage,
# just in case it ever gets invoked in a bad way
.PHONY: clean
clean:
	rm -f $(build)/*.{html,lc,sh,txt,desktop} \
	      $(build)/$(executable){,.bin}

Modified render/groff.lua from [ab8e0fd21b] to [62c90e9915].

40
41
42
43
44
45
46




47
48
49
50
51
52
53
..
61
62
63
64
65
66
67




68
69
70





71
72
73
74
75
76
77
...
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
...
212
213
214
215
216
217
218
219
220
221
222
223

224
225
226
227
228
229
230
...
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
...
419
420
421
422
423
424
425

426
427
428
429
430
431
432


433
434
435
436
437
438
439
...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
...
485
486
487
488
489
490
491


492
493
494
495
496
497
498
...
505
506
507
508
509
510
511



512


513
514
515
516
517
518
519
520
521
			if me.linbuf == nil then
				me.linbuf = ss.strac()
			end
			me.linbuf(text)
		end;
		txt = function(me, str, ...)
			if str == nil then return end




			me:raw(gsan(str))
			-- WARN this will cause problems if str is ever allowed to
			-- include a line break. we can sanitize by converting
			-- every line break into a new entry in the table, but i
			-- don't think it should be possible for a \n to reach us
			-- at this point, so i'm omitting the safety check as it
			-- would involve an excessive hit to performance
................................................................................
			me:flush()
			me:txt(...)
		end;
		req = function(me, r)
			me:flush()
			table.insert(me.lines, '.'..r)
		end;




		esc = function(me, e)
			me:raw('\\' .. e)
		end;





		flush = function(me)
			if me.linbuf ~= nil then
				local line = me.linbuf:compile()
				local first = line:sub(1,1)
				-- make sure our lines aren't accidentally interpreted
				-- as groff requests. groff is kinda hostile to script
				-- generation, huh?
................................................................................
		};
		color = {'.color'};
		insert = {};
		footnote = {
			'.de footnote-blank';
			'.  sp 0.25m';
			'..';

			'.ev footnote-env';
			'.  ps 8p';
			'.  in 0.5c';
			'.  blm footnote-blank';
			'.ev';

			'.de footnote-print';
-- 			'.  sp |\\\\n[.p]u-\\\\n[footnote-pos]u';
			'.  sp 0.5c';
			'.  ev footnote-env';

			'.    fn';

			'.  ev';
			'.  rm fn';
			'.  nr footnote-pos 0';
			-- move the trap past the bottom of the page so it's not
			-- invoked again until more footnotes have been assembled
			'.  ch footnote-print |\\\\n[.p]u+10';
			'.  bp';
			'..';

			'.wh |\\n[.p]u footnote-print';
		};
		root = {
		-- these are macros included in all documents
		-- page offset is hideously broken and unusable; we
		-- zero it out so we can use .in to control indents
		-- instead. note that the upshot of this is we need
		-- to manually specify the indent in every other
		-- environment from now on, .evc doesn't seem to cut it
		-- set up the page title environment & trap
			"'in 2c";
			"'ll 18c";
			"'po 0";
			"'ps 13p";
			"'vs 15p";
			".ev pgti";
			".  evc 0";
			".  fam H";
			".  ps 10pt";
................................................................................
			'.  lt 19c';
			".  tl '\\\\*[doctitle]'\\fB\\\\*[title]\\f[]'%'";
			'.  po 0';
			".  br";
			'.  ev';
			'.  sp 1.2c';
			'..';
			'.wh 0 ph';
			'.de np';
			'.  sp 0.2c';
			'..';
			'.blm np'


		};
	}
	rs.macsNeeded = {
		order = {};
		map = {};
		count = 0;
................................................................................
			elseif spanRenderers[v.kind] then
				spanRenderers[v.kind](rc, v, b, sec)
			end
		end
	end

	local blockRenderers = {}




	function	blockRenderers.label(rc, b, sec)
		if ct.sec.is(b.captions) then
			local sizes = {36,24,12,8,4,2}
			local margins = {0,5,2,1,0.5}
			local dedents = {2.5,1.3,0.8,0.4}

			rc.prop.dsz = sizes[b.captions.depth] or 10
			rc.prop.underline = b.captions.depth < 4
			rc.prop.bold = b.captions.depth > 3
			rc.prop.margin = {
				top = margins[b.captions.depth] or 0;
				bottom = 0.1;
			}

			rc.prop.indent = -(dedents[b.captions.depth] or 0)
			rc.prop.underline = true
			rc.prop.chtitle = collectText(rc, b.spans, b.spec):compile()
			if b.captions.depth == 1 then
				rc.prop.breakBefore = true
			end
			rs.renderSpans(rc, b.spans, b, sec)
		else
			ss.bug 'tried to render label for an unknown object type':throw()
................................................................................
	local skippedFirstPagebreak = doc.secorder[1]:visible()
	local deferrer = ss.declare {
		ident = 'groff-deferrer';
		mk = function(buf) return {ops={}, tgt=buf} end;
		fns = {
			esc = function(me, str) table.insert(me.ops, {0, str}) end;
			req = function(me, str) table.insert(me.ops, {1, str}) end;

			flush = function(me)
				for i=#me.ops,1,-1 do
					local d = me.ops[i]
					if d[1] == 0 then
						me.tgt:esc(d[2])
					elseif d[1] == 1 then
						me.tgt:req(d[2])


					end
				end
				me.ops = {}
			end;
		};
	}
	function rs.emitSpan(gtxt, s)
................................................................................
		else
			gtxt:txt(s.txt)
		end
		defer:flush()
		if s.div then
			for div, body in pairs(s.div) do
				if div == 'fn' then
					gtxt:req 'ev footnote-env'
				end
				gtxt:req('boxa '..div)
				gtxt:txt(body)
				gtxt:raw '\n'
				gtxt:req 'boxa'
				if div == 'fn' then
					gtxt:req 'ev'
					gtxt:req 'nr footnote-pos (\\n[footnote-pos]u+\\n[dn]u)'
					gtxt:req 'ch footnote-print -(\\n[footnote-pos]u+1c)'
				end
			end
		end
	end
	function rs.emitBlock(gtxt, b)
		local didfinalbreak = false
		local defer = deferrer(gtxt)
................................................................................
		end
		if ln.breakBefore then
			if skippedFirstPagebreak then
				gtxt:req 'bp'
			else
				skippedFirstPagebreak = true
			end


		end
		if ln.indent then
			if ln.indent < 0 then
				gtxt:req('in '..tostring(ln.indent)..'m')
				defer:req 'in'
				gtxt:req('ll +'..tostring(-ln.indent)..'m')
				defer:req 'll'
................................................................................
		if ln.margin then
			if ln.margin.top then
				gtxt:req(string.format('sp %sm', ln.margin.top))
			end
		end

		if ln.underline then



			defer:esc("D'l \\n[.ll]u-\\n[.in]u 0'")


			defer:esc"v'-0.5'"
			defer:req'br'
		end

		if ln.dsz and ln.dsz > 0 then
			gtxt:req('ps +' .. tostring(ln.dsz) .. 'p')
			defer:req('ps -' .. tostring(ln.dsz) .. 'p')
		elseif ln.sz or ln.dsz then
			if ln.sz and ln.sz <= 0 then







>
>
>
>







 







>
>
>
>



>
>
>
>
>







 







>



<

>




>

>



|

|


>











|







 







<

|

|
>







 







>
>
>
>



|

>

|


|


>

<







 







>







>
>







 







|

|


|

|
|
|







 







>
>







 







>
>
>
|
>
>

<







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
..
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
...
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
...
229
230
231
232
233
234
235

236
237
238
239
240
241
242
243
244
245
246
247
...
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
...
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
...
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
...
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
...
532
533
534
535
536
537
538
539
540
541
542
543
544
545

546
547
548
549
550
551
552
			if me.linbuf == nil then
				me.linbuf = ss.strac()
			end
			me.linbuf(text)
		end;
		txt = function(me, str, ...)
			if str == nil then return end
         if me.linbuf == nil then
	         -- prevent unwanted linebreaks
	         str = str:gsub('^%s+','')
         end
			me:raw(gsan(str))
			-- WARN this will cause problems if str is ever allowed to
			-- include a line break. we can sanitize by converting
			-- every line break into a new entry in the table, but i
			-- don't think it should be possible for a \n to reach us
			-- at this point, so i'm omitting the safety check as it
			-- would involve an excessive hit to performance
................................................................................
			me:flush()
			me:txt(...)
		end;
		req = function(me, r)
			me:flush()
			table.insert(me.lines, '.'..r)
		end;
		sreq = function(me, r)
			me:flush()
			table.insert(me.lines, "'"..r)
		end;
		esc = function(me, e)
			me:raw('\\' .. e)
		end;
      draw = function(me, args)
         for _,v in ipairs(args) do
				me:esc("D'" .. v .. "'")
         end
      end;
		flush = function(me)
			if me.linbuf ~= nil then
				local line = me.linbuf:compile()
				local first = line:sub(1,1)
				-- make sure our lines aren't accidentally interpreted
				-- as groff requests. groff is kinda hostile to script
				-- generation, huh?
................................................................................
		};
		color = {'.color'};
		insert = {};
		footnote = {
			'.de footnote-blank';
			'.  sp 0.25m';
			'..';

			'.ev footnote-env';
			'.  ps 8p';
			'.  in 0.5c';

			'.ev';

			'.de footnote-print';
-- 			'.  sp |\\\\n[.p]u-\\\\n[footnote-pos]u';
			'.  sp 0.5c';
			'.  ev footnote-env';
			'.    blm footnote-blank';
			'.    fn';
			'.    blm np';
			'.  ev';
			'.  rm fn';
			'.  nr footnote-pos 0';
			-- move the trap past the top of the page so it's not
			-- invoked again until more footnotes have been assembled
			'.  ch footnote-print |-1000';
			'.  bp';
			'..';

			'.wh |\\n[.p]u footnote-print';
		};
		root = {
		-- these are macros included in all documents
		-- page offset is hideously broken and unusable; we
		-- zero it out so we can use .in to control indents
		-- instead. note that the upshot of this is we need
		-- to manually specify the indent in every other
		-- environment from now on, .evc doesn't seem to cut it
		-- set up the page title environment & trap
			"'in 2c";
			"'ll 19.5c";
			"'po 0";
			"'ps 13p";
			"'vs 15p";
			".ev pgti";
			".  evc 0";
			".  fam H";
			".  ps 10pt";
................................................................................
			'.  lt 19c';
			".  tl '\\\\*[doctitle]'\\fB\\\\*[title]\\f[]'%'";
			'.  po 0';
			".  br";
			'.  ev';
			'.  sp 1.2c';
			'..';

			'.de np';
			'.  sp 0.6m';
			'..';
			'.blm np';
			'.wh 0 ph';

		};
	}
	rs.macsNeeded = {
		order = {};
		map = {};
		count = 0;
................................................................................
			elseif spanRenderers[v.kind] then
				spanRenderers[v.kind](rc, v, b, sec)
			end
		end
	end

	local blockRenderers = {}
	blockRenderers['horiz-rule'] = function(rc, b, sec)
		rc.prop.margin = { top = 0.3 }
		rc.prop.underline = 0.1
	end
	function	blockRenderers.label(rc, b, sec)
		if ct.sec.is(b.captions) then
			local sizes = {36,24,12,8,4,2}
			local margins = {0,3}
			local dedents = {2.5,1.3,0.8,0.4}
			local uls = {3,1.5,0.5,0.25}
			rc.prop.dsz = sizes[b.captions.depth] or 10
			rc.prop.underline = uls[b.captions.depth]
			rc.prop.bold = b.captions.depth > 3
			rc.prop.margin = {
				top = margins[b.captions.depth] or 1;
				bottom = 0.1;
			}
			rc.prop.vassure = rc.prop.dsz+70;
			rc.prop.indent = -(dedents[b.captions.depth] or 0)

			rc.prop.chtitle = collectText(rc, b.spans, b.spec):compile()
			if b.captions.depth == 1 then
				rc.prop.breakBefore = true
			end
			rs.renderSpans(rc, b.spans, b, sec)
		else
			ss.bug 'tried to render label for an unknown object type':throw()
................................................................................
	local skippedFirstPagebreak = doc.secorder[1]:visible()
	local deferrer = ss.declare {
		ident = 'groff-deferrer';
		mk = function(buf) return {ops={}, tgt=buf} end;
		fns = {
			esc = function(me, str) table.insert(me.ops, {0, str}) end;
			req = function(me, str) table.insert(me.ops, {1, str}) end;
			draw = function(me, lst) table.insert(me.ops,{2, lst}) end;
			flush = function(me)
				for i=#me.ops,1,-1 do
					local d = me.ops[i]
					if d[1] == 0 then
						me.tgt:esc(d[2])
					elseif d[1] == 1 then
						me.tgt:req(d[2])
					elseif d[1] == 2 then
						me.tgt:draw(d[2])
					end
				end
				me.ops = {}
			end;
		};
	}
	function rs.emitSpan(gtxt, s)
................................................................................
		else
			gtxt:txt(s.txt)
		end
		defer:flush()
		if s.div then
			for div, body in pairs(s.div) do
				if div == 'fn' then
					gtxt:sreq 'ev footnote-env'
				end
				gtxt:sreq('boxa '..div)
				gtxt:txt(body)
				gtxt:raw '\n'
				gtxt:sreq 'boxa'
				if div == 'fn' then
					gtxt:sreq 'ev'
					gtxt:sreq 'nr footnote-pos (\\n[footnote-pos]u+\\n[dn]u)'
					gtxt:sreq 'ch footnote-print -(\\n[footnote-pos]u+1.5c)'
				end
			end
		end
	end
	function rs.emitBlock(gtxt, b)
		local didfinalbreak = false
		local defer = deferrer(gtxt)
................................................................................
		end
		if ln.breakBefore then
			if skippedFirstPagebreak then
				gtxt:req 'bp'
			else
				skippedFirstPagebreak = true
			end
		elseif ln.vassure then
			gtxt:req(string.format('if (\\n[.t]u < %sp) .bp',ln.vassure))
		end
		if ln.indent then
			if ln.indent < 0 then
				gtxt:req('in '..tostring(ln.indent)..'m')
				defer:req 'in'
				gtxt:req('ll +'..tostring(-ln.indent)..'m')
				defer:req 'll'
................................................................................
		if ln.margin then
			if ln.margin.top then
				gtxt:req(string.format('sp %sm', ln.margin.top))
			end
		end

		if ln.underline then
			defer:req'br'
			defer:draw {
				"t "..tostring(ln.underline).."p";
				"l \\n[.ll]u-\\n[.in]u 0";
			}
			defer:esc("h'-" .. tostring(ln.underline) .. "p'")
			defer:esc"v'-0.5'"

		end

		if ln.dsz and ln.dsz > 0 then
			gtxt:req('ps +' .. tostring(ln.dsz) .. 'p')
			defer:req('ps -' .. tostring(ln.dsz) .. 'p')
		elseif ln.sz or ln.dsz then
			if ln.sz and ln.sz <= 0 then

Modified render/html.lua from [778a76ed09] to [39c7338664].

671
672
673
674
675
676
677



678
679
680
681
682
683
684
	local function getBlockRenderers(procs, sr)
		local tag, elt, catenate = procs.tag, procs.elt, procs.catenate
		local null = function() return catenate{} end

		local block_renderers = {
			anchor = function(b,s)
				return tag('a',{id = getSafeID(b)},null())



			end;
			paragraph = function(b,s)
				addStyle 'paragraph'
				return tag('p', nil, sr.htmlSpan(b.spans, b, s), b)
			end;
			directive = function(b,s)
				-- deal with renderer directives







>
>
>







671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
	local function getBlockRenderers(procs, sr)
		local tag, elt, catenate = procs.tag, procs.elt, procs.catenate
		local null = function() return catenate{} end

		local block_renderers = {
			anchor = function(b,s)
				return tag('a',{id = getSafeID(b)},null())
			end;
			['horiz-rule'] = function(b,s)
				return elt'hr'
			end;
			paragraph = function(b,s)
				addStyle 'paragraph'
				return tag('p', nil, sr.htmlSpan(b.spans, b, s), b)
			end;
			directive = function(b,s)
				-- deal with renderer directives

Modified sirsem.lua from [550cdedbd6] to [eb2c53bff4].

4
5
6
7
8
9
10

11
12
13
14
15
16
17
18
...
600
601
602
603
604
605
606


607
608
609
610
611
612
613
...
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
...
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
....
1107
1108
1109
1110
1111
1112
1113

















































































































--  ? utility library with functionality common to
--    cortav.lua and its extensions
--    from Ranuir "software utility"
--  > local ss = require 'sirsem.lua'

local ss
do -- pull ourselves up by our own bootstraps

	local package = _G.package -- prevent namespace from being broken by env shenanigans
	local function namespace(name, tbl)
		local pkg = tbl or {}
		if package then
			package.loaded[name] = pkg
		end
		return pkg
	end
................................................................................

	if c.op then
		cls.__add = c.op.sum
		cls.__sub = c.op.sub
		cls.__div = c.op.div
		cls.__mul = c.op.mul
		cls.__concat = c.op.cat


	end

	cls.mk = function(...)
		local val = setmetatable(c.mk and c.mk(...) or {}, cls)
		if c.init then
			for k,v in pairs(c.init) do
				val[k] = v
................................................................................

ss.version = ss.declare {
	name = 'version';
	mk = function(tbl) return tbl end;
	fns = {
		pre = function(self,other) end;
		post = function(self,other) end;
		string = function(self) return tostring(self) end;		
	};
	cast = {
		string = function(vers)
			if not(next(vers)) then return '0.0' end
			local str = ''
			for _,v in pairs(vers) do
				if type(v) == 'string' then
................................................................................
function ss.tuple.cdr(x, ...) return ... end

ss.stack = ss.declare {
	ident = 'stack';
	mk = function() return {
		top = 0;
		store = {};
   } end;
	index = function(me, i)
		if i <= 0 then
			return me.store[me.top + i]
		else
			return me.store[i]
		end
	end;
	fns = {
		push = function(me, val, ...)
         if val~=nil then
	         me.top = me.top + 1
	         me.store[me.top] = val
	         me:push(...)
         end
         return val, ...
      end;
      pop = function(me,n) n = n or 1
         local r = {}
			if n < me.top then
				for i = 0,n-1 do
					r[i+1] = me.store[me.top - i]
					me.store[me.top - i] = nil
				end
				me.top = me.top - n
         else
	         r = me.store
				me.store = {}
         end
			return table.unpack(r)
      end;
      set = function(me,val)
         if me.top == 0 then
	         me.top = me.top + 1 --autopush
         end
         me.store[me.top] = val
      end;
      all = function(me) return table.unpack(me.store) end;
      each = function(forward)
         if forward then
	         local idx = 0
	         return function()
		         idx = idx + 1
		         if idx > top
						then return nil
						else return me.store[idx], idx
					end
	         end
         else
	         local idx = top + 1
	         return function()
		         idx = idx - 1
		         if idx == 0
						then return nil
						else return me.store[idx], idx
					end
	         end
         end
      end;
	};
}

ss.automat = ss.declare {
	ident = 'automat';
	mk = function() return {
		state = ss.stack();
................................................................................
			-- versions at least can launch programs in a sane and secure
			-- way.
		else
			return s
		end
	end, ...))
end
























































































































>
|







 







>
>







 







|







 







|









|
|
|
|
|
|
|
|
|






|
|

|

|
|
|
|
|
|
|
|
|
|
|
|
|
|



|
|
|
|
|
|



|
|
|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
...
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
...
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
....
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
--  ? utility library with functionality common to
--    cortav.lua and its extensions
--    from Ranuir "software utility"
--  > local ss = require 'sirsem.lua'

local ss
do -- pull ourselves up by our own bootstraps
	local package = _G.package
	-- prevent namespace from being broken by env shenanigans
	local function namespace(name, tbl)
		local pkg = tbl or {}
		if package then
			package.loaded[name] = pkg
		end
		return pkg
	end
................................................................................

	if c.op then
		cls.__add = c.op.sum
		cls.__sub = c.op.sub
		cls.__div = c.op.div
		cls.__mul = c.op.mul
		cls.__concat = c.op.cat
		cls.__eq = c.op.eq
		cls.__lt = c.op.lt
	end

	cls.mk = function(...)
		local val = setmetatable(c.mk and c.mk(...) or {}, cls)
		if c.init then
			for k,v in pairs(c.init) do
				val[k] = v
................................................................................

ss.version = ss.declare {
	name = 'version';
	mk = function(tbl) return tbl end;
	fns = {
		pre = function(self,other) end;
		post = function(self,other) end;
		string = function(self) return tostring(self) end;
	};
	cast = {
		string = function(vers)
			if not(next(vers)) then return '0.0' end
			local str = ''
			for _,v in pairs(vers) do
				if type(v) == 'string' then
................................................................................
function ss.tuple.cdr(x, ...) return ... end

ss.stack = ss.declare {
	ident = 'stack';
	mk = function() return {
		top = 0;
		store = {};
	} end;
	index = function(me, i)
		if i <= 0 then
			return me.store[me.top + i]
		else
			return me.store[i]
		end
	end;
	fns = {
		push = function(me, val, ...)
			if val~=nil then
				me.top = me.top + 1
				me.store[me.top] = val
				me:push(...)
			end
			return val, ...
		end;
		pop = function(me,n) n = n or 1
			local r = {}
			if n < me.top then
				for i = 0,n-1 do
					r[i+1] = me.store[me.top - i]
					me.store[me.top - i] = nil
				end
				me.top = me.top - n
			else
				r = me.store
				me.store = {}
			end
			return table.unpack(r)
		end;
		set = function(me,val)
			if me.top == 0 then
				me.top = me.top + 1 --autopush
			end
			me.store[me.top] = val
		end;
		all = function(me) return table.unpack(me.store) end;
		each = function(me,forward)
			if forward then
				local idx = 0
				return function()
					idx = idx + 1
					if idx > me.top
						then return nil
						else return me.store[idx], idx
					end
				end
			else
				local idx = me.top + 1
				return function()
					idx = idx - 1
					if idx == 0
						then return nil
						else return me.store[idx], idx
					end
				end
			end
		end;
	};
}

ss.automat = ss.declare {
	ident = 'automat';
	mk = function() return {
		state = ss.stack();
................................................................................
			-- versions at least can launch programs in a sane and secure
			-- way.
		else
			return s
		end
	end, ...))
end

ss.mime = ss.declare {
	ident = 'mime-type';
	mk = function() return {
		class = nil;
		kind = nil;
		opts = {};
	} end;
	construct = function(me,str)
		if not str then return end
		local p,o = str:match '^([^;]+);?%s*(.-)$'
		if not p then ss.mime.exn('invalid type syntax %s',str):throw() end
		local c,k = p:match '^([^/]+)/?(.-)$'
		me.class = (c ~= '') and c or nil
		me.kind = (k ~= '') and k or nil
		if o and o ~= '' then
			for key, e, val in o:gmatch '%s*([^=;]+)(=?)([^;]*)' do
				if me.opts[key] then
					ss.mime.exn('mime type cannot contain multiple %s options',key):throw()
				elseif me.opts.hex    and key == 'base64'
				    or me.opts.base64 and key == 'hex' then
					ss.mime.exn('mime type cannot more than one of (base64, hex)',key):throw()
				end
				if e == '' then val = true end
				me.opts[key] = val
			end
		end
	end;
	op = {
		eq = function(self, other)
		-- exact match operator
			if not ss.mime.is(other) then return ss.mime.exn("tried to compare MIME type %s against %s (%s)", tostring(self), type(other), tostring(other)):throw() end
			if (self.kind  == other.kind  or (self.kind == '*' or other.kind == '*')) and
			   (self.class == other.class or (self.class == '*' or other.class == '*')) and
			  (#self.opts  ==#other.opts) then
				for k,v in pairs(self.opts) do
					if not(other.opts[k] == '*' or (v == '*' and other.opts[k])) then
						if other.opts[k] ~= v then return false end
					end
				end
				for k,v in pairs(other.opts) do
					if not(self.opts[k] == '*' or (v == '*' and self.opts[k])) then
						if self.opts[k] ~= v then return false end
					end
				end
				return true
			else
				return false
			end
		end;
		lt = function(self,other)
		-- lt is the "subset?" operator -- it returns true if self
		-- matches at least as many fields as other has. use this
		-- when you have a base type and want to check whether
		-- another type is compatible with that type. say all you
		-- care about is whether a file is "text/plain", and it
		-- can be encoded however as long as that much fits.
		-- you would then ask ss.mime'text/plain' < file.mime
			return other:superset_of(self)
		end;
	};
	cast = {
		string = function(me)
			local r
			if me.kind and me.class then
				r = string.format('%s/%s',me.class,me.kind)
			elseif me.class then
				r = me.class
			end
			for k,v in pairs(me.opts) do
				if v and v ~= true then
					r = r .. string.format(';%s=%s',k,v)
				elseif v == true then
					r = r .. string.format(';%s',k)
				end
			end
			return r
		end;
	};
	fns = {
		superset_of = function(self, other)
		-- a mime type is greater than another if all the fields
		-- other has have a matching field in self. think of this
		-- as the "superset?" operator -- all fields and options
		-- on other must either match self or be unset
			if not ss.mime.is(other) then return ss.mime.exn("tried to compare MIME type %s against %s (%s)", tostring(self), type(other), tostring(other)):throw() end
			if (other.class and self.class ~= other.class and other.class ~='*')
			or (other.kind  and self.kind  ~= other.kind  and other.kind ~= '*')
				then return false end
			for k,v in pairs(other.opts) do
				if self.opts[k] and self.opts[k] ~= v and v ~='*' then
					return false
				end
			end
			return true
		end;
		is = function(me, pc)
			local mimeclasses = {
				['application/svg+xml'] = 'image';
				['application/x-tar'] = 'archive';
			}
			local c = me.class
			for k,v in pairs(mimeclasses) do
				if me > ss.mime(k) then
					c = v break
				end
			end
			print(c)
			return c == pc
		end;
	};
}
ss.mime.exn = ss.exnkind 'MIME error'

Modified tool/makeshim.lua from [f2235ca34c] to [cea771ab78].

7
8
9
10
11
12
13

14
15
16
17
18
19
20
..
31
32
33
34
35
36
37
38








39
40
41
42
43
44
45
..
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
--    giving cortav extra privileges

local includes = [[
#include <lua.h>
#include <lauxlib.h>
#include <stdio.h>
#include <stddef.h>

extern int luaL_openlibs(lua_State* l);
]]


local main = [[
int main(int argc, char** argv) {
	lua_State* l = luaL_newstate();
................................................................................
	// load and run our payload
	int e = luaL_loadbufferx(l, ct_bytecode, sizeof(ct_bytecode), "cortav", "b");
	if (e != LUA_OK) {
		printf("some kind of error idk fam\n");
		return -1;
	}

	lua_call(l, 0, 0);









	// normal termination is by the os.exit() call
	return -1;
}
]]

local function setfile(i, dflt, mode)
................................................................................
	return dflt
end

local src = setfile(1, io.stdin, "rb")
local dest = setfile(2, io.stdout, "w")

local cstr = {}
local strtpl = 'static char ct_bytecode [%u] = {%s};'
local lines = {includes}


local bytes = {}

local bn = 1
local len = 0
while true do
	local byte = src:read(1)
	if not byte then break end
	local str = tostring(byte:byte(1))..','
	-- make sure our source file is parseable by
	-- a compliant C compiler
	len = len + string.len(str)
	if len >= 4096 then
		len = 0
		bytes[bn]='\n'
		bn = bn + 1
	end

	bytes[bn] = str
	bn = bn + 1
end



table.insert(lines, strtpl:format(#bytes, table.concat(bytes)))
table.insert(lines, main)



dest:write(table.concat(lines, '\n'))







>







 







|
>
>
>
>
>
>
>
>







 







|
|
>











|
|




>




>
>
|
<
>
|
>

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
..
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
--    giving cortav extra privileges

local includes = [[
#include <lua.h>
#include <lauxlib.h>
#include <stdio.h>
#include <stddef.h>
#include <unistd.h>
extern int luaL_openlibs(lua_State* l);
]]


local main = [[
int main(int argc, char** argv) {
	lua_State* l = luaL_newstate();
................................................................................
	// load and run our payload
	int e = luaL_loadbufferx(l, ct_bytecode, sizeof(ct_bytecode), "cortav", "b");
	if (e != LUA_OK) {
		printf("some kind of error idk fam\n");
		return -1;
	}

	if (lua_pcall(l, 0, 0, 0) != LUA_OK) {
		size_t len;
		const char* msg = luaL_tolstring(l, -1, &len);
		if (isatty(2)) {
			fprintf(stderr, "\33[31;1m(fatal)\33[m %.*s\n", (int)len, msg);
		} else {
			fprintf(stderr, "(fatal) %.*s\n", (int)len, msg);
		}
	};

	// normal termination is by the os.exit() call
	return -1;
}
]]

local function setfile(i, dflt, mode)
................................................................................
	return dflt
end

local src = setfile(1, io.stdin, "rb")
local dest = setfile(2, io.stdout, "w")

local cstr = {}
local strtpl = [[static char ct_bytecode [%u] = {
%s
};]]

local bytes = {}

local bn = 1
local len = 0
while true do
	local byte = src:read(1)
	if not byte then break end
	local str = tostring(byte:byte(1))..','
	-- make sure our source file is parseable by
	-- a compliant C compiler
	local strl = string.len(str)
	if len + strl >= 4095 then
		len = 0
		bytes[bn]='\n'
		bn = bn + 1
	end
	len = len + strl
	bytes[bn] = str
	bn = bn + 1
end

local lines = {
	includes;
	strtpl:format(#bytes, table.concat(bytes));

	main;
}

dest:write(table.concat(lines, '\n'))