|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- This file:
-- http://anggtwu.net/blogme3/cruft-jan2024.lua.html
-- http://anggtwu.net/blogme3/cruft-jan2024.lua
-- (find-angg "blogme3/cruft-jan2024.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
--
-- (defun e () (interactive) (find-angg "blogme3/cruft-jan2024.lua"))
-- Code removed from ~/LUA/lua50init.lua in 2024jan23.
-- See: (find-angg "LUA/lua50init.lua" ".EevIntro")
-- (find-blogme3 "anggdefs.lua" "cruft-jan2024")
-- (find-blogme3 "angglisp.lua" "cruft-jan2024")
-- «.EevIntro» (to "EevIntro")
-- «.youtube_make_url» (to "youtube_make_url")
-- «.youtube_split» (to "youtube_split")
-- «.getsexp» (to "getsexp")
-- «.ELispHF» (to "ELispHF")
-- «.SexpSkel» (to "SexpSkel")
-- «.ELispH» (to "ELispH")
-- «.Sexp» (to "Sexp")
-- «.to_youtube_hash» (to "to_youtube_hash")
-- Commented out:
---------- «.cruft-begins» (to "cruft-begins")
-- «.url_split» (to "url_split")
-- «.Blogme» (to "Blogme")
-- «.code_video» (to "code_video")
-- «.ELispInfo» (to "ELispInfo")
-- «.getsexpskel» (to "getsexpskel")
-- «.SexpLine» (to "SexpLine")
-- --------«.cruft-ends» (to "cruft-ends")
-- «EevIntro» (to ".EevIntro")
-- (find-es "lua5" "EevIntro")
-- Superseded by sandwiches:
-- (find-blogme3file "sandwiches.lua")
-- TODO: check which .blogme files still use this.
--
EevIntro = Class {
type = "EevIntro",
from = function (stem, sec)
return EevIntro {stem=stem, sec=sec}
end,
fromshort = function (short)
if short:match"#"
then return EevIntro.from(short:match"^(.-)#(.*)")
else return EevIntro.from(short)
end
end,
fromheadposspec = function (head, posspec)
local stem = head:match "^find%-(.*)%-intro$"
local sec = posspec and posspec:match "^(%d[%d%.]*)%. "
return EevIntro.from(stem, sec)
end,
fromsexp = function (li)
local head, rest = li:match "^%s*%(([!-~]+)(.*)%)%s*$"
local posspec = rest:match "^%s+\"(.*)\"$"
return EevIntro.fromheadposspec(head, posspec)
end,
__tostring = function (ei) return mytostring(ei) end,
__index = {
url = function (ei)
return format("eev-intros/find-%s-intro.html%s",
ei.stem, ei.sec and "#"..ei.sec or "")
end,
short = function (ei)
return ei.stem .. (ei.sec and "#"..ei.sec or "")
end,
},
}
introhtml = function (stem, sec)
return EevIntro.from(stem, sec):url()
end
-- «youtube_make_url» (to ".youtube_make_url")
-- (find-es "youtube" "time-syntax")
youtube_make_url = function (hash, time)
return "http://www.youtube.com/watch?v=" .. hash .. youtube_time(time)
end
youtube_time = function (time)
if type(time) ~= "string" then return "" end
local mm,ss = time:match("^(%d?%d):(%d%d)$")
if ss then return "&t="..(mm*60+ss) end
local hh,mm,ss = time:match("^(%d?%d):(%d%d):(%d%d)$")
if ss then return "&t="..(hh*3600+mm*60+ss) end
return ""
end
youtube_time_hhmmss = function (time)
if type(time) ~= "string" then return "" end
local mm,ss = time:match("^(%d?%d):(%d%d)$")
if ss then return format("&t=%sm%ss", mm, ss) end
local hh,mm,ss = time:match("^(%d?%d):(%d%d):(%d%d)$")
if ss then return format("&t=%sh%sm%ss", hh, mm, ss) end
return ""
end
-- «youtube_split» (to ".youtube_split")
-- I was using this at too many places - including one-shot programs...
-- (find-angg "LUA/youtube-tags.lua")
-- (find-angg "LUA/youtube.lua")
-- (find-blogme3 "youtube.lua")
youtube_split_url0 = function (li)
local a, url, b, title, c = li:match "^(.-)(https?://%S*)(%s*)(.-)(%s*)$"
if not url then return end
local hash, time
for key,value in url:gmatch "[?&](%w*)=([^?&#'()]*)" do
if key == "v" then hash = value end
if key == "t" then time = value end -- not being used now
end
if not hash then return end
return a, hash, b, title, c
end
youtube_split_url = function (li)
local a, hash, b, title, c = youtube_split_url0(li)
if a then return hash, youtube_make_url(hash), title end
end
-- «getsexp» (to ".getsexp")
-- Superseded by sandwiches:
-- (find-blogme3file "sandwiches.lua")
-- TODO: check which .blogme files still use this.
--
-- New version: (find-angg "LUA/SexpAtEol1.lua" "SexpAtEol-tests")
-- (find-es "lua5" "getsexp")
-- (find-blogme3 "sexp.lua" "getsexp")
-- Version: 2019jan08.
-- A low-level function that splits a line into a sexp, a skel, and other stuff.
-- If str = 'Hello (find-xpdfpage "~/LATEX/foo.pdf" (+ 2 3))'
-- then sexp = '(find-xpdfpage "~/LATEX/foo.pdf" (+ 2 3))',
-- skel = '(find-xpdfpage "_______________" (_____))',
-- head = 'find-xpdfpage',
-- left = 'Hello '.
getsexp = function (str)
if str:sub(-1) ~= ")" then return end
local rep = string.rep
local simpq = function (s) return '"'..rep("_", #s-2)..'"' end -- simplify '"'s
local simpp = function (s) return '('..rep("_", #s-2)..')' end -- simplify parens
local leks = str:gsub("\\.", "__"):reverse():gsub('"[^"]*"', simpq):match("^%b)(")
if not leks then return end
local skel = leks:reverse()
local sexp = str:sub(-#skel)
local head = sexp:match("^%(([^ ()\"]+)")
local skel = "(" .. skel:sub(2):gsub("%b()", simpp)
local left = str:sub(1, -1-#skel)
return sexp, head, skel, left
end
-- «ELispHF» (to ".ELispHF")
-- Superseded by sandwiches:
-- (find-blogme3file "sandwiches.lua")
-- TODO: check which .blogme files still use this.
--
-- (find-es "lua5" "ELispHF")
-- (find-es "lua5" "ELispHF-tests")
-- An ELispHF object holds an "elisp hyperlink function", that when
-- called produces an ElispH object.
--
ELispHF = Class {
type = "ELispHF",
newangg = function (head, d, suffix)
return ELispHF {head=head, d=d, suffix=suffix, f="angg"}
end,
newintro = function (head)
return ELispHF {head=head, f="intro"}
end,
newnode = function (head, c, manual)
return ELispHF {head=head, c=c, manual=manual, f="node"}
end,
newyoutube = function (head, hash)
return ELispHF {head=head, hash=hash, f="youtube"}
end,
__tostring = function (ehf) return mytabletostring(ehf) end,
__call = function (ehf, ...) return ehf[ehf.f](ehf, ...) end,
__index = {
angg = function (ehf, a, b, c)
local target = suffixing(ehf.d..(a or ""), ehf.suffix, b)
return ELispH {intro="eev-quick#9", target=target}
end,
intro = function (ehf, a)
local ei = EevIntro.fromheadposspec(ehf.head, a)
return ELispH {intro=ei.stem, target=ei:url()}
-- return ELispH {intro=ei:short(), target=ei:url()}
end,
node = function (ehf, a)
local manual, section = ehf.manual, a
local target = ELispInfo{}:mstohtml(manual, section)
return ELispH {intro="eev-quick#9.2", target=target}
end,
youtube = function (ehf, a)
local hash, time = ehf.hash, a
local target = youtube_make_url(hash, time)
return ELispH {intro="audiovideo#4.3", target=target}
end,
codevideo = function (ehf, c, urlorfnameorhash)
if c and urlorfnameorhash then code_video(c, urlorfnameorhash) end
return ELispH {intro="audiovideo#4.3"}
end,
},
}
_EHF = VerticalTable {}
-- «SexpSkel» (to ".SexpSkel")
-- (find-es "lua5" "SexpSkel")
-- (find-es "lua5" "SexpSkel-test")
-- A user-friendly class based on getsexp with a nice printing function.
SexpSkel = Class {
type = "SexpSkel",
fromline = function (line)
local str,right = line:match("^(.-%))([%s]*)$")
if not str then return SexpSkel {line=line} end
local sexp,head,skel,left = getsexp(str)
if not sexp then return SexpSkel {line=line} end
return SexpSkel {line=line, left=left, sexp=sexp, right=right,
skel=skel, head=head}
end,
__tostring = function (ss)
if not ss.sexp then return ss.line.."\n[no sexp]" end
local spacify = function (s, c) return string.rep(c or " ", #s) end
local left0 = spacify(ss.left)
local right0 = spacify(ss.right, ".")
return ss.line .."\n"..
left0..ss.sexp..right0 .."\n"..
left0..ss.skel .."\n"..
left0.." "..ss.head
end,
__index = {
splitsexp = function (ss)
local sexpmid = ss.sexp:sub(2, -2) -- without the '(' and the ')'
local skelmid = ss.skel:sub(2, -2) -- without the '(' and the ')'
local A = {}
local f = function (p0, p1) -- positions from skelmid
table.insert(A, sexpmid:sub(p0, p1-1)) -- substring from sexpmid
-- PP(sexpmid:sub(p0, p1-1), skelmid:sub(p0, p1-1))
end
skelmid:gsub("()[^%s]+()", f)
return A
end,
parsestrargs = function (ss)
local A = ss:splitsexp()
local f = function (str) return str and str:match("^\"(.*)\"$") end
return f(A[2]), f(A[3]), f(A[4])
end,
parseq = function (ss)
local headpat = "("..string.rep(".", #ss.head)..")"
local qppat = "(\"?%))" -- optional last quote, closing parenthesis
local a,head,b,qp = ss.sexp:match("^(.)"..headpat.."(.-)"..qppat.."$")
-- print(table.concat({a,head,b,qp}, "|"))
return a,head,b,qp
end,
--
-- (find-es "lua5" "SexpSkel")
-- Interface with ELispH and ELispHF:
ehtosexphtml = function (ss, eh, hzer)
return eh:sexphtml(hzer, ss:parseq())
end,
ehftoeh = function (ss, ehf)
return ehf(ss:parsestrargs()) end,
toehf = function (ss)
return _EHF[ss.head] end,
toeh = function (ss)
local ehf = ss:toehf(); return ehf and ss:ehftoeh(ehf)
end,
totarget = function (ss)
local eh = ss:toeh(); return eh and eh:gettarget()
end,
tohelp = function (ss)
local eh = ss:toeh(); return eh and eh:gethelp()
end,
tosexphtml = function (ss, hzer)
local eh = ss:toeh(); return eh and ss:ehtosexphtml(eh, hzer)
end,
},
}
-- «ELispH» (to ".ELispH")
-- Superseded by sandwiches:
-- (find-blogme3file "sandwiches.lua")
-- TODO: check which .blogme files still use this.
--
-- See: (find-es "lua5" "ELispH")
-- (find-es "lua5" "ELispH-tests")
-- An ELispH object holds data that can generate a "help url" and
-- a "target url". For example:
--
-- eh = ELispH({intro="eev-quick", target="index.html", anchor="eev"})
-- eh:gethelp() --> "eev-intros/find-eev-quick-intro.html"
-- eh:gettarget() --> "index.html#eev"
--
-- The :sexphtml(...) method connects this to SexpSkel.
--
ELispH = Class {
type = "ELispH",
__tostring = function (eh) return mytabletostring(eh) end,
__index = {
gethelp = function (eh)
if eh.intro then
local stem,section = eh.intro:match("^(.-)#(.*)")
if section then return introhtml(stem, section) end
return introhtml(eh.intro)
end
return eh.help
end,
gettarget = function (eh)
return eh.target and (eh.target .. (eh.anchor and "#"..eh.anchor or ""))
end,
sexphtml = function (eh, hzer, a, head, b, qp)
hzer = hzer or id
local help = eh:gethelp()
local target = eh:gettarget()
return hzer(a) .. HREF1(help, hzer(head)) ..
hzer(b) .. HREF1(target, hzer(qp))
end,
--
test = function (eh)
local outt = {help=eh:gethelp(), target=eh:gettarget()}
return tostring(eh) .. " ->\n" .. mytabletostring(outt)
end,
},
}
elispSPECIAL = {}
-- «Sexp» (to ".Sexp")
-- Used here: (find-blogme3 "anggdefs.lua" "Sexp")
elisp = {}
elisp["find-angg"] = meta_find_angg("")
elisp["find-es"] = meta_find_angg("e/", ".e.html")
Sexp = Class {
type = "Sexp",
__index = {
getsexp = function (sexp)
local line = sexp.line
if line:sub(#line) ~= ")" then return end
local len = #line
local skel = line:gsub("\\.", "__") -- backslash+c -> __
skel = skel:revgsub("\"[^\"]*\"", underlinify) -- "abc" -> "___"
skel = skel:sub(1, len-1):revgsub("%b)(", underlinify)..skel:sub(len)
local revsexp = line:reverse():match("^%b)(")
if not revsexp then return end
sexp.sexp = revsexp:reverse()
sexp.pre = line:sub(1, len-#sexp.sexp)
-- sexp.sexpskel = skel:sub(#sexp.pre+1)
sexp.midskel = skel:sub(#sexp.pre+2, len-1)
sexp.head = sexp.midskel:match("^%S*")
return sexp.head
end,
getsexpargs = function (sexp)
local n = 0
sexp.ranges = {}
for i,j in sexp.midskel:gmatch("()%S+()") do
n = n + 1
sexp[n] = sexp.sexp:sub(i+1, j)
sexp.ranges[n] = {i+1, j+1}
end
end,
string = function (sexp, n)
return sexp[n] and sexp[n]:match '^"(.*)"$'
end,
--
Q = function (text) return text end,
hrefto = function (sexp, url)
return function (text)
return '<a href="'..url..'">'..sexp.Q(text)..'</a>'
end
end,
setrange = function (sexp, a, b, s_or_f)
table.insert(sexp.htmlranges, {a, b, s_or_f})
end,
sethelp = function (sexp, url)
local r = sexp.ranges[1]
if url then sexp:setrange(r[1], r[2], sexp:hrefto(url)) end
-- table.insert(sexp.htmlranges, {r[1], r[2], sexp:hrefto(url)})
-- end
end,
settarget = function (sexp, url)
local len = #sexp.sexp
if url then sexp:setrange(len-1, len+1, sexp:hrefto(url)) end
-- table.insert(sexp.htmlranges, {len-1, len+1, sexp:hrefto(url)})
-- end
end,
tohtml0 = function (sexp)
return replaceranges(sexp.sexp, sexp.htmlranges or {}, sexp.Q)
end,
getsexphtml = function (sexp)
sexp.htmlranges = {}
if not sexp.head then return end
if elispSPECIAL[sexp.head] then -- for all kinds of special hacks
elispSPECIAL[sexp.head](sexp)
return
end
local find_aaa = elisp[sexp.head]
if not find_aaa then return end
sexp:getsexpargs()
sexp.target, sexp.help = find_aaa(sexp:string(2), sexp:string(3))
sexp:sethelp(sexp.help)
sexp:settarget(sexp.target)
sexp.sexphtml = sexp:tohtml0()
end,
getlinehtml = function (sexp)
if sexp:getsexp() then sexp:getsexphtml() end
if sexp.sexphtml
then sexp.linehtml = sexp.Q(sexp.pre)..sexp.sexphtml
else sexp.linehtml = sexp.Q(sexp.line)
end
return sexp.linehtml
end,
},
}
-- (find-blogme3 "anggdefs.lua" "basic-words-for-html" "HREF")
HREF = function (url, str) return format('<a href="%s">%s</a>', url, str) end
HREF1 = function (url, str) return url and HREF(url, str) or str end
-- «to_youtube_hash» (to ".to_youtube_hash")
to_youtube_hash = function (str)
str = str:gsub("%.%w%w%w$", "")
str = str:sub(-11)
return str
end
-- «url_split» (to ".url_split")
-- Used here: (find-angg "LUA/redirect.lua")
url_percent_decode = function (str)
local f = function (hh) return string.char(tonumber(hh, 16)) end
return (str:gsub("%%(%x%x)", f))
end
url_query_split = function (query)
local Q = {}
for key,value in query:gmatch "[?&](%w*)=([^?&#'()]*)" do
Q[key] = url_percent_decode(value)
end
return Q
end
--
url_split_re = nil
url_split_re0 = function ()
userocks()
require "re" -- (find-es "lua5" "lpeg-re")
return re.compile [=[
{| {:scheme: [a-z]+ :} "://"
{:host: [^/]+ :}
( "/" {:path: [^?#]* :} ) ?
( "?" {:query: [^#]* :} ) ?
( "#" {:anchor: [^#]* :} ) ?
|}
]=]
end
url_split = function (url)
url_split_re = url_split_re or url_split_re0()
local parts = url_split_re:match(url)
if parts and parts.query then parts.q = url_query_split("?" .. parts.query) end
return parts
end
------------------------------------------------------------
-- «cruft-begins» (to ".cruft-begins")
--[====[
-- «Blogme» (to ".Blogme")
-- Deleted! Superseded by: (find-anggfile "LUA/BlogMe3.lua")
code_c_d_angg = function (c, d, suffix)
local find_c = "find-"..c
local find_cfile = "find-"..c.."file"
_EHF[find_c ] = ELispHF.newangg(find_c, d, suffix or ".html")
_EHF[find_cfile] = ELispHF.newangg(find_c, d, ".html")
end
-- (find-blogme3 "angglisp.lua" "code_c_m_b_s")
-- (find-angg "LUA/lua50init.lua" "ELispHF")
-- (find-es "blogme" "code_c_m_b")
infomanual_basedir = VerticalTable {}
code_c_m_b = function (c, manual, basedir)
infomanual_basedir[manual] = basedir
local find_cnode = "find-"..c.."node"
_EHF[find_cnode] = ELispHF.newnode(find_cnode, c, manual)
end
-- «code_video» (to ".code_video")
-- Superseded by sandwiches:
-- (find-blogme3file "sandwiches.lua")
-- TODO: check which .blogme files still use this.
--
-- Run this to make blogme3 process `(code-video "c" "fname")' sexps:
-- _EHF["code-video"] = ELispHF {f="codevideo"}
--
code_video = function (c, urlorfnameorhash)
local find_c = "find-"..c
local hash = to_youtube_hash(urlorfnameorhash)
_EHF[find_c] = ELispHF.newyoutube(find_c, hash)
end
-- «ELispInfo» (to ".ELispInfo")
-- (find-es "lua5" "ELispInfo")
-- (find-blogme3 "sexp.lua" "find-xxxnodes")
-- Superseded by sandwiches:
-- (find-blogme3file "sandwiches.lua")
-- TODO: check which .blogme files still use this.
--
ELispInfo = Class {
type = "ELispInfo",
new = function (c, manual, basedir)
infomanual_basedir[manual] = basedir
return ELispInfo {c=c, manual=manual}
end,
__index = {
-- convert [s]ection name to [h]tml
shre = "([-'/ &])",
shtable = {["-"] = "_002d", ["'"] = "_0027", ["/"] = "_002f",
[" "] = "-", ["&"] = "-"},
shexpand = function (eli, section)
return section:gsub("%s+", " "):gsub(eli.shre, eli.shtable)
end,
--
-- convert a pair (manual, section) to html
mstohtml = function (eli, manual, section)
if not manual or not section then return end
local basedir = infomanual_basedir[manual]
if not basedir then return end
local sectionh = eli:shexpand(section)
return basedir..sectionh..".html"
end,
-- a "nodename" is a string like "(libc)I/O Overview"
nodenametohtml = function (eli, nodename)
if not nodename then return end
local manual, section = string.match(nodename, "^%(([^()]+)%)(.*)$")
return eli:mstohtml(manual, section)
end,
--
-- -- convert a section name to html
-- stohtml = function (eli, section)
-- return eli:mstohtml(eli.manual, section)
-- end,
-- -- convert a (manual, section) pair or a section to an ELispH
-- mstoeh = function (eli, manual, section)
-- return ELispH {intro="eev-quick#3", target=eli:mstohtml(manual, section)}
-- end,
-- stoeh = function (eli, section)
-- return ELispH {intro="eev-quick#9.2", target=eli:stohtml(section)}
-- end,
--
},
}
-- _E = {}
-- _E["to"] = ElispHF {intro="anchors", calctarget=calctarget_to}
-- _E["find-angg"] = ElispHF {intro="anchors", d=""}
-- «getsexpskel» (to ".getsexpskel")
-- Olbsolete.
-- Algorithm and tests: (find-es "lua5" "getsexpskel")
--
-- getsexpskel = function (str)
-- if str:sub(-1) ~= ")" then return end
-- local f = function (s) return '"'..string.rep("_", #s-2)..'"' end
-- local g = function (s) return ')'..string.rep("_", #s-2)..'(' end
-- local str2 = str:gsub("\\.", "__") -- backslash+c -> __
-- local str3 = str2:reverse()
-- local str4 = str3:gsub('"[^"]*"', f)
-- local skel1 = str4:match("%b)("); if not skel1 then return end
-- local skel2 = skel1:sub(2, -2):gsub("%b)(", g)
-- local skel3 = skel2:reverse()
-- return skel3
-- end
-- «SexpLine» (to ".SexpLine")
-- Obsolete. See: (find-es "lua5" "SexpLine")
-- This was intended to replace some parts of: (find-blogme3 "escripts.lua")
--
-- SexpLine = Class {
-- type = "SexpLine",
-- from = function (src)
-- return SexpLine {src=src, skel=getsexpskel(src)}
-- end,
-- __tostring = function (sl) return mytabletostring(sl) end,
-- __index = {
-- skelf = function (sl) return sl.skel:match"^(%S+)" end,
-- split = function (sl)
-- local f = sl:skelf()
-- local len = #sl.src
-- local lensexp = #sl.skel + 2
-- local lena = len - lensexp
-- local lenb = 1
-- local lenc = #f
-- local lene = (sl.src:sub(-2, -2) == "\"") and 2 or 1
-- local lend = len - lena - lenb - lenc - lene
-- sl.a = sl.src:sub(1, lena)
-- sl.b = "("
-- sl.c = f
-- sl.d = sl.src:sub(lena + lenb + lenc + 1, lena + lenb + lenc + lend)
-- sl.e = sl.src:sub(-lene)
-- local p1, p2 = sl.skel:match"^%S+%s+()%S+()"
-- if p1 then
-- local offset = lena + 1
-- sl.arg1 = sl.src:sub(offset + p1, offset + p2):match"^\"(.*)\"$"
-- end
-- return sl
-- end,
-- splitt = function (sl) -- for tests
-- return sl.a.."|"..sl.b.."|"..sl.c.."|"..sl.d.."|"..sl.e
-- end,
-- splitsexp = function (sl)
-- sl.nth = {}
-- for p1,p2 in sl.skel:gmatch("()%S+()") do
-- local b, e = #sl.a + 1 + p1, #sl.a + p2
-- local raw = sl.src:sub(b, e)
-- local str = raw:match"^\"(.*)\"$"
-- table.insert(sl.nth, {b=b, e=e, raw=raw, str=str})
-- end
-- return sl
-- end,
-- n = function (sl) return #sl.nth end,
-- rawarg = function (sl, n) return (sl.nth[n] or {}).raw end,
-- arg = function (sl, n) return (sl.nth[n] or {}).str end,
-- --
-- q = function (sl, body) return body end,
-- r = function (sl, url, body)
-- return url and format('<a href="%s">%s</a>', url, body) or body
-- end,
-- sethtml = function (sl)
-- sl.f = sl.skel and sl:skelf()
-- sl.ef = sl.f and _E[sl.f]
-- if not sl.ef then
-- sl.html = sl:q(sl.src)
-- else
-- sl:split()
-- sl:splitsexp()
-- sl.help = sl.ef:calchelp()
-- sl.target = sl.ef:calctarget(sl:arg(2), sl:arg(3))
-- sl.sexphtml = sl.b..
-- sl:r(sl.help, sl.c)..
-- sl:q(sl.d)..
-- sl:r(sl.target, sl.e)
-- sl.html = sl:q(sl.a) .. sl.sexphtml
-- end
-- return sl
-- end,
-- },
-- }
--]====]
-- «cruft-ends» (to ".cruft-ends")
-- Local Variables:
-- coding: utf-8-unix
-- End: