Overview
Comment: | add xref blocks, minor refactors |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
76fe4885f4e440299021f7299bc42f59 |
User & Date: | lexi on 2022-09-10 03:11:19 |
Other Links: | manifest | tags |
Context
2022-09-10
| ||
03:16 | defuck xref structure check-in: 0ef3dd0c77 user: lexi tags: trunk | |
03:11 | add xref blocks, minor refactors check-in: 76fe4885f4 user: lexi tags: trunk | |
01:02 | add path class; add URI support for HTML link output check-in: 8c11f3b669 user: lexi tags: trunk | |
Changes
Modified cortav.ct from [54b40e50db] to [fb6019b4ad].
118 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 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 -* [*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. 125 +* [*cross-references] ([`=>] [`⇒]): inserts a block-level link. has two forms for the sake of gemtext compatibility. [$styled-text] is a descriptive text of the destination. especially useful for menus and gemtext output. 126 +** the cortav syntax is [`=>[$ident] [$styled-text]], where [$ident] is an identifier; links to the same destination as [` \[>[$ident] [$styled-text]\]] would 127 +** the compatibility syntax is [`=> [$uri] [$styled-text]] (note the space before [$uri]!). instead of taking an identifier for an object in the document, it directly accepts a URI. note that this is not formally equivalent to gemtext's link syntax, which also allows paths in place of URIs; [`cortav] does not. the gemtext line ["=> /somewhere] would need to be expressed as ["=> file:/somewhere], and ["=> /somewhere?key=val] as ["http:/somewhere?key=val] (or ["gemini:/somewhere?key=val], if the result is to be served over a gemini server). 126 128 * [*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. 127 129 128 130 ##onspans styled text 129 131 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. 130 132 131 133 * strong {obj *|styled-text}: causes its text to stand out from the narrative, generally rendered as bold or a brighter color. 132 134 * emphatic {obj !|styled-text}: indicates that its text should be spoken with emphasis, generally rendered as italics
Modified cortav.lua from [08a1a9b804] to [c03c132cce].
1028 1028 flush() 1029 1029 buf.header = c == '+' 1030 1030 elseif c == ':' then 1031 1031 local lst = l:sub(p.byte-#c,p.byte-#c) 1032 1032 local nxt = l:sub(p.next.byte,p.next.byte) 1033 1033 if lst == '|' or lst == '+' and l:sub(p.byte-2,p.byte-2) ~= '\\' then 1034 1034 buf.align = 'left' 1035 - elseif nxt == '|' or nxt == '|' then 1035 + elseif nxt == '|' or nxt == '+' then 1036 1036 if buf.align == 'left' then 1037 1037 buf.align = 'center' 1038 1038 else 1039 1039 buf.align = 'right' 1040 1040 end 1041 1041 else 1042 1042 buf.str = buf.str .. c ................................................................................ 1076 1076 j:hook('block_table_insert', c, tbl, l) 1077 1077 j:hook('block_table_row_insert', c, tbl, tbl.rows[1], l) 1078 1078 end 1079 1079 end 1080 1080 1081 1081 local function insert_link_block(seq) 1082 1082 return blockwrap(function(s,c) 1083 - local r = s:sub(#seq):gsub('^%s+','') -- chomp 1084 - local uri, txt = r:match('^([^%s]*)%s*(.*)$') 1083 + local r = s:sub(#seq+1) 1084 + local k, uri, txt = r:match('^(%s*)([^%s]*)%s*(.*)$') 1085 1085 return { 1086 - uri = ss.uri(uri); 1087 - label = ct.parse_span(txt, c); 1086 + kind = 'link'; 1087 + uri = (k~='') and ss.uri(uri) or nil; 1088 + ref = (k=='') and uri or nil; 1089 + spans = ct.parse_span(txt, c); 1088 1090 } 1089 1091 end) 1090 1092 end 1091 1093 1092 1094 ct.ctlseqs = { 1093 1095 {seq = '.', fn = insert_paragraph}; 1094 1096 {seq = '¶', fn = insert_paragraph};
Modified render/html.lua from [78b49cf252] to [8ab06e9795].
401 401 h1 { 402 402 page-break-before: always; 403 403 } 404 404 h1,h2,h3,h4,h5,h6 { 405 405 page-break-after: avoid; 406 406 } 407 407 ]]; 408 + linkBlock = [[ 409 + a[href].link { 410 + position: relative; 411 + display: block; 412 + padding: .5em; 413 + padding-right: 1.5em; 414 + border: 1px solid @tone(0.2 30); 415 + background: @tone(0.05 30); 416 + font-size: 1.1em; 417 + margin: 0 1em; 418 + text-decoration: none; 419 + color: @tone(0.8 30); 420 + } 421 + a[href].link + a[href].link { 422 + margin-top: -1px; 423 + } 424 + a[href].link:hover { 425 + border-color: @tone(0.3 30); 426 + background: @tone(0.2 30); 427 + color: @tone(0.95 30); 428 + } 429 + a[href].link:hover + a[href].link { 430 + margin-top: 0; 431 + border-top: none; 432 + } 433 + a[href].link::after { 434 + display: block; 435 + position: absolute; 436 + right: .5em; 437 + content: "→"; 438 + top: 50%; 439 + margin-left: 1em; 440 + font-size: 1.8em; 441 + transform: translateY(-50%); 442 + color: @tone(0.3 30); 443 + } 444 + a[href].link:hover::after { 445 + color: @tone(0.7 30); 446 + } 447 + ]]; 408 448 } 409 449 410 450 local stylesNeeded = { 411 451 flags = {}; 412 452 order = {}; 413 453 } 414 454 local function addStyle(sty) ................................................................................ 447 487 448 488 local renderJob = doc:job('render_html', nil, render_state_handle) 449 489 doc.stage.job = renderJob; 450 490 451 491 local runhook = function(h, ...) 452 492 return renderJob:hook(h, render_state_handle, ...) 453 493 end 494 + 495 + local function htmlURI(uri) 496 + local family = uri:canfetch() 497 + if family == 'file' then 498 + if uri.namespace == 'localhost' then 499 + -- emit an actual file url 500 + return 'file://' .. uri:construct('path','frag') 501 + elseif uri.namespace == nil then 502 + -- this is gonna be tricky. first we establish the location 503 + -- of the CWD/asset base relative to the output file (if any; 504 + -- assume equivalent otherwise) then express the difference 505 + -- as a directory prefix. 506 + -- jk tho for now we just emit the path+frag sadlol TODO 507 + if uri.path == nil and uri.frag then 508 + -- file:#sec links to #sec within the current document 509 + return uri:part 'frag' 510 + else 511 + return uri:construct('path','frag') 512 + end 513 + else 514 + b.origin:fail('file: URI namespace must be empty or “localhost” for HTML links; others are not meaningful (offending URI: “%s”)', uri.raw) 515 + end 516 + elseif family == 'http' then 517 + local sc = 'http' 518 + if uri.class[1] == 'https' or uri.class[2] == 'tls' then 519 + sc = 'https' 520 + end 521 + if uri.namespace == nil and uri.auth == nil and uri.svc == nil then 522 + -- omit the scheme so we can use a relative path 523 + return uri:construct('path','query','frag') 524 + else 525 + uri.class = {sc} 526 + return tostring(uri) 527 + end 528 + else return tostring(uri) end 529 + end 530 + 531 + local function idLink(id,b) 532 + local dest_o, _, dest_s = b.origin:ref(id) 533 + if dest_o == nil then 534 + -- link is to the section itself 535 + return '#' .. getSafeID(dest_s) 536 + else 537 + if type(dest_o) == 'table' then 538 + return '#' .. getSafeID(dest_o) 539 + else -- URI in reference 540 + return htmlURI(ss.uri(dest_o)) 541 + end 542 + end 543 + end 454 544 455 545 local tagproc do 456 546 local html_open = function(t,attrs) 457 547 if attrs then 458 548 return t .. ss.reduce(function(a,b) return a..b end, '', 459 549 ss.map(function(v,k) 460 550 if v == true ................................................................................ 611 701 end 612 702 613 703 function span_renderers.raw(v,b,s) 614 704 return htmlSpan(v.spans, b, s) 615 705 end 616 706 617 707 function span_renderers.link(sp,b,s) 618 - local dest_o, _, dest_s = b.origin:ref(sp.ref) 619 - local href 620 - if dest_o == nil then 621 - -- link is to the section itself 622 - href = '#' .. getSafeID(dest_s) 623 - else 624 --- if sp.addr then href = sp.addr else 625 - if type(dest_o) == 'table' then 626 - href = '#' .. getSafeID(dest_o) 627 - else -- URI in reference 628 - local uri = ss.uri(dest_o) 629 - if uri.class[1] == 'file' 630 - or uri.class[1] == 'asset' then 631 - if uri.namespace == 'localhost' then 632 - -- emit an actual file url 633 - href = 'file://' .. uri:construct('path','frag') 634 - elseif uri.namespace == nil then 635 - -- this is gonna be tricky. first we establish the location 636 - -- of the CWD/asset base relative to the output file (if any; 637 - -- assume equivalent otherwise) then express the difference 638 - -- as a directory prefix. 639 - -- jk tho for now we just emit the path+frag sadlol TODO 640 - href = uri:construct('path','frag') 641 - else 642 - b.origin:fail('file: URI namespace must be empty or “localhost” for HTML links; others are not meaningful (offending URI: “%s”)', dest_o) 643 - end 644 - elseif uri:canfetch() == 'http' then 645 - local sc = 'http' 646 - if uri.class[1] == 'https' or uri.class[2] == 'tls' then 647 - sc = 'https' 648 - end 649 - if uri.namespace == nil and uri.auth == nil and uri.svc == nil then 650 - -- omit the scheme so we can use a relative path 651 - href = uri:construct('path','query','frag') 652 - else 653 - uri.class = {sc} 654 - href = tostring(uri) 655 - end 656 - else href = tostring(uri) end 657 - end 658 - end 659 - return tag('a',{href=href},next(sp.spans) and htmlSpan(sp.spans,b,s) or href) 708 + local href = idLink(sp.ref,b) 709 + return tag('a',{href=href}, next(sp.spans) and htmlSpan(sp.spans,b,s) or href) 660 710 end 661 711 662 712 span_renderers['line-break'] = function(sp,b,s) 663 713 return elt('br') 664 714 end 665 715 666 716 function span_renderers.macro(m,b,s) ................................................................................ 773 823 else 774 824 -- handle other uses of labels here 775 825 end 776 826 end; 777 827 ['list-item'] = function(b,s) 778 828 return tag('li', nil, sr.htmlSpan(b.spans, b, s), b) 779 829 end; 830 + link = function(b,s) 831 + addStyle 'linkBlock' 832 + local href 833 + if b.uri then 834 + href = htmlURI(b.uri) 835 + elseif b.ref then 836 + href = idLink(b.ref, b) 837 + end 838 + local sp = sr.htmlSpan(b.spans, b, s) 839 + return tag('div', {}, 840 + catenate{tag('a',{class='link', href=href},sp)}) 841 + end; 780 842 table = function(b,s) 781 843 local tb = {} 782 844 for i, r in ipairs(b.rows) do 783 845 local row = {} 784 846 for i, c in ipairs(r) do 785 847 table.insert(row, tag(c.header and 'th' or 'td', 786 848 {align=c.align}, sr.htmlSpan(c.spans, b))) ................................................................................ 863 925 864 926 function block_renderers.embed(b,s) 865 927 local obj 866 928 if b.rsrc 867 929 then obj = b.rsrc 868 930 else obj = b.origin:ref(b.ref) 869 931 end 870 - local function htmlURI(u) 871 - local family = u:canfetch() 872 - if family == 'file' or 873 - (family == 'http' and u.namespace == nil) then 874 - -- TODO asset: 875 - return u.path 876 - else 877 - return tostring(u) 878 - end 879 - end 880 932 local function uriForSource(s) 881 933 if s.mode == 'link' or s.mode == 'auto' then 882 934 return htmlURI(s.uri) 883 935 elseif s.mode == 'embed' then 884 936 local mime = s.mime:clone() 885 937 mime.opts = {} 886 938 return string.format('data:%s;base64,%s', mime, ss.str.b64e(s.raw))