Differences From
Artifact [ab8e0fd21b]:
40 40 if me.linbuf == nil then
41 41 me.linbuf = ss.strac()
42 42 end
43 43 me.linbuf(text)
44 44 end;
45 45 txt = function(me, str, ...)
46 46 if str == nil then return end
47 + if me.linbuf == nil then
48 + -- prevent unwanted linebreaks
49 + str = str:gsub('^%s+','')
50 + end
47 51 me:raw(gsan(str))
48 52 -- WARN this will cause problems if str is ever allowed to
49 53 -- include a line break. we can sanitize by converting
50 54 -- every line break into a new entry in the table, but i
51 55 -- don't think it should be possible for a \n to reach us
52 56 -- at this point, so i'm omitting the safety check as it
53 57 -- would involve an excessive hit to performance
................................................................................
61 65 me:flush()
62 66 me:txt(...)
63 67 end;
64 68 req = function(me, r)
65 69 me:flush()
66 70 table.insert(me.lines, '.'..r)
67 71 end;
72 + sreq = function(me, r)
73 + me:flush()
74 + table.insert(me.lines, "'"..r)
75 + end;
68 76 esc = function(me, e)
69 77 me:raw('\\' .. e)
70 78 end;
79 + draw = function(me, args)
80 + for _,v in ipairs(args) do
81 + me:esc("D'" .. v .. "'")
82 + end
83 + end;
71 84 flush = function(me)
72 85 if me.linbuf ~= nil then
73 86 local line = me.linbuf:compile()
74 87 local first = line:sub(1,1)
75 88 -- make sure our lines aren't accidentally interpreted
76 89 -- as groff requests. groff is kinda hostile to script
77 90 -- generation, huh?
................................................................................
163 176 };
164 177 color = {'.color'};
165 178 insert = {};
166 179 footnote = {
167 180 '.de footnote-blank';
168 181 '. sp 0.25m';
169 182 '..';
183 +
170 184 '.ev footnote-env';
171 185 '. ps 8p';
172 186 '. in 0.5c';
173 - '. blm footnote-blank';
174 187 '.ev';
188 +
175 189 '.de footnote-print';
176 190 -- '. sp |\\\\n[.p]u-\\\\n[footnote-pos]u';
177 191 '. sp 0.5c';
178 192 '. ev footnote-env';
193 + '. blm footnote-blank';
179 194 '. fn';
195 + '. blm np';
180 196 '. ev';
181 197 '. rm fn';
182 198 '. nr footnote-pos 0';
183 - -- move the trap past the bottom of the page so it's not
199 + -- move the trap past the top of the page so it's not
184 200 -- invoked again until more footnotes have been assembled
185 - '. ch footnote-print |\\\\n[.p]u+10';
201 + '. ch footnote-print |-1000';
186 202 '. bp';
187 203 '..';
204 +
188 205 '.wh |\\n[.p]u footnote-print';
189 206 };
190 207 root = {
191 208 -- these are macros included in all documents
192 209 -- page offset is hideously broken and unusable; we
193 210 -- zero it out so we can use .in to control indents
194 211 -- instead. note that the upshot of this is we need
195 212 -- to manually specify the indent in every other
196 213 -- environment from now on, .evc doesn't seem to cut it
197 214 -- set up the page title environment & trap
198 215 "'in 2c";
199 - "'ll 18c";
216 + "'ll 19.5c";
200 217 "'po 0";
201 218 "'ps 13p";
202 219 "'vs 15p";
203 220 ".ev pgti";
204 221 ". evc 0";
205 222 ". fam H";
206 223 ". ps 10pt";
................................................................................
212 229 '. lt 19c';
213 230 ". tl '\\\\*[doctitle]'\\fB\\\\*[title]\\f[]'%'";
214 231 '. po 0';
215 232 ". br";
216 233 '. ev';
217 234 '. sp 1.2c';
218 235 '..';
219 - '.wh 0 ph';
220 236 '.de np';
221 - '. sp 0.2c';
237 + '. sp 0.6m';
222 238 '..';
223 - '.blm np'
239 + '.blm np';
240 + '.wh 0 ph';
224 241
225 242 };
226 243 }
227 244 rs.macsNeeded = {
228 245 order = {};
229 246 map = {};
230 247 count = 0;
................................................................................
377 394 elseif spanRenderers[v.kind] then
378 395 spanRenderers[v.kind](rc, v, b, sec)
379 396 end
380 397 end
381 398 end
382 399
383 400 local blockRenderers = {}
401 + blockRenderers['horiz-rule'] = function(rc, b, sec)
402 + rc.prop.margin = { top = 0.3 }
403 + rc.prop.underline = 0.1
404 + end
384 405 function blockRenderers.label(rc, b, sec)
385 406 if ct.sec.is(b.captions) then
386 407 local sizes = {36,24,12,8,4,2}
387 - local margins = {0,5,2,1,0.5}
408 + local margins = {0,3}
388 409 local dedents = {2.5,1.3,0.8,0.4}
410 + local uls = {3,1.5,0.5,0.25}
389 411 rc.prop.dsz = sizes[b.captions.depth] or 10
390 - rc.prop.underline = b.captions.depth < 4
412 + rc.prop.underline = uls[b.captions.depth]
391 413 rc.prop.bold = b.captions.depth > 3
392 414 rc.prop.margin = {
393 - top = margins[b.captions.depth] or 0;
415 + top = margins[b.captions.depth] or 1;
394 416 bottom = 0.1;
395 417 }
418 + rc.prop.vassure = rc.prop.dsz+70;
396 419 rc.prop.indent = -(dedents[b.captions.depth] or 0)
397 - rc.prop.underline = true
398 420 rc.prop.chtitle = collectText(rc, b.spans, b.spec):compile()
399 421 if b.captions.depth == 1 then
400 422 rc.prop.breakBefore = true
401 423 end
402 424 rs.renderSpans(rc, b.spans, b, sec)
403 425 else
404 426 ss.bug 'tried to render label for an unknown object type':throw()
................................................................................
419 441 local skippedFirstPagebreak = doc.secorder[1]:visible()
420 442 local deferrer = ss.declare {
421 443 ident = 'groff-deferrer';
422 444 mk = function(buf) return {ops={}, tgt=buf} end;
423 445 fns = {
424 446 esc = function(me, str) table.insert(me.ops, {0, str}) end;
425 447 req = function(me, str) table.insert(me.ops, {1, str}) end;
448 + draw = function(me, lst) table.insert(me.ops,{2, lst}) end;
426 449 flush = function(me)
427 450 for i=#me.ops,1,-1 do
428 451 local d = me.ops[i]
429 452 if d[1] == 0 then
430 453 me.tgt:esc(d[2])
431 454 elseif d[1] == 1 then
432 455 me.tgt:req(d[2])
456 + elseif d[1] == 2 then
457 + me.tgt:draw(d[2])
433 458 end
434 459 end
435 460 me.ops = {}
436 461 end;
437 462 };
438 463 }
439 464 function rs.emitSpan(gtxt, s)
................................................................................
458 483 else
459 484 gtxt:txt(s.txt)
460 485 end
461 486 defer:flush()
462 487 if s.div then
463 488 for div, body in pairs(s.div) do
464 489 if div == 'fn' then
465 - gtxt:req 'ev footnote-env'
490 + gtxt:sreq 'ev footnote-env'
466 491 end
467 - gtxt:req('boxa '..div)
492 + gtxt:sreq('boxa '..div)
468 493 gtxt:txt(body)
469 494 gtxt:raw '\n'
470 - gtxt:req 'boxa'
495 + gtxt:sreq 'boxa'
471 496 if div == 'fn' then
472 - gtxt:req 'ev'
473 - gtxt:req 'nr footnote-pos (\\n[footnote-pos]u+\\n[dn]u)'
474 - gtxt:req 'ch footnote-print -(\\n[footnote-pos]u+1c)'
497 + gtxt:sreq 'ev'
498 + gtxt:sreq 'nr footnote-pos (\\n[footnote-pos]u+\\n[dn]u)'
499 + gtxt:sreq 'ch footnote-print -(\\n[footnote-pos]u+1.5c)'
475 500 end
476 501 end
477 502 end
478 503 end
479 504 function rs.emitBlock(gtxt, b)
480 505 local didfinalbreak = false
481 506 local defer = deferrer(gtxt)
................................................................................
485 510 end
486 511 if ln.breakBefore then
487 512 if skippedFirstPagebreak then
488 513 gtxt:req 'bp'
489 514 else
490 515 skippedFirstPagebreak = true
491 516 end
517 + elseif ln.vassure then
518 + gtxt:req(string.format('if (\\n[.t]u < %sp) .bp',ln.vassure))
492 519 end
493 520 if ln.indent then
494 521 if ln.indent < 0 then
495 522 gtxt:req('in '..tostring(ln.indent)..'m')
496 523 defer:req 'in'
497 524 gtxt:req('ll +'..tostring(-ln.indent)..'m')
498 525 defer:req 'll'
................................................................................
505 532 if ln.margin then
506 533 if ln.margin.top then
507 534 gtxt:req(string.format('sp %sm', ln.margin.top))
508 535 end
509 536 end
510 537
511 538 if ln.underline then
512 - defer:esc("D'l \\n[.ll]u-\\n[.in]u 0'")
513 - defer:esc"v'-0.5'"
514 539 defer:req'br'
540 + defer:draw {
541 + "t "..tostring(ln.underline).."p";
542 + "l \\n[.ll]u-\\n[.in]u 0";
543 + }
544 + defer:esc("h'-" .. tostring(ln.underline) .. "p'")
545 + defer:esc"v'-0.5'"
515 546 end
516 547
517 548 if ln.dsz and ln.dsz > 0 then
518 549 gtxt:req('ps +' .. tostring(ln.dsz) .. 'p')
519 550 defer:req('ps -' .. tostring(ln.dsz) .. 'p')
520 551 elseif ln.sz or ln.dsz then
521 552 if ln.sz and ln.sz <= 0 then