cortav  Check-in [52f88f818d]

Overview
Comment:macro & doc improvements
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 52f88f818db58c95f4196293a2681596560742a9309535614819a4447c4304c1
User & Date: lexi on 2022-09-09 21:08:16
Other Links: manifest | tags
Context
2022-09-09
21:20
fix stupid table bug check-in: e8ab2a68d8 user: lexi tags: trunk
21:08
macro & doc improvements check-in: 52f88f818d user: lexi tags: trunk
19:04
enable basic ID interpolation check-in: 8b33bc074d user: lexi tags: trunk
Changes

Modified cortav.ct from [1a665df7bf] to [af24dd1316].

    97     97   ** [`~~~ language] (markdown-style shorthand syntax)
    98     98   ** [`~~~ \[language\] ~~~] (cortav syntax)
    99     99   ** [`~~~ \[language\] #id ~~~]
   100    100   ** [`~~~ title ~~~]
   101    101   ** [`~~~ title \[language\] ~~~]
   102    102   ** [`~~~ \[language\] title ~~~]
   103    103   ** [`~~~ title \[language\] #id ~~~]
   104         -*[*definition] ([^def-ex tab]): a line [^def-tab-enc beginning with a tab] is a multipurpose metadata syntax. the tab may be followed by an identifier, a colon, and a value string, in which case it opens a new definition; alternatively, a second tab character turns the line into a [*definition continuation], adding the remaining characters as a new line to the definition value on the previous line.  when a new definition is opened on a line immediately following certain kinds of objects, such as resource, it attaches key-value metadata to that object. when a definition is not preceded by such an object, an independent [*reference] is created instad.
   105         -** a [*reference] is a general mechanism for out-of-line metadata, and references are used in many different ways -- e.g. to specify link destinations, footnote contents, abbreviations, or macros. to ensure that a definition is interpreted as a reference, rather than as metadata for an object, precede it with a blank line.
          104  +*[*definition] ([^def-ex tab]): a line [^def-tab-enc beginning with a tab] is a multipurpose metadata syntax. the tab may be followed by an identifier, a colon, and a value string, in which case it opens a new definition; alternatively, a second tab character turns the line into a [*definition continuation], adding the remaining characters as a new line to the definition value on the previous line.  when a new definition is opened on a line immediately following certain kinds of objects, such as resources, embeds, or multiline macro expansions, it attaches key-value metadata to that object. when a definition is not preceded by such an object, an independent [*reference] is created instad.
          105  +** a [*reference] is a general mechanism for out-of-line metadata, and references are used in many different ways -- e.g. to specify link destinations, footnote contents, abbreviations, or macro bodies. to ensure that a definition is interpreted as a reference, rather than as metadata for an object, precede it with a blank line.
   106    106   	def-tab-enc: in encodings without tab characters, a definition is opened by a line beginning with two blanks, and continued by a line beginning with four blanks.
   107    107   	def-ex: [*open a new reference]: [`[!\\t][$key]: [$value]]
   108    108   		[*continue a reference]: [`[!\\t\\t][$value]]
   109    109   * [*quotation] ([`<]): a line of the form [`<[$name]> [$quote]] denotes an utterance by [$name].
   110    110   * [*blockquote] ([`>]): alternate blockquote syntax. can be nested by repeating the [`>] character.
   111    111   * [*subtitle/caption] ([`\--]): attaches a subtitle to the previous header, or caption to the previous object
   112         -* [*embed] ([`&]): embeds a referenced object. can be used to show images or repeat previously defined objects like lists or tables, optionally with a caption.
   113         -** [`$[$macro] [$arg1]|[$arg2]|[$argn]…] invokes a block-level macro with the supplied arguments
   114         -*** [`$mymacro arg 1|arg 2|arg 3]
          112  +* [*embed] ([`&]): embeds a referenced object. can be used to show images or repeat previously defined objects like lists or tables, optionally with a caption. an embed line can be followed immediately by a sequence of [*definitions] in the same way that resource definitions can, to override resource properties on a per-instance basis. note that only presentation-related properties like [$desc] can be meaningful overridden, as embed does not trigger a re-render of the parse tree; if you want to override e.g. context variables, use a multiline macro invocation instead.
   115    113   ** [`&[$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)
   116    114   ***[`&myimg All that remained of the unfortunate blood magic pageant contestants and audience (police photo)]
   117    115   ** [`&-[$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
   118    116   *** [`&-ex-a Prosecution Exhibit A (GRAPHIC CONTENT)]
   119    117   ** [`&+[$section] [$styled-text]] is like the above, but the disclosure element is open by default
          118  +* [`$[$macro] [$arg1]|[$arg2]|[$argn]…] invokes a block-level macro with the supplied arguments, and can be followed by a property override definition list the same way embed and resource lines can. note that while both [`$[$id]] and [`&[$id]] can be used to instantiate resources of type [`text/x.cortav], there is a critical difference: [`$[$id]] renders out the sub-document separately each time it is named, allowing for parameter expansion and for context variables to be overridden for each invocation. by contrast, [`&[$id]] can only insert copies of the same render; no parameters can be passed and context variables will be expanded to their value at the time the resource was defined.
          119  +** [`$mymacro arg 1|arg 2|arg 3]
   120    120   * [*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).
   121    121   * [*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
   122    122   * [*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. [`^-^] [`^_^] [`^----^] [`^__--^] [`^┈┈┈┈┈^])
   123    123   * [*table cells] ([`+ |]): see [>ex.tab table examples].
   124    124   * [*equations] ([`=]): block-level equations can be inserted with the [`=] sequence
   125    125   * [*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.
   126    126   * [*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.
................................................................................
   368    368   *** [`image/*] (graphical outputs only)
   369    369   *** [`video/*] (interactive outputs only)
   370    370   *** [`image/svg+xml] is handled specially for HTML files, and may or may not be compatible with other renderer backends.
   371    371   *** [`font/*] can be used with the HTML backend to reference a web font
   372    372   *** [`font/woff2] can be used with the HTML backend to reference a web font
   373    373   *** [`text/plain] (will be inserted as a preformatted text block)
   374    374   *** [`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)
   375         -*** [`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])
          375  +*** [`text/x.cortav] (will be parsed and inserted as a formatted text block; context variables can be passed to the file by setting [`.[$var]] properties on the resource, e.g. [`.recipient-name: Mr. Winthrop])
   376    376   *** [`application/x-troff] can be used to supply sections of text written in raw [`groff] syntax. these are ignored by other renderers.
   377    377   *** [`text/html] can be used to supply sections of text written in raw HTML. these are ignored by non-HTML outputs.
   378    378   *** 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.
   379    379   ** URI types: additional URI types can be added by extensions or different implementations, but every compliant implementation must support these URIs.
   380    380   *** [`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.
   381    381   *** [`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. on systems where text and binary files are handled differently, the URIs [`file+txt:] and [`file+bin:] can be used to specify an opening mode.
   382    382   *** [`asset]: identical to file [`file], except that paths are interpreted relative to the asset base (the parent directory of the source file if not otherwise defined), rather than the current working directory of the [`cortav] translator process.
................................................................................
   607    607   	zombo: https://zombo.com
   608    608   	any: anything you want
   609    609   ~~~
   610    610   
   611    611   ~~~ macros #mac [cortav] ~~~
   612    612   the ranuir word {gloss cor|writing}…
   613    613   	gloss: [*[#1]] “[#2]”
          614  +
          615  +$def sur|n|socialism
          616  +$def par|n|speech
          617  +	def: * [*[#1]] [!([#2])]
          618  +		** [#3]
          619  +
          620  +%% equivalent to
          621  +
          622  +@def {
          623  +	* [*[#1]] [!([#2])]
          624  +	** [#3]
          625  +}
          626  +$def sur|n|socialism
          627  +$def par|n|speech
          628  +
          629  +%% we could even do the same thing abusing context variables
          630  +
          631  +@def {
          632  +	* [*[#word]] [!([#pos])]
          633  +	** [#meaning]
          634  +}
          635  +
          636  +$def
          637  +	.word: sur
          638  +	.pos: n
          639  +	.meaning: socialism
          640  +$def
          641  +	.word: par
          642  +	.pos: n
          643  +	.meaning: speech
          644  +
          645  +%% context variables are useful because they inherit from the enclosing context
          646  +%% thus, we can exploit resource syntax to create templates with default values
          647  +
          648  +@agent {
          649  +	+ CODENAME :| [#1]
          650  +	+ CIVILIAN IDENTITY :| [#civil]
          651  +	+ RULES of ENGAGEMENT :| [#roe]
          652  +	+ DANGER LEVEL :| [#danger]
          653  +}
          654  +	.civil: (unknown)
          655  +	.roe: Monitor; do not engage
          656  +	.danger: (unknown)
          657  +
          658  +$agent ZUCCHINI PARABLE
          659  +	.civil: Zephram "Rolodex" Goldberg
          660  +	.danger: Category Scarlet
          661  +$agent RHADAMANTH EXQUISITE
          662  +	.roe: Eliminate with extreme prejudice; CBRN deployment authorized
          663  +	.danger: [*Unquantifiable]
   614    664   ~~~
   615    665   
   616    666   ~~~ tables #tab [cortav] ~~~
   617    667   here is a glossary table.
   618    668   
   619    669   + english :+ ranuir + zia ţai  + thaliste        +
   620    670   | honor   :| tef    | pang     | mbecheve        |

Modified cortav.lua from [7f118fbbfd] to [827b243474].

   282    282   				if sp == nil then
   283    283   					if test then return false else return '' end
   284    284   				else
   285    285   					return sp
   286    286   				end
   287    287   			elseif self.vars[var] then
   288    288   				return self.vars[var]
          289  +			elseif ctx.invocation
          290  +				and ctx.invocation.props
          291  +				and ctx.invocation.props['.' .. var] then
          292  +				return ctx.invocation.props['.' .. var]
          293  +			elseif ctx.declaration
          294  +				and ctx.declaration.props['.' .. var] then
          295  +				return ctx.declaration.props['.' .. var]
   289    296   			else
   290    297   				local sp = scanParents(var)
   291    298   				if sp then return sp end
   292    299   				if test then return false end
   293    300   				return '' -- is this desirable behavior?
   294    301   			end
   295    302   		end;
................................................................................
  1107   1114   	end};
  1108   1115   	{seq = '\t', pred = function(l)
  1109   1116   		return (l:match '\t+([^:]+):%s*(.*)$')
  1110   1117   	end; fn = blockwrap(function(l,c,j,d)
  1111   1118   		local ref, val = l:match '\t+([^:]+):%s*(.*)$'
  1112   1119   		local last = d[#d]
  1113   1120   		local rsrc
  1114         -		if last and last.kind == 'resource' then
         1121  +		if last and last.kind == 'resource'
         1122  +		         or last.kind == 'embed'
         1123  +               or last.kind == 'macro' then
         1124  +			last.props = last.props or {}
  1115   1125   			last.props[ref] = val
  1116         -			j:hook('rsrc_set_prop', c, last, ref, val, l)
         1126  +			j:hook('set_prop', c, last, ref, val, l)
  1117   1127   			rsrc = last
  1118   1128   		elseif last and last.kind == 'reference' and last.rsrc then
  1119   1129   			last.rsrc.props[ref] = val
  1120   1130   			rsrc = last.rsrc
  1121   1131   		else
  1122   1132   			c.sec.refs[ref] = val
  1123   1133   		end
................................................................................
  1286   1296   				open = brak;
  1287   1297   				close = mirror(brak);
  1288   1298   			}
  1289   1299   			rsrc.raw = '';
  1290   1300   			if src == nil then
  1291   1301   				rsrc.props.src = 'text/x.cortav'
  1292   1302   			end
  1293         -		else
  1294         -			-- load the raw body, where possible
  1295   1303   		end
  1296   1304   		if id then
  1297   1305   			if c.sec.refs[id] then
  1298   1306   				c:fail('an object with id “%s” already exists in that section',id)
  1299   1307   			else
  1300   1308   				c.sec.refs[id] = rsrc
  1301   1309   			end
  1302   1310   		end
  1303   1311   		table.insert(d, rsrc)
  1304   1312   		j:hook('block_insert', c, rsrc, s)
  1305         -		if id == '' then --shorthand syntax
         1313  +		if id == nil then --shorthand syntax
  1306   1314   			local embed = {
  1307   1315   				kind = 'embed';
  1308   1316   				rsrc = rsrc;
  1309   1317   				origin = c;
         1318  +				mode = 'inline';
  1310   1319   			}
  1311   1320   			table.insert(d, embed)
  1312   1321   			j:hook('block_insert', c, embed, s)
  1313   1322   		end
  1314   1323   
  1315   1324   		if brak then
  1316   1325   			c.mode = {
................................................................................
  1404   1413   			local mf = job:proc('modes', ctx.mode.kind)
  1405   1414   			if not mf then
  1406   1415   				ctx:fail('unimplemented syntax mode %s', ctx.mode.kind)
  1407   1416   			end
  1408   1417   			mf(job, ctx, l, dest) --NOTE: you are responsible for triggering the appropriate hooks if you insert anything!
  1409   1418   		end
  1410   1419   	else
  1411         -		if l then
         1420  +		if l and l ~= '' then
  1412   1421   			local function tryseqs(seqs, ...)
  1413   1422   				for _, i in pairs(seqs) do
  1414   1423   					if ((not i.seq ) or startswith(l, i.seq)) and
  1415   1424   					   ((not i.pred) or i.pred    (l, ctx  )) then
  1416   1425   						i.fn(l, ctx, job, dest, ...)
  1417   1426   						return true
  1418   1427   					end
................................................................................
  1547   1556   							r.origin:fail('resource “%s” is not inline and supplies no URI',
  1548   1557   											  r.id or "(anonymous)")
  1549   1558   						end
  1550   1559   
  1551   1560   						-- the resource has been cached. check the mime-type to see if
  1552   1561   						-- we need to parse it or if it is suitable as-is
  1553   1562   
  1554         -						if resource.mime.class == "text" then
  1555         -							if resource.mime.kind == "x.cortav" then
  1556         -								local sd, sc = r.origin.doc:sub(r.origin)
  1557         -								local lines = ss.str.breaklines(r.origin.doc.enc, resource.raw, {})
  1558         -								for i, ln in ipairs(lines) do
  1559         -									sc.line = sc.line + 1
  1560         -									ct.parse_line(ln, sc, sc.sec.blocks)
  1561         -								end
  1562         -								resource.doc = sd
         1563  +						if ss.mime 'text/x.cortav' < resource.mime then
         1564  +							local sd, sc = r.origin.doc:sub(r.origin)
         1565  +							-- we store the resource block itself in the declaration
         1566  +							-- slot so that its properties (e.g. context variables)
         1567  +							-- can affect the way the document is rendered
         1568  +							sc.declaration = r
         1569  +							local lines = ss.str.breaklines(r.origin.doc.enc, resource.raw, {})
         1570  +							for i, ln in ipairs(lines) do
         1571  +								sc.line = sc.line + 1
         1572  +								ct.parse_line(ln, sc, sc.sec.blocks)
  1563   1573   							end
         1574  +							resource.doc = sd
  1564   1575   						end
  1565   1576   					end
  1566   1577   					table.insert(srcs, resource)
  1567   1578   				end
  1568   1579   				r.srcs = srcs
  1569   1580   				-- note that resources do not themselves have kinds. when a
  1570   1581   				-- document requests to insert a resource, the renderer must
................................................................................
  1576   1587   		end
  1577   1588   	end
  1578   1589   
  1579   1590   	-- expand block macros
  1580   1591   	for i, sec in ipairs(ctx.doc.secorder) do
  1581   1592   		for n, r in pairs(sec.blocks) do
  1582   1593   			if r.kind == 'macro' then
  1583         -				local mc = r.origin:clone()
  1584         -				mc.invocation = r
  1585         -				local mac = r.origin:ref(r.macro)
         1594  +				local mc = r.origin
         1595  +				local mac = mc:ref(r.macro)
  1586   1596   				if not mac then
  1587         -					r.origin:fail('no such reference or resource “%s”', r.macro)
         1597  +					mc:fail('no such reference or resource “%s”', r.macro)
  1588   1598   				end
         1599  +
  1589   1600   				local subdoc, subctx = ctx.doc:sub(mc)
  1590   1601   				local rawbody
         1602  +				subctx.invocation = r
  1591   1603   
  1592   1604   				if type(mac) == 'string' then
  1593   1605   					rawbody = mac
  1594   1606   				elseif mac.raw then
  1595   1607   					rawbody = mac.raw
         1608  +					subctx.declaration = mac
  1596   1609   				else
  1597         -					r.origin:fail('block macro “%s” must be either a reference or an embedded text/x.cortav resource', r.macro)
         1610  +					mc:fail('block macro “%s” must be either a reference or an embedded text/x.cortav resource', r.macro)
  1598   1611   				end
  1599   1612   
  1600   1613   				local lines = ss.str.breaklines(ctx.doc.enc, rawbody)
  1601   1614   				for i, ln in ipairs(lines) do
  1602   1615   					ct.parse_line(ln, subctx, subctx.sec.blocks)
  1603   1616   				end
  1604   1617   				r.doc = subdoc

Modified render/html.lua from [14fa0c3d9d] to [84a861628f].

   853    853   				elseif s.mode == 'embed' then
   854    854   					local mime = s.mime:clone()
   855    855   					mime.opts = {}
   856    856   					return string.format('data:%s;base64,%s', mime, ss.str.b64e(s.raw))
   857    857   				end
   858    858   			end
   859    859   			--figure out how to embed the given object
          860  +			local function P(p) -- get prop
          861  +				if b.props and b.props[p] then
          862  +					return b.props[p]
          863  +				end
          864  +				return obj.props[p]
          865  +			end
   860    866   			local embedActs = {
   861    867   				{ss.mime'image/*',       function(s,ctr)
   862    868   					if s == nil then
   863    869   						return {tag = "picture", nodes = {}}
   864    870   					else
   865    871   						local uri = uriForSource(s)
   866    872   						local fbimg, idx
   867    873   						if next(ctr.nodes) == nil then
   868    874   							idx = 1
   869    875   							fbimg = {
   870    876   								elt = 'img'; --fallback
   871    877   								attrs = {
   872         -									alt = obj.props.desc or obj.props.detail or '';
   873         -									title = obj.props.detail;
          878  +									alt = P'desc' or P'detail' or '';
          879  +									title = P'detail';
   874    880   									src = uri;
   875         -									width = obj.props.width;
   876         -									height = obj.props.height;
          881  +									width = P'width';
          882  +									height = P'height';
   877    883   								};
   878    884   							}
   879    885   						else idx = #ctr.nodes end
   880    886   						table.insert(ctr.nodes, idx, {
   881    887   							elt = 'source'; --fallback
   882    888   							attrs = { srcset = uri; };
   883    889   						})
................................................................................
   972    978   			local top = rtype[2]() -- create container
   973    979   			for n, src in ipairs(obj.srcs) do
   974    980   				if rtype[1] < src.mime then
   975    981   					rtype[2](src, top)
   976    982   				end
   977    983   			end
   978    984   			local ft = flatten(top)
   979         -			local cap = b.cap or obj.props.desc or obj.props.detail
          985  +			local cap = b.cap or P'desc' or P'detail'
   980    986   			if b.mode == 'inline' then
   981    987   				-- TODO insert caption
   982    988   				return ft
   983    989   			else
   984    990   				local prop = {}
   985    991   				if b.mode == 'open' then
   986    992   					prop.open = true