cortav  Check-in [9215a9c850]

Overview
Comment:add beginnings of groff renderer, document more planned syntaxes
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 9215a9c850343f45b4116f6270b8487bdf63be0fea80a875f58c7e2b994931dd
User & Date: lexi on 2021-12-27 13:20:36
Other Links: manifest | tags
Context
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
2021-12-27
13:20
add beginnings of groff renderer, document more planned syntaxes check-in: 9215a9c850 user: lexi tags: trunk
06:06
add hue spread check-in: 560e69cc54 user: lexi tags: trunk
Changes

Modified cli.lua from [9f14981767] to [ad6ab18d31].

216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
		input.stream = file
		input.src.file = args[1]
	end

	return main(input, outp, log, mode, suggestions, vars, extrule)
end

local ok, e = pcall(entry_cli)
-- local ok, e = true, entry_cli()
if not ok then
	local str = 'translation failure'
	if ss.exn.is(e) then
		str = e.kind.desc
	end
	local color = false
	if log:seek() == nil then







|
|







216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
		input.stream = file
		input.src.file = args[1]
	end

	return main(input, outp, log, mode, suggestions, vars, extrule)
end

-- local ok, e = pcall(entry_cli)
local ok, e = true, entry_cli()
if not ok then
	local str = 'translation failure'
	if ss.exn.is(e) then
		str = e.kind.desc
	end
	local color = false
	if log:seek() == nil then

Modified cortav.ct from [0c4afc6088] to [4ed3bc7476].

115
116
117
118
119
120
121

122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
...
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
...
256
257
258
259
260
261
262

263
264
265
266
267
268
269
...
343
344
345
346
347
348
349





































