Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- This file: -- http://anggtwu.net/blogme3/sandwiches.lua.html -- http://anggtwu.net/blogme3/sandwiches.lua -- (find-angg "blogme3/sandwiches.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2023oct23 -- This file is part of blogme3. -- See: http://anggtwu.net/blogme3-sandwiches.html -- (find-TH "blogme3-sandwiches") -- Typical usage: -- -- require "sandwiches-defs" -- use_sand_htmlizeline() -- -- See: (find-blogme3 "sandwiches-defs.lua") -- (find-blogme3 "sandwiches-defs.lua" "use_sand_htmlizeline") -- -- -- This file defines classes for transforming sexps into "sandwiches" -- that alternate between parts that are plain text (slices of bread) -- and parts that are hrefs with both a target URL and text -- (fillings). For example, this sexp -- -- (find-eev-intro "1." (+ -2 -3) +4 "foo" "bar") -- -- can have these three intervals marked as "fillings": -- -- (find-eev-intro "1." (+ -2 -3) +4 "foo" "bar") -- -------------- :1: head -- -- :2m: sec -- --:e: end -- -- its intervals are: -- -- (find-eev-intro "1." (+ -2 -3) +4 "foo" "bar") -- - :bread -- -------------- :filling:1: head -- -- :bread -- -- :filling:2m: sec -- ------------------------- :bread -- --:filling:e: end -- :bread -- -- Each interval is represented by a "be" structure, that in the case -- of bread is just a pair {b=<pos>, e=<pos>}, and in the case of -- filling is a table {b=<pos>, e=<pos>, text=<string>, st=<st>}, -- where <st> is either a SexpTarget structure or nil. The -- representation above displays for each filling the "name" of its -- interval: -- -- "1" means "first item of the sexp", -- "2m" means "middle of the second item of the sexp", -- "e" means "end of the sexp" (the '")"'). -- -- An object si of the class SexpIntervals has these fields: -- -- si.line: the line that we are trying to htmlize, -- -- si.left,si.sexp,si.head,si.skel,si.right: the results of running -- getsexpr(si.line), -- -- si.item_be_s: an array of "be"s with just the fields b and e, -- one for each item, -- -- si.filling_be_s: a table of "be"s with the fields b, e, and -- text, and maybe st, indexed by `b's, -- -- si.b_to_name: a table that lets us converts the `b's of -- intervals that are fillings to their names, and back; the `b's -- are numbers, and the names are strings. -- -- The documentation at this moment consists mostly of test blocks. -- See: (find-eepitch-intro "3. Test blocks") -- «.getsexpr» (to "getsexpr") -- «.SexpIntervals» (to "SexpIntervals") -- «.SexpIntervals-tests» (to "SexpIntervals-tests") -- «.SexpTarget» (to "SexpTarget") -- «.SexpTarget-tests» (to "SexpTarget-tests") -- «.SexpHead» (to "SexpHead") -- «.SexpHead-tests» (to "SexpHead-tests") -- «.code_helponly» (to "code_helponly") -- «.code_helponly-tests» (to "code_helponly-tests") -- «.HtmlizeLine» (to "HtmlizeLine") -- «.HtmlizeLine-tests» (to "HtmlizeLine-tests") -- «.code_c_d_angg» (to "code_c_d_angg") -- «.code_c_d_angg-tests» (to "code_c_d_angg-tests") -- «.code_c_d_remote» (to "code_c_d_remote") -- «.code_c_d_remote-tests» (to "code_c_d_remote-tests") -- «.code_intro» (to "code_intro") -- «.code_intro-tests» (to "code_intro-tests") -- «.code_c_m_b» (to "code_c_m_b") -- «.code_c_m_b-tests» (to "code_c_m_b-tests") -- «.code_youtube» (to "code_youtube") -- «.code_youtube-tests» (to "code_youtube-tests") -- «getsexpr» (to ".getsexpr") -- Based on: (find-angg "LUA/lua50init.lua" "getsexp") -- New version: (find-angg "LUA/SexpAtEol1.lua" "SexpAtEol-tests") -- getsexpr = function (linestr) local right = linestr:reverse():match("%s*"):reverse() local linestr0 = linestr:sub(1, -#right-1) local sexp, head, skel, left = getsexp(linestr0) return sexp, head, skel, left, right end -- ____ ___ _ _ -- / ___| _____ ___ __|_ _|_ __ | |_ ___ _ ____ ____ _| |___ -- \___ \ / _ \ \/ / '_ \| || '_ \| __/ _ \ '__\ \ / / _` | / __| -- ___) | __/> <| |_) | || | | | || __/ | \ V / (_| | \__ \ -- |____/ \___/_/\_\ .__/___|_| |_|\__\___|_| \_/ \__,_|_|___/ -- |_| -- -- «SexpIntervals» (to ".SexpIntervals") -- SexpIntervals = Class { type = "SexpIntervals", from = function (linestr) local sexp, head, skel, left, right = getsexpr(linestr) if not sexp then return end local si = SexpIntervals { line=str, -- Like '# (find-eev-intro "1.")' sexp=sexp, -- like '(find-eev-intro "1.")' head=head, -- like 'find-eev-intro' skel=skel, -- like '(find-eev-intro "__")' left=left, -- like '# ' right=right, -- like '' } local skelbody = " "..si.skel:sub(2,-2).." " local item_be_s = {} for b,e in skelbody:gmatch("()[^ \t]+()") do table.insert(item_be_s, {b=b, e=e}) end si.item_be_s = item_be_s si.filling_be_s = VTable {} -- filling intervals, indexed by `b's si.b_to_name = HTable {} -- `b's <-> `name's; for example 2 <-> "1" return si end, __tostring = function (si) return si:tostring() end, __index = { -- -- When si.sexp = '(find-foopdf (+ -2 42) "Text")' -- we have si:sexp_rawarg(1) = 'find-foopdf', -- si:sexp_numericarg(2) = 40, -- si:sexp_strarg(3) = 'Text'. sexp_sub = function (si, b, e) return si.sexp:sub(b, e-1) end, sexp_rawarg = function (si, n) local be = si.item_be_s[n] if not be then return end return si:sexp_sub(be.b, be.e) end, sexp_strarg = function (si, n) local rawarg = si:sexp_rawarg(n) if not rawarg then return end if not rawarg:match('^".*"$') then return end return rawarg:sub(2, -2) end, sexp_numericarg = function (si, n) local rawarg = si:sexp_rawarg(n) if not rawarg then return end if rawarg:match('^[-+]?%d+$') then return tonumber(rawarg) end local body = rawarg:match('^%(%+ (.*)%)') if body then local total = 0 for _,k in ipairs(map(tonumber, split(body))) do total = total + k end return total end end, -- n_shrink_to_b_e_name = function (si, n, shrink) if n == "e" then local e = #si.sexp+1 local b = (si.sexp:sub(-2, -2) == '"') and e-2 or e-1 return b,e,"e" end local be = si.item_be_s[n] if shrink == nil or shrink == 0 then return be.b, be.e, n.."" end if shrink == 1 then return be.b+1, be.e-1, n.."m" end error() end, add_filling0 = function (si, be) local b,name = be.b, be.name si.filling_be_s[b] = be si.b_to_name[name] = b si.b_to_name[b] = name end, add_filling = function (si, n, shrink, text, st) local b,e,name = si:n_shrink_to_b_e_name(n, shrink) local be = VTable {b=b, e=e, name=name, text=text} be.st = (st and SexpTarget.from(st)) or SexpTarget.from(text) -- if not be.st then be.st = SexpTarget {text=text} end si:add_filling0(be) return si end, -- dash = function (si, b, e) return (" "):rep(b-1) .. ("-"):rep(e-b) .. (" "):rep(#si.sexp-e+1) end, be_name = function (si, be) return si.b_to_name[be.b] end, filling_to_string = function (si, be) return format("%s:filling:%s: %s", si:dash(be.b, be.e), si:be_name(be), be.text) end, fillings_sorted = function (si) local bes = {} for _,b in ipairs(sorted(keys(si.filling_be_s))) do table.insert(bes, si.filling_be_s[b]) end return bes end, tostring = function (si) local bigstr = si.sexp for _,be in ipairs(si:fillings_sorted()) do bigstr = bigstr.."\n"..si:filling_to_string(be) end return bigstr end, -- tosandwich = function (si) local fills = si:fillings_sorted() local bes, lastpos = VerticalTable {}, 1 local add = function (b, e, st) table.insert(bes, {b=b, e=e, origtext=si:sexp_sub(b, e), st=st}) end for _,be in ipairs(fills) do add(lastpos, be.b) add(be.b, be.e, be.st) lastpos = be.e end add(lastpos, #si.sexp+1) return bes end, -- name_to_st = function (si, name) return si.filling_be_s[si.b_to_name[name]].st end, target_st = function (si) local o = si.b_to_name["e"] or si.b_to_name["2m"] or si.b_to_name["2"] or si.b_to_name["1"] return si.filling_be_s[o].st end, -- -- :head_apply() uses the table of SexpHeads defined below. head_apply = function (si) local sh = _SH[si.head] if sh then sh:f(si); return true end end, }, } -- «SexpIntervals-tests» (to ".SexpIntervals-tests") --[==[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "sandwiches.lua" si = SexpIntervals.from [[ (find-foopdf (+ -2 42) "Text") ]] PPV(si) = si:sexp_rawarg(1) --> "find-foopdf" = si:sexp_numericarg(2) --> 40 = si:sexp_strarg(3) --> "Text" = si = si:add_filling(1, nil, "head") = si:add_filling("e", nil, "end") = si:add_filling(3, 1, "str") = si:name_to_st("3m") = si:target_st("e") PPV(si:fillings_sorted()) = si:tosandwich() --]==] -- ____ _____ _ -- / ___| _____ ___ _|_ _|_ _ _ __ __ _ ___| |_ -- \___ \ / _ \ \/ / '_ \| |/ _` | '__/ _` |/ _ \ __| -- ___) | __/> <| |_) | | (_| | | | (_| | __/ |_ -- |____/ \___/_/\_\ .__/|_|\__,_|_| \__, |\___|\__| -- |_| |___/ -- -- «SexpTarget» (to ".SexpTarget") -- infomanual_basedir = infomanual_basedir or VerticalTable {} SexpTarget = Class { type = "SexpTarget", from = function (o) if type(o) == "string" then return SexpTarget {text=o} end if otype(o) == "SexpTarget" then return o end error() end, __tostring = mytabletostring, __index = { url = function (st) if st.f then return st[st.f](st) end return st.text end, ru = function (st, relativeurl) return "http://anggtwu.net/"..relativeurl -- change this end, -- find_angg = function (st) local fname,anchor = st.fname, st.anchor return st:ru(fname..(st.ext or ".html").. (anchor and ("#"..anchor) or "")) end, find_intro = function (st) local stem,anchor = st.stem, st.anchor local anggurl = "eev-intros/find-"..stem.."-intro.html" if anchor then anggurl = anggurl.."#"..anchor end return st:ru(anggurl) end, find_node = function (st) local manual,node = st.manual, st.node local baseurl = infomanual_basedir[manual] if not baseurl then return nil end local shre = "([-'/ &])" local shtable = {["-"] = "_002d", ["'"] = "_0027", ["/"] = "_002f", [" "] = "-", ["&"] = "-"} local shnode = node and node:gsub("%s+", " "):gsub(shre, shtable) return baseurl..(shnode or "") end, find_youtube = function (st) local hash,time = st.hash, st.time return youtube_make_url(hash, time) end, find_pdf = function (st) local pdfurl,page = st.pdfurl, st.page return pdfurl..(page and "#page="..page or "") end, find_remote = function (st) local baseurl,rest = st.baseurl, st.rest return baseurl..rest end, }, } -- «SexpTarget-tests» (to ".SexpTarget-tests") --[==[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "sandwiches.lua" st = SexpTarget.from("foo") = st = st:url() SexpTarget.__index.foo = function (st) return "FOO" end = SexpTarget { f="foo" } :url() SexpTarget.__index.foo = function (st) return "FOO"..st.a end = SexpTarget { f="foo", a="AAA" } :url() = SexpTarget { f="find_angg", fname="abc/def" } :url() = SexpTarget { f="find_angg", fname="abc/def", anchor="ghi" } :url() = SexpTarget { f="find_intro", stem="eev" } :url() = SexpTarget { f="find_intro", stem="eev", anchor="1" } :url() = SexpTarget { f="find_youtube", hash="0123456789abc" } :url() = SexpTarget { f="find_youtube", hash="0123456789abc", time="1:23" } :url() infomanual_basedir["emacs"] = "http://gnu/manual/emacs/" = SexpTarget { f="find_node", manual="emacs" } :url() = SexpTarget { f="find_node", manual="emacs", node="Sec 1-2/3" } :url() = SexpTarget { f="find_node", manual="emAcs", node="Sec 1-2/3" } :url() --]==] -- ____ _ _ _ -- / ___| _____ ___ __ | | | | ___ __ _ __| | -- \___ \ / _ \ \/ / '_ \| |_| |/ _ \/ _` |/ _` | -- ___) | __/> <| |_) | _ | __/ (_| | (_| | -- |____/ \___/_/\_\ .__/|_| |_|\___|\__,_|\__,_| -- |_| -- -- «SexpHead» (to ".SexpHead") -- SexpHead = Class { type = "SexpHead", __tostring = mytabletostring, __index = { }, } _SH = VerticalTable {} -- «SexpHead-tests» (to ".SexpHead-tests") --[==[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "sandwiches.lua" dofile "cruft-jan2024.lua" _SH["foo"] = SexpHead { e = "abc", f = function (sh, si) si:add_filling(1, nil, "FOO") si:add_filling(2, 1, si:sexp_strarg(3)) si:add_filling("e", nil, sh.e) end, } si = SexpIntervals.from [[ (foo "def" "ghi") ]] si:head_apply() = si = _SH["foo"] = _SH --]==] -- _ _ _ _ -- ___ ___ __| | ___ | |__ ___| |_ __ ___ _ __ | |_ _ -- / __/ _ \ / _` |/ _ \ | '_ \ / _ \ | '_ \ / _ \| '_ \| | | | | -- | (_| (_) | (_| | __/ | | | | __/ | |_) | (_) | | | | | |_| | -- \___\___/ \__,_|\___|___|_| |_|\___|_| .__/ \___/|_| |_|_|\__, | -- |_____| |_| |___/ -- -- «code_helponly» (to ".code_helponly") -- (find-blogme3 "sandwiches-defs.lua" "code_helponly2") -- code_helponly = function (head, stem, anchor) _SH[head] = SexpHead { head = head, help = SexpTarget {f="find_intro", stem=stem, anchor=anchor}, f = function (sh, si) si:add_filling(1, nil, "help", sh.help) end, } end code_helponly_line = function (linestr) local si = SexpIntervals.from(linestr) if not si then return end local head = bitrim(si.left) local stem = si.head:match "find%-(.*)%-intro(.*)" local posspec = si:sexp_strarg(2) local anchor = posspec and posspec:match "^(%d[.%d]*)%." code_helponly(head, stem, anchor) end code_helponly_lines = function (bigstr) for _,linestr in ipairs(splitlines(bigstr)) do code_helponly_line(linestr) end end -- «code_helponly-tests» (to ".code_helponly-tests") -- --[==[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "sandwiches.lua" code_helponly_lines [[ eelatex-bounded (find-bounded-intro) eev-bounded (find-bounded-intro) eek (find-eev-quick-intro "3. Elisp hyperlinks") find-efunction (find-eev-quick-intro "3. Elisp hyperlinks") ]] = _SH si = SexpIntervals.from [[ (eek "H e l l o") ]] si:head_apply() = si = si:tosandwich() --]==] -- _ _ _ _ _ _ _ -- | | | | |_ _ __ ___ | (_)_______| | (_)_ __ ___ -- | |_| | __| '_ ` _ \| | |_ / _ \ | | | '_ \ / _ \ -- | _ | |_| | | | | | | |/ / __/ |___| | | | | __/ -- |_| |_|\__|_| |_| |_|_|_/___\___|_____|_|_| |_|\___| -- -- «HtmlizeLine» (to ".HtmlizeLine") -- HtmlizeLine = Class { type = "HtmlizeLine", __index = { left = function (hl, str) return str end, plain = function (hl, str) return str end, href = function (hl, url, text) return format('<a href="%s">%s</a>', url, text) end, be = function (hl, be) local texthtml = hl:plain(be.origtext) local url = be.st and be.st:url() if url then return hl:href(url, texthtml) end return texthtml end, sandwich = function (hl, sand) local bigstr = "" for _,be in ipairs(sand) do bigstr = bigstr..hl:be(be) end return bigstr end, line = function (hl, linestr) local si = SexpIntervals.from(linestr) if not si then return hl:left(linestr) end if not si:head_apply() then return hl:left(linestr) end DBG("s530") local left,right = si.left, si.right local sandwich = si:tosandwich() DBG("s533") local html = hl:left(left) .. hl:sandwich(sandwich) .. right DBG("s535") return html,si end, }, } -- «HtmlizeLine-tests» (to ".HtmlizeLine-tests") --[==[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "sandwiches.lua" code_helponly_lines [[ eev-bounded (find-bounded-intro) eek (find-eev-quick-intro "3. Elisp hyperlinks") ]] hl = HtmlizeLine {} linestr = [[ (eek "H e l l o") ]] html,si = hl:line(linestr) = html = si = si:tosandwich() linestr = [[ (foo) ]] = hl:line(linestr) --]==] -- _ _ -- ___ ___ __| | ___ ___ __| | __ _ _ __ __ _ __ _ -- / __/ _ \ / _` |/ _ \ / __| / _` | / _` | '_ \ / _` |/ _` | -- | (_| (_) | (_| | __/ | (__ | (_| | | (_| | | | | (_| | (_| | -- \___\___/ \__,_|\___|___\___|___\__,_|___\__,_|_| |_|\__, |\__, | -- |_____| |_____| |_____| |___/ |___/ -- -- «code_c_d_angg» (to ".code_c_d_angg") -- code_c_d_angg = function (c, d, ext) local find_c = "find-"..c _SH[find_c] = SexpHead { head = find_c, -- (find-eev-quick-intro "9. Shorter hyperlinks") help = SexpTarget {f="find_intro", stem="eev-quick", anchor="9"}, f = function (sh, si) si:add_filling(1, nil, "help", sh.help) local a, b = si:sexp_strarg(2), si:sexp_strarg(3) if a then local target = SexpTarget {f="find_angg", fname=d..a, anchor=b, ext=ext} si:add_filling("e", nil, "target", target) end end, } end -- «code_c_d_angg-tests» (to ".code_c_d_angg-tests") -- --[==[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "sandwiches.lua" code_c_d_angg("LATEX", "LATEX/") linestr = [[ (find-LATEX "2021haskell.tex" "title") ]] si = SexpIntervals.from(linestr) si:head_apply() = si = si:tosandwich() --]==] -- _ _ _ -- ___ ___ __| | ___ ___ __| | _ __ ___ _ __ ___ ___ | |_ ___ -- / __/ _ \ / _` |/ _ \ / __| / _` | | '__/ _ \ '_ ` _ \ / _ \| __/ _ \ -- | (_| (_) | (_| | __/ | (__ | (_| | | | | __/ | | | | | (_) | || __/ -- \___\___/ \__,_|\___|___\___|___\__,_|___|_| \___|_| |_| |_|\___/ \__\___| -- |_____| |_____| |_____| -- -- «code_c_d_remote» (to ".code_c_d_remote") -- code_c_d_remote = function (c, baseurl) local find_c = "find-"..c _SH[find_c] = SexpHead { head = find_c, -- (find-eev-quick-intro "9. Shorter hyperlinks") help = SexpTarget {f="find_intro", stem="eev-quick", anchor="3"}, f = function (sh, si) si:add_filling(1, nil, "help", sh.help) local a = si:sexp_strarg(2) if a then local target = SexpTarget {f="find_remote", baseurl=baseurl, rest=a} local shrink = (a == "") and 0 or 1 si:add_filling(2, shrink, "target", target) end end, } end -- «code_c_d_remote-tests» (to ".code_c_d_remote-tests") -- --[==[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "sandwiches.lua" code_c_d_remote("lua51manual", "http://www.lua.org/manual/5.1/manual.html") linestr = [[ (find-lua51manual "" "title") ]] linestr = [[ (find-lua51manual "#2.1" "title") ]] si = SexpIntervals.from(linestr) si:head_apply() = si = si:tosandwich() --]==] -- _ _ _ -- ___ ___ __| | ___ (_)_ __ | |_ _ __ ___ -- / __/ _ \ / _` |/ _ \ | | '_ \| __| '__/ _ \ -- | (_| (_) | (_| | __/ | | | | | |_| | | (_) | -- \___\___/ \__,_|\___|___|_|_| |_|\__|_| \___/ -- |_____| -- -- «code_intro» (to ".code_intro") -- code_intro = function (stem) local find_stem_intro = "find-"..stem.."-intro" _SH[find_stem_intro] = SexpHead { head = find_stem_intro, help = SexpTarget {f="find_intro", stem=stem, anchor=nil}, f = function (sh, si) si:add_filling(1, nil, "help", sh.help) local a = si:sexp_strarg(2) local anchor = a and a:match("^(%d[.%d]*)%.") local target = anchor and SexpTarget {f="find_intro", stem=stem, anchor=anchor} si:add_filling("e", nil, "target", target or sh.help) end, } end -- «code_intro-tests» (to ".code_intro-tests") -- --[==[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "sandwiches.lua" code_intro("foobar") linestr = [[ (find-foobar-intro "42.3. plic") ]] si = SexpIntervals.from(linestr) si:head_apply() = si = si:tosandwich() --]==] -- _ _ -- ___ ___ __| | ___ ___ _ __ ___ | |__ -- / __/ _ \ / _` |/ _ \ / __| | '_ ` _ \ | '_ \ -- | (_| (_) | (_| | __/ | (__ | | | | | | | |_) | -- \___\___/ \__,_|\___|___\___|___|_| |_| |_|___|_.__/ -- |_____| |_____| |_____| -- -- «code_c_m_b» (to ".code_c_m_b") -- Skel: (find-sandwiches-def-links "find-enode") -- code_c_m_b_f = function (sh, si) si:add_filling(1, nil, "help", sh.help) local a = si:sexp_strarg(2) if not a then return end local target = SexpTarget {f="find_node", manual=manual, node=a} if target then si:add_filling("e", nil, "target", target) end end code_c_m_b = function (c, manual, basedir) infomanual_basedir[manual] = basedir local find_cnode = "find-"..c.."node" _SH[find_cnode] = SexpHead { head = find_cnode, -- (find-eev-quick-intro "9.2. Extra arguments to `code-c-d'") help = SexpTarget {f="find_intro", stem="eev-quick", anchor="9.2"}, f = code_c_m_b_f, f = function (sh, si) si:add_filling(1, nil, "help", sh.help) local a = si:sexp_strarg(2) if not a then return end local target = SexpTarget {f="find_node", manual=manual, node=a} if target then si:add_filling("e", nil, "target", target) end end, } end -- «code_c_m_b-tests» (to ".code_c_m_b-tests") -- --[==[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "sandwiches.lua" dofile "cruft-jan2024.lua" -- (find-blogme3file "cruft-jan2024.lua") code_c_m_b("e", "emacs", "http://www.gnu.org/software/emacs/manual/html_node/emacs/") linestr = [[ (find-enode "Keys") ]] si = SexpIntervals.from(linestr) si:head_apply() = si = si:tosandwich() -- Not working yet: = sexp_to_target_si [[ (find-enode "37675653 202207 1" "structural") ]] = sexp_to_target_st [[ (find-enode "37675653 202207 1" "structural") ]] --]==] -- _ _ _ -- ___ ___ __| | ___ _ _ ___ _ _| |_ _ _| |__ ___ -- / __/ _ \ / _` |/ _ \ | | | |/ _ \| | | | __| | | | '_ \ / _ \ -- | (_| (_) | (_| | __/ | |_| | (_) | |_| | |_| |_| | |_) | __/ -- \___\___/ \__,_|\___|____\__, |\___/ \__,_|\__|\__,_|_.__/ \___| -- |_____|___/ -- -- «code_youtube» (to ".code_youtube") -- code_youtube = function (c, hash) local find_c = "find-"..c _SH[find_c] = SexpHead { head = find_c, -- (find-audiovideo-intro "4. Short hyperlinks to audio and video files") help = SexpTarget {f="find_intro", stem="audiovideo", anchor="4"}, f = function (sh, si) si:add_filling(1, nil, "help", sh.help) local time = si:sexp_strarg(2) if time then local target = SexpTarget {f="find_youtube", hash=hash, time=time} si:add_filling(2, 1, "target", target) end end, } end -- «code_youtube-tests» (to ".code_youtube-tests") -- --[==[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "sandwiches.lua" code_youtube("eev2019video", "86yiRG8YJD0") linestr = [[ (find-eev2019video "15:56") ]] si = SexpIntervals.from(linestr) si:head_apply() = si = si:tosandwich() --]==]