Differences From
Artifact [62c90e9915]:
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