350
351
352
353
354
355
356
* [*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 \[\\[`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
* 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.
................................................................................
* {def cortav.page} the number of the page currently being rendered
* {def cortav.id} the identifier of the renderer
* {def cortav.hash} the SHA3 hash of the source file being rendered
	def: [*[#1]]:

on systems with environment variables, these may be accessed as context variables by prefixing their name with [`env.].

different renderers may provide context in different ways, such as from command line options or a context file. any predefined variables should carry an appropriate prefix to prevent conflation. 

##fonts fonts
for output backends that support font specification, cortav provides a sophisticated font management system by means of the [!font stack].

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.

................................................................................
#^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

@sans
	src: link font name:Alegreya Sans
		link font name:Open Sans
		link font name:sans-serif
~~~

here we have defined two font families, [`fonts.serif] and [`fonts.sans]. each contains a list of references to fonts which will be tried in order. for example, this could be translated into the following CSS:
................................................................................

&$cursive-quote Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident

%% without affecting the overall font context. in fact, since 'cursive-quote' creates
%% its context using 'dup', it would import all font specifications besides 'body'
%% from the environment it is invoked in
~~~






































##dir directives
	d: [`%[*[##1]]]
* {d author} encodes document authorship. multiple author directives can be issued to add additional coauthors
* {d cols} specifies the number of columns the next object should be rendered with
* {d include} transcludes another file
* {d import} reads in the contents of another file as an embeddable section







>










|







 







|







 







>







 







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







115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
...
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
...
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
* [*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
* custom style {span .|id|[$styled-text]}: applies a specially defined font style. for example, if you have defined [`caution] to mean "demibold italic underline", cortav will try to apply the proper weight and styling within the constraints of the current font to the span [$styled-text]. see the [>fonts-sty fonts section] for more information about this mechanism.
* 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
* 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.
................................................................................
* {def cortav.page} the number of the page currently being rendered
* {def cortav.id} the identifier of the renderer
* {def cortav.hash} the SHA3 hash of the source file being rendered
	def: [*[#1]]:

on systems with environment variables, these may be accessed as context variables by prefixing their name with [`env.].

different renderers may provide context in different ways, such as from command line options or a context file. any predefined variables should carry an appropriate prefix to prevent conflation.

##fonts fonts
for output backends that support font specification, cortav provides a sophisticated font management system by means of the [!font stack].

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.

................................................................................
#^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
	src: link font name:Alegreya Sans
		link font name:Open Sans
		link font name:sans-serif
~~~

here we have defined two font families, [`fonts.serif] and [`fonts.sans]. each contains a list of references to fonts which will be tried in order. for example, this could be translated into the following CSS:
................................................................................

&$cursive-quote Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident

%% without affecting the overall font context. in fact, since 'cursive-quote' creates
%% its context using 'dup', it would import all font specifications besides 'body'
%% from the environment it is invoked in
~~~

you may have noticed the rather odd bit at the end of our font definition, with the [`dit] URI. the reasons for this are tragic. groff, while delightful, has a thoroughly antiquated understanding of fonts, and doesn't support normal font formats like truetype. groff ships with a limited number of fonts in its own format, identified by obscurantist letter code ([`HBI] is "Helvetica Bold Italic", for instance) and lacking normal metadata. for this reason, you'll have to tell cortav how you want your fonts translated.

it is possible to use modern fonts with groff, but to do that you'll have to convert and install them, which is outside the scope of this document. however, even if you do this, you should specify a fallback font (if possible) so that people rendering your document on other machines still get somewhat sensible output.

the syntax of a [`dit] specification is [`dit:[$regular]], where [$regular] specifies the name of the regular font. this can be followed by any number of variant specifications [`/[$variant]=[$name]], where [$variant] is one of the tags described in the [>fonts-sty custom] style section, and [$name] is the name of a DIT font. so the URI in the example names a font [`T] with bold [`TB], italic [`TI], and bold-italic [`TBI].

the [`groff] backend does do a little magic to make this mess more bearable, however. some of groff's built-in fonts can be accessed by a [`name] URI instead of having to construct them by hand with a [`dit] URI -- the backend hardcodes metadata for these fonts so that documents can render somewhat intellgibly in groff even if the original author did not make special provisions for this. the groff fonts accessible by [`name] are:
* Times New Roman
* Helvetica
* Courier
* Bookman
additionally, as a shortcut, if the regular, bold, italic, and bold-italic variants of a DIT font have the predictable pattern of [`[$X]], [`[$X]B], [`[$X]I], [`[$X]BI] (which many do), you can simply write the URI [`dit:[$X]] and cortav will infer the rest. so the example above could be rewritten as [`dit:T] to exactly the same effect.

###fonts-sty custom styles
sometimes you want to be able to issue more specific formatting instructions than "italic" or "bold". cortav provides a simple [!custom style] mechanism to allow this. a custom style is simply a reference that binds a name to a sequence of space-separated formatting directives. these directives include:
* [`regular]: applies the regulat form of the font, overriding any previous set styles
* [`medium]: applies a weight of the font between [`regular] and [`bold], defaulting to [`regular] if one is not available
* [`demibold]: applies a weight of the font between [`regular] and [`bold], defaulting to [`bold] if one is not available
* [`bold]: applies the usual "bold" weight of the font
* [`dense]: applies the heaviest available weight of th the font. usually the same as [`bold]
* [`light]: applies the usual "light" weight of the font. most fonts do not have a light weight, so this will be the same as [`regular].
* [`thin]: applies the slimmest available weight of the font. usually the same as [`light].
* [`underline]: underlines the text
* [`strike]: strikes the text out
* [`italic]: applies a slanted variant of the font
* [`oblique]: applies the most slanted variant of the font available. usually the same as [`italic]
* [`font=[$id]]: switches to font [$id] for the duration of the span. [$id] must be the ID of a resource defining a font.
* [`[$ext].[$prop]=[$word]]: attaches extra information for use by formatting extensions. [$ext] must be the ID of the extension.

once a custom style is defined, you can make use of it using the [` \[.[$id] [$styled-text]\]] span notation, where [$id] is the identifier of the reference containing your style. for instance, to define and use a style named [`important] that [^pls-no specifies a dense, underlined variant of font [`impact]] and applies the CSS class [`blink] when rendered with the [`html] backend:
	pls-no: please do not do this
~~~cortav
this paragraph contains some [.important truly important] information.
	important: dense underline font=impact html.class=blink
~~~
you should always give your styles semantic names where practicable, instead of simply describing their graphical characteristics. this is good practice in general, but especially because your document will be renderable to different formats with different characteristics, and what makes text look important on a manpage in the terminal may be quite different from how it looks in a webpage or PDF.

##dir directives
	d: [`%[*[##1]]]
* {d author} encodes document authorship. multiple author directives can be issued to add additional coauthors
* {d cols} specifies the number of columns the next object should be rendered with
* {d include} transcludes another file
* {d import} reads in the contents of another file as an embeddable section

Modified desk/cortav.xml from [b82e1b14f3] to [d0eba8f9ef].

119
120
121
122
123
124
125

126
127
128
129
130
131
132
				<DetectChar   attribute='Span Cue' char='~' context='#pop!span-del' />

				<AnyChar      attribute='Span Cue' String='`$+🔒' context='#pop!span' />
				<StringDetect attribute='Span Cue' String='→' context='#pop!ref' />
				<StringDetect attribute='Span Cue' String='🔗' context='#pop!ref' />
				<DetectChar   attribute='Span Cue' char='>' context='#pop!ref' />
				<DetectChar   attribute='Span Cue' char='^' context='#pop!ref' />

				<DetectChar   attribute='Span Cue' char='&amp;' context='#pop!ref' />
				<DetectChar   attribute='Span Cue' char='#' context='#pop!var-ref' />
				<DetectChar   attribute='Span Cue' char='\' context='#pop!flat-span' />
				<Detect2Chars attribute='Comment' char='%' char1='%' context='#pop!inline-comment' />
				<Detect2Chars attribute='Critical Directive Cue' char='%' char1='!' context='#pop!inline-directive' />
				<DetectChar   attribute='Directive Cue' char='%' context='#pop!inline-directive' />
			</context>







>







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
				<DetectChar   attribute='Span Cue' char='~' context='#pop!span-del' />

				<AnyChar      attribute='Span Cue' String='`$+🔒' context='#pop!span' />
				<StringDetect attribute='Span Cue' String='→' context='#pop!ref' />
				<StringDetect attribute='Span Cue' String='🔗' context='#pop!ref' />
				<DetectChar   attribute='Span Cue' char='>' context='#pop!ref' />
				<DetectChar   attribute='Span Cue' char='^' context='#pop!ref' />
				<DetectChar   attribute='Span Cue' char='"' context='#pop!ref' />
				<DetectChar   attribute='Span Cue' char='&amp;' context='#pop!ref' />
				<DetectChar   attribute='Span Cue' char='#' context='#pop!var-ref' />
				<DetectChar   attribute='Span Cue' char='\' context='#pop!flat-span' />
				<Detect2Chars attribute='Comment' char='%' char1='%' context='#pop!inline-comment' />
				<Detect2Chars attribute='Critical Directive Cue' char='%' char1='!' context='#pop!inline-directive' />
				<DetectChar   attribute='Directive Cue' char='%' context='#pop!inline-directive' />
			</context>

Modified ext/toc.lua from [35da212f52] to [e8a2cf6308].

82
83
84
85
86
87
88



89
90
91
92
93
94
95
			}
			ol.toc > ol > li {
				list-style: decimal;
			}
				ol.toc > li > ol > li > ol > li {
					list-style: enclosed;
				}



	}
]]

ct.ext.install {
	id = 'toc';
	desc = 'provides a table of contents for HTML renderer plus generic fallback';
	version = ss.version {0,1; 'devel'};







>
>
>







82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
			}
			ol.toc > ol > li {
				list-style: decimal;
			}
				ol.toc > li > ol > li > ol > li {
					list-style: enclosed;
				}
					ol.toc > li > ol > li > ol > li > ol > li {
						list-style: lower-roman;
					}
	}
]]

ct.ext.install {
	id = 'toc';
	desc = 'provides a table of contents for HTML renderer plus generic fallback';
	version = ss.version {0,1; 'devel'};

Added render/groff.lua version [a43bfa19e3].





















































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
-- [ʞ] render/groff.lua
--  ~ lexi hale <lexi@hale.su>
--  🄯 AGPLv3
--  ? renders cortav to groff source code, for creating pdfs,
--    dvis, manapages, and html files that are grievously
--    inferior compared to our own illustrious direct-html
--    renderer.
--  > cortav -m render:format groff

local ct = require 'cortav'
local ss = require 'sirsem'

local tcat = function(a,b)
	for i,v in ipairs(b) do
		table.insert(a, b)
	end
	return a
end
local lines = function(...)
	local s = ss.strac()
	for _, v in pairs{...} do s(v) end
	return s
end

function ct.render.groff(doc, opts)
	-- rs contains state specific to this render job
	-- that modules will need access to
	local rs = {};
	rs.macsets = {
		strike = {
			'.de ST';
			[[.nr ww \w'\\$1']];
			[[\Z@\v'-.25m'\l'\\n[ww]u'@\\$1']];
			'..';
		};
	}
	rs.macsNeeded = {
		order = {};
		count = 0;
	}
	function rs.macAdd(id)
		if rs.macsets[id] then
			rs.macsNeeded.count = macsNeeded.count + 1
			rs.macsNeeded.order[rs.macsNeeded.count] = id
			return true
		else return false end
	end
	local job = doc:job('render_groff',nil,rs)

	-- the way this module works is we build up a table for each block
	-- of individual strings paired with attributes that say how they
	-- should be rendered. we then iterate over the table, applying
	-- formats as need be, and inserting blanks after each block

	local spanRenderers = {}
	function spanRenderers.format(rc, s, b, sec)
		local rcc = rc:clone()
		if s.style == 'strong' then
			rcc.prop.bold = true
		elseif s.style == 'emph' then
			rcc.prop.emph = true
		elseif s.style == 'strike' then
			rcc.prop.strike = true
			rs.macAdd 'strike'
		elseif s.style == 'insert' then
		end
		rs.renderSpans(rcc, s.spans, b, sec)
	end;

	function rs.renderSpans(rc, sp, b, sec)
		for i, v in ipairs(sp) do
			if type(v) == 'string' then
				rc:add(v)
			elseif spanRenderers[v.kind] then
				spanRenderers[v.kind](rc, v, b, sec)
			end
		end
	end

	local blockRenderers = {}
	function	blockRenderers.paragraph(rc, b, sec)
		rs.renderSpans(rc, b.spans, b, sec)
	end
	function rs.renderBlock(b, sec)
		local rc = {
			clone = function(self)
				return {
					clone = self.clone;
					lines = self.lines;
					prop = ss.clone(self.prop);
					mk = self.mk;
					add = self.add;
				}
			end;
			lines = {};
			prop = {};
			mk = function(self, ln)
				local p = ss.clone(self.prop)
				p.txt = ln
				return p
			end;
			add = function(self, ln)
				table.insert(self.lines, self:mk(ln))
			end;
		}
		if blockRenderers[b.kind] then
			blockRenderers[b.kind](rc, b, sec)
		end
		return rc.lines
	end

	function rs.emitLine(ln)
		local q = ss.strac()
		if ln.dsz then
			q('\\ps +' .. tostring(ln.dsz))
		elseif ln.sz then
			q('\\ps ' .. tostring(ln.dsz))
		end

		if ln.bold and ln.emph then
			q '\\f(BI'
		elseif ln.bold then
			q '\\fB'
		elseif ln.emph then
			q '\\fI'
		end


		q(ln.txt)

		if ln.bold or ln.emph then
			q'\\f[]'
		end

		if ln.dsz then
			q('.ps -' .. tostring(ln.dsz))
		elseif ln.sz then
			q '.ps'
		end
		return q
	end

	local ir = {}
	for i, sec in ipairs(doc.secorder) do
		if sec.kind == 'ordinary' then
			local blks = {}
			for j, b in ipairs(sec.blocks) do
				local r = rs.renderBlock(b, sec)
				if r then table.insert(blks, r) end
			end
			table.insert(ir, blks)
		end
	end

	local rd = ss.strac()
	for i, s in ipairs(ir) do
		for j, b in ipairs(s) do
			for z, l in ipairs(b) do
				rd(rs.emitLine(l))
			end
			rd'\n'
		end
	end

	local macs = ss.strac()
	for _, m in pairs(rs.macsNeeded.order) do
		for _, ln in pairs(m) do macs(ln) end
	end
	return macs:compile'\n' .. rd:compile''
end

Modified render/html.lua from [35b47400ac] to [c1f1be8e43].









1
2
3
4
5
6
7
...
298
299
300
301
302
303
304

305
306
307
308
309
310
311








local ct = require 'cortav'
local ss = require 'sirsem'

-- install rendering function for html
function ct.render.html(doc, opts)
	local doctitle = opts['title']
	local f = string.format
................................................................................
		abbr = [[
			abbr[title] { cursor: help; }
		]];
		editors_markup = [[]];
		block_code_listing = [[
			figure.listing {
				font-family: monospace;

				background: @tone(0.05 20);
				color: @tone(1 20);
				padding: 0;
				margin: 0.3em 0;
				counter-reset: line-number;
				position: relative;
				border: 1px solid @tone(1 20);
>
>
>
>
>
>
>
>







 







>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
-- [ʞ] render/html.lua
--  ~ lexi hale <lexi@hale.su>
--  🄯 AGPLv3
--  ? renders cortav to beautiful, highly customizable
--    webpages full of css trickery to make them look
--    good both on a screen and when printed.
--  > cortav -m render:format html

local ct = require 'cortav'
local ss = require 'sirsem'

-- install rendering function for html
function ct.render.html(doc, opts)
	local doctitle = opts['title']
	local f = string.format
................................................................................
		abbr = [[
			abbr[title] { cursor: help; }
		]];
		editors_markup = [[]];
		block_code_listing = [[
			figure.listing {
				font-family: monospace;
				font-size: 85%;
				background: @tone(0.05 20);
				color: @tone(1 20);
				padding: 0;
				margin: 0.3em 0;
				counter-reset: line-number;
				position: relative;
				border: 1px solid @tone(1 20);

Modified sirsem.lua from [dc1f0ae1fb] to [4b787982a7].

885
886
887
888
889
890
891


















































				end
			else
				me:react(sym)
			end
		end;
	};
}

























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
				end
			else
				me:react(sym)
			end
		end;
	};
}

-- convenience buffer for holding strings under
-- construction, accumulating and compiling then in
-- as quick a way as lua permits
ss.strac = ss.declare {
	ident = 'string-accumulator';
	mk = function() return {
		strs = {};
		strc = 0;
		plain = true;
	} end;
	call = function(self, s, ...)
		if s == nil then return end
		self.strc = self.strc + 1
		self.strs[self.strc] = s
		if type(s) ~= 'string' then self.plain = false end
		self(...)
	end;
	cast = {
		string = function(self)
			return self:compile()
		end;
	};
	fns = {
		compile = function(self, delim)
			if self.plain then
				return table.concat(self.strs, delim)
			end
			local tbl = {}
			local function delve(a)
				for i=1,a.strc do
					local s = a.strs[i]
					if type(s) == 'string' then
						table.insert(tbl, s)
					elseif ss.strac.is(s) then
						delve(s)
					elseif s ~= nil then
						table.insert(tbl, tostring(s))
					end
				end
			end
			delve(self)
			return table.concat(tbl, delim)
		end;
		wrap = function(self,a,b)
			table.insert(self.strs, 1, a)
			table.insert(self.strs, b)
		end;
	};
}