cortav  Diff

Differences From Artifact [62c90e9915]:

To Artifact [3a20caca9a]:


    19     19   local lines = function(...)
    20     20   	local s = ss.strac()
    21     21   	for _, v in pairs{...} do s(v) end
    22     22   	return s
    23     23   end
    24     24   
    25     25   local function gsan(str)
    26         -	local tocodepoint = function(ch)
    27         -		return string.format('\\[u%04X]', utf8.codepoint(ch))
           26  +	-- groff does not support UTF-8
           27  +	local ascii = {}
           28  +	for p,c in utf8.codes(str) do
           29  +		if c > 0x7F or c == 0x27 or c == 0x22 or c == 0x5C then
           30  +			table.insert(ascii, string.format('\\[u%04X]', c))
           31  +		else
           32  +			table.insert(ascii, utf8.char(c))
           33  +		end
    28     34   	end
    29         -	str = str:gsub('(["\'\\])',tocodepoint)
           35  +	str = table.concat(ascii)
           36  +	str = str:gsub('\t','\\t') -- tabs are sometimes syntactically meaningful
    30     37   	return str
    31     38   end
    32     39   
    33     40   local gtxt = ss.declare {
    34     41   	ident = 'groff-text';
    35     42   	mk = function() return {
    36     43   		lines = {};
................................................................................
   140    147   				spans = self.spans;
   141    148   			}
   142    149   		end;
   143    150   		blocks = {};
   144    151   		prop = {};
   145    152   		block = function(self)
   146    153   			local sub = self:clone()
          154  +			sub.parent = self -- needed for blocks that contain blocks
   147    155   			sub.spans = {}
   148    156   			sub.blocks = nil
          157  +			sub.block = nil
   149    158   			sub.span = function(me, ln)
   150    159   				local p = ss.clone(me.prop)
   151    160   				p.txt = ln
   152    161   				p.block = sub
   153    162   				p.origin = me.origin
   154    163   				table.insert(me.spans, p)
   155    164   				return p
................................................................................
   400    409   	local blockRenderers = {}
   401    410   	blockRenderers['horiz-rule'] = function(rc, b, sec)
   402    411   		rc.prop.margin = { top = 0.3 }
   403    412   		rc.prop.underline = 0.1
   404    413   	end
   405    414   	function	blockRenderers.label(rc, b, sec)
   406    415   		if ct.sec.is(b.captions) then
          416  +			local visDepth = b.captions.depth + (b.origin.docDepth or 0)
   407    417   			local sizes = {36,24,12,8,4,2}
   408    418   			local margins = {0,3}
   409    419   			local dedents = {2.5,1.3,0.8,0.4}
   410    420   			local uls = {3,1.5,0.5,0.25}
   411         -			rc.prop.dsz = sizes[b.captions.depth] or 10
   412         -			rc.prop.underline = uls[b.captions.depth]
   413         -			rc.prop.bold = b.captions.depth > 3
          421  +			rc.prop.dsz = sizes[visDepth] or 10
          422  +			rc.prop.underline = uls[visDepth]
          423  +			rc.prop.bold = visDepth > 3
   414    424   			rc.prop.margin = {
   415         -				top = margins[b.captions.depth] or 1;
          425  +				top = margins[visDepth] or 1;
   416    426   				bottom = 0.1;
   417    427   			}
   418    428   			rc.prop.vassure = rc.prop.dsz+70;
   419         -			rc.prop.indent = -(dedents[b.captions.depth] or 0)
          429  +			rc.prop.indent = -(dedents[visDepth] or 0)
   420    430   			rc.prop.chtitle = collectText(rc, b.spans, b.spec):compile()
   421         -			if b.captions.depth == 1 then
          431  +			if visDepth == 1 then
   422    432   				rc.prop.breakBefore = true
   423    433   			end
   424    434   			rs.renderSpans(rc, b.spans, b, sec)
   425    435   		else
   426    436   			ss.bug 'tried to render label for an unknown object type':throw()
   427    437   		end
   428    438   	end
   429    439   	function	blockRenderers.paragraph(rc, b, sec)
   430    440   		rs.renderSpans(rc, b.spans, b, sec)
          441  +	end
          442  +	function	blockRenderers.macro(rc, b, sec)
          443  +		local rc = rc.parent:clone()
          444  +		rs.renderDoc(rc, b.doc)
          445  +	end
          446  +	function	blockRenderers.quote(rc, b, sec)
          447  +		local rc = rc.parent:clone()
          448  +		rc.prop.indent = (rc.prop.indent or 0) + 1
          449  +		local added = rs.renderDoc(rc, b.doc)
          450  +		 -- select last block of last section and increase bottom margin
          451  +		local ap = added[#added].blocks
          452  +		ap = ap[#ap].prop
          453  +		if ap.margin then
          454  +			if ap.margin.bottom then
          455  +				ap.margin.bottom = ap.margin.bottom + 1.1
          456  +			else
          457  +				ap.margin.bottom = 1.1
          458  +			end
          459  +		else
          460  +			ap.margin = {bottom = 1.1}
          461  +		end
          462  +	end
          463  +	function	blockRenderers.table(rc, b, sec)
          464  +		function rc:begin(g)
          465  +			g:req 'TS'
          466  +			local aligns = {}
          467  +			for i, c in ipairs(b.rows[1]) do
          468  +				aligns[i] = ({
          469  +					left = 'l';
          470  +					center = 'c';
          471  +					right = 'r';
          472  +				})[c.align] or 'l'
          473  +			end
          474  +			table.insert(aligns, '.')
          475  +			g:txt(table.concat(aligns, ' ') .. '\n')
          476  +
          477  +			local rc_hdr = rc:clone()
          478  +			rc_hdr.prop.bold = true
          479  +			for ri, r in ipairs(b.rows) do
          480  +				for ci, c in ipairs(r) do
          481  +					local sp = collect(c.header and rc_hdr or rc, c.spans, b, sec)
          482  +					for si, s in ipairs(sp) do rs.emitSpan(g,s) end
          483  +					g:raw '\t'
          484  +				end
          485  +				if ri ~= #b.rows then g:raw '\n' end
          486  +			end
          487  +			g:req 'TE'
          488  +		end
   431    489   	end
   432    490   	function rs.renderBlock(rc, b, sec, outerBlockRenderContext)
   433    491   		if blockRenderers[b.kind] then
   434    492   			local rcc = rc:block()
   435    493   			blockRenderers[b.kind](rcc, b, sec)
   436    494   		end
   437    495   	end
................................................................................
   556    614   			if ln.dsz then
   557    615   				defer:req('ps +' .. tostring(0 - ln.dsz) .. 'p')
   558    616   			else
   559    617   				defer:req'ps'
   560    618   			end
   561    619   		end
   562    620   
   563         -		for i,s in pairs(b.spans) do
   564         -			rs.emitSpan(gtxt, s)
          621  +		if b.begin then b:begin(gtxt) end
          622  +		if b.spans then
          623  +			for i,s in pairs(b.spans) do
          624  +				rs.emitSpan(gtxt, s)
          625  +			end
   565    626   		end
   566         -
          627  +		if b.complete then b:complete(gtxt) end
   567    628   
   568    629   		if ln.margin then
   569    630   			if ln.margin.bottom then
   570    631   				gtxt:req(string.format('sp %sm', ln.margin.bottom))
   571    632   			end
   572    633   		end
   573    634   
   574    635   		defer:flush()
   575    636   
   576    637   		if not ln.margin then gtxt:brk() end
   577    638   	end
   578    639   
   579         -	local ir = {}
   580         -	for i, sec in ipairs(doc.secorder) do
   581         -		if sec.kind == 'ordinary' then
   582         -			local rc = mkrc()
   583         -			for j, b in ipairs(sec.blocks) do
   584         -				rs.renderBlock(rc, b, sec)
          640  +	function rs.renderDoc(gctx, doc, ir) ir = ir or {}
          641  +		for i, sec in ipairs(doc.secorder) do
          642  +			if sec.kind == 'ordinary' then
          643  +				local rc = gctx and gctx:clone() or mkrc()
          644  +				for j, b in ipairs(sec.blocks) do
          645  +					rs.renderBlock(rc, b, sec)
          646  +				end
          647  +				table.insert(ir, {blocks = rc.blocks, src = sec})
   585    648   			end
   586         -			table.insert(ir, {blocks = rc.blocks, src = sec})
   587    649   		end
          650  +		return ir
   588    651   	end
          652  +	local ir = rs.renderDoc(nil, doc)
   589    653   
   590    654   	local gd = gtxt()
   591    655   	for i, s in ipairs(ir) do
   592    656   		for j, b in ipairs(s.blocks) do
   593    657   			rs.emitBlock(gd,b)
   594    658   		end
   595    659   	end
................................................................................
   613    677   				top = s.depth
   614    678   				doctitle = collectText(mkrc():block(), s.heading_node.spans, s.heading_node, s):compile()
   615    679   			end
   616    680   		end
   617    681   	end
   618    682   	macs('.ds doctitle '..doctitle)
   619    683   
   620         -	return macs:compile'\n' .. '\n' .. gd:compile()
          684  +	return macs:compile'\n' .. '\n' .. gd:compile() .. '\n'
          685  +	-- if the document doesn't end with the character \n, groff will bitch
          686  +	-- and moan in certain circumstances
   621    687   end