|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- elisp2.lua - Support for elisp hyperlinks for Blogme4 (rewritten).
-- The function `trisect_and_split' below identifies, extracts and
-- splits the last sexp in a line - the one that M-e would execute as
-- a sexp hyperlink in Emacs, as in:
-- (find-TH "eev-article" "hyperlinks")
-- (find-TH "eev-article" "forward-and-back")
--
-- The algorithm
-- =============
-- The algorithm - in the function `trisect' - works by determining
-- the "skeleton" of a line, in four steps:
--
-- 1) simplify all the backslash-char pairs, replacing each by `__';
-- 2) simplify all the strings, replacing each by `"____"';
-- 3) extract the last sexp, using a balanced parentheses count;
-- 4) simplify its subsexps, replacing each by `(___)'.
--
-- Some of these operations are performed on reversed strings, to let
-- a simple "%b" pattern match the last sexp very quickly. The
-- resulting skeleton has whitespace exactly in the places that
-- separate each element from the next in the top list of the sexp;
-- `trisect_and_split' uses these whitespaces as cues to split the
-- original line at the right places.
--
-- ___ ___ ___
-- / _ \/ _ \ / _ \
-- | __/ (_) | (_) |
-- \___|\___/ \___/
--
-- require "eoo" -- (find-blogme4 "eoo.lua")
-- require "eoo" -- (find-dn5 "eoo.lua")
Class = {
type = "Class",
__call = function (class, o) return setmetatable(o, class) end,
}
setmetatable(Class, Class)
-- ____
-- / ___| _____ ___ __
-- \___ \ / _ \ \/ / '_ \
-- ___) | __/> <| |_) |
-- |____/ \___/_/\_\ .__/
-- |_|
--
-- The "Sexp" class:
-- Low-level class function and object methods
Sexp = Class {
type = "Sexp",
q = function (str) return str end,
href = function (u, t) return u and "(HREF "..u.." "..t..")" or t end,
simp_backslashes = function (s) return s:gsub("\\.", "__") end,
simp_quote = function (s) return '"'..string.rep("_", #s)..'"' end,
simp_quotes = function (s) return s:gsub('"([^"]-)"', Sexp.simp_quote) end,
simp_subsexp = function (subsexp)
return "("..string.rep("_", #subsexp-2)..")"
end,
simp_subsexps = function (sexpskelin)
return sexpskelin:gsub("%b()", Sexp.simp_subsexp)
end,
trisect = function (line)
local revskel = Sexp.simp_quotes(Sexp.simp_backslashes(line):reverse())
local secaps, lekspxes, erp = revskel:match("^([ \t]*)(%b)()(.*)")
if not secaps then return end
local pre = line:sub(1, #erp)
local sexpskel = lekspxes:reverse()
local sexp = line:sub(1+#pre, #pre+#sexpskel)
local spaces = secaps:reverse()
--
local sexp_in = sexp:sub(2, -2)
local sexpskel_in = sexpskel:sub(2, -2)
local sexpskelsimp_in = Sexp.simp_subsexps(sexpskel_in)
local sexpskelsimp = "("..sexpskelsimp_in..")"
local subsexps = {}
for b,e in sexpskelsimp_in:gmatch("()[^ \t]+()[ \t]*") do
table.insert(subsexps, sexp_in:sub(b, e-1))
end
return Sexp {line=line,
l=pre, sexp=sexp, r=spaces,
skel=sexpskel, unpack(subsexps)}
end,
__index = {
strarg = function (sexp, n)
if sexp[n] then return (sexp[n]:match("^\"(.*)\"$")) end
end,
abcd = function (sexp)
sexp.a, sexp.b, sexp.c, sexp.d =
sexp.sexp:match("^(%()([A-Za-z0-9_%-]+)(.-)(\"?%))$")
return sexp
end,
},
}
-- High-level methods and class functions
--
Sexp.__index.sexpurls = function (sexp)
local head = sexp[1]
local stem = sexp:strarg(2)
local anchor = sexp:strarg(3)
local defun = defuns[head]
-- PP(91, defun)
if defun then
sexp.help = defun.help and defun:help() -- a URL
sexp.target = defun.target and defun:f(stem, anchor) -- another URL
-- no overrides yet
end
return sexp
end
Sexp.__index.sexphtml_ = function (sexp, href, q)
href = href or Sexp.href
q = q or Sexp.q
sexp:sexpurls()
if sexp.help or sexp.target then
sexp:abcd()
sexp.sexphtml = sexp.a ..
href(sexp.help, sexp.b) ..
q(sexp.c) ..
href(sexp.target, sexp.d)
end
return sexp
end
Sexp.sexphtml = function (line)
local sexp = Sexp.trisect(line)
return (sexp and sexp:sexphtml_()) or Sexp {line=line}
end
Sexp.__index.linehtml = function (sexp, href, q)
-- PP(117, sexp)
-- PP(118, sexp.sexphtml)
href = href or Sexp.href
q = q or Sexp.q
if sexp.sexphtml then
sexp.linehtml = q(sexp.l)..sexp.sexphtml..q(sexp.r)
else
sexp.linehtml = q(sexp.line)
end
return sexp
end
Sexp.linehtml = function (line)
local sexp = Sexp.sexphtml(line)
-- PP(129, sexp)
return sexp:linehtml().linehtml
end
-- ___
-- / _ \
-- | | | |
-- | |_| |
-- \__\_\
--
-- (find-blogme4 "anggdefs.lua" "Q")
Q_re = "([\001-\008\011-\031&<>\127-\255])"
Q_table = { ["&"]="&", ["<"]="<", [">"]=">" }
Q_table["\15"] = "<font color=\"red\"><strong>*</strong></font>"
Q_table["\171"] = "<font color=\"green\"><i>«</i></font>"
Q_table["\187"] = "<font color=\"green\"><i>»</i></font>"
Sexp.q = function (str) return str:gsub(Q_re, Q_table) end
Sexp.href = function (url, text)
if url
then return "<a href=\""..url.."\">"..Sexp.q(text).."</a>"
else return Sexp.q(text)
end
end
-- _ _
-- | |_ __ _ __ _ __ _(_)_ __ __ _
-- | __/ _` |/ _` |/ _` | | '_ \ / _` |
-- | || (_| | (_| | (_| | | | | | (_| |
-- \__\__,_|\__, |\__, |_|_| |_|\__, |
-- |___/ |___/ |___/
nsexps = 0
sexp_to_tag = {}
tag_to_sexp = {}
tag_to_html = {}
Sexp.__index.taggedline_ = function (s)
if s.sexphtml then
local sexp = s.sexp
local sexphtml = s.sexphtml
local tag = sexp_to_tag[sexp]
if tag then
s.tag = tag -- recycle tag
else
repeat
nsexps = nsexps + 1
tag = "sexp"..nsexps.."_"
until (tag_to_html[tag] == nil)
s.tag = tag
sexp_to_tag[sexp] = tag
tag_to_html[tag] = sexphtml
end
s.taggedline = s.l .. tag .. s.r
else
s.taggedline = s.line
end
return s
end
Sexp.taggedline = function (line)
return Sexp.sexphtml(line):taggedline_().taggedline
end
tag_all_lines = function (bigstr)
return (bigstr:gsub("([^\n]+)", Sexp.taggedline))
end
-- _ _ _ _ _ _ _
-- | |__ (_) __ _| |__ | (_) __ _| |__ | |_
-- | '_ \| |/ _` | '_ \| | |/ _` | '_ \| __|
-- | | | | | (_| | | | | | | (_| | | | | |_
-- |_| |_|_|\__, |_| |_|_|_|\__, |_| |_|\__|
-- |___/ |___/
tmpdir = "/tmp/highlight/"
highlight = function (fname, lang, out)
local bigstr, bigstr2, bigstr3, title, qtitle
local fname_tagged, fname_taggedhtml, fname_html
local cmd
qtitle = "'"..fname.." (htmlized)'"
fname_tagged = tmpdir.."1"
fname_taggedhtml = tmpdir.."1.html"
fname_html = out or tmpdir.."2.html"
bigstr = readfile(fname)
bigstr2 = tag_all_lines(bigstr)
writefile(fname_tagged, bigstr2)
cmd = "highlight -I -S "..lang..
" -T "..qtitle..
" -o "..fname_taggedhtml..
" "..fname_tagged
print(cmd)
print(getoutput(cmd))
bigstr3 = readfile(fname_taggedhtml)
bigstr4 = bigstr3:gsub("(sexp[0-9]+_)", tag_to_html)
writefile(fname_html, bigstr4)
end
ta = function (line) PP(Sexp.sexphtml(line):linehtml()) end
ta = function (line) print(Sexp.linehtml(line)) end
-- inputfname = "lua50init.lua"
--[==[
* (message (find-sh0 "rm -Rv /tmp/highlight/; mkdir /tmp/highlight/"))
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "elisp2.lua"
highlight("../LUA/lua50init.lua", "lua")
# (find-fline "/tmp/highlight/")
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
* (message (find-sh0 "cp -v ~/LUA/lua50init.lua /tmp"))
dofile "elisp2.lua"
bigstr = readfile "/tmp/lua50init.lua"
bigstr2 = tag_all_lines(bigstr)
PP(sexp_to_tag)
PP(tag_to_html)
writefile("/tmp/lua50init_.lua", bigstr2)
-- (find-tkdiff "/tmp/lua50init.lua" "/tmp/lua50init_.lua")
* (message (find-sh0 "highlight -I -o /tmp/lua50init_.lua.html /tmp/lua50init_.lua"))
bigstr3 = readfile "/tmp/lua50init_.lua.html"
bigstr4 = bigstr3:gsub("(sexp[0-9]+_)", tag_to_html)
writefile("/tmp/lua50init.lua.html", bigstr4)
* (message (find-sh0 "rm -Rv /tmp/highlight/; mkdir /tmp/highlight/"))
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "elisp2.lua"
userocks()
chdir "~/eev-current/"
-- PP(getoutput("ls"))
-- PP(getoutput("ls *.el"))
for _,fname in ipairs(split(getoutput("ls *.el"))) do
print(fname)
highlight(fname, "el", "/tmp/highlight/"..fname..".html")
end
-- (find-sh "cd ~/eev-current/; ls *.el")
-- (find-angg "LUA/lua50init.lua" "getoutput")
-- (find-fline "/tmp/")
-- (find-fline "/tmp/highlight/")
# (find-man "1 highlight")
# (find-man "1 highlight" "-T, --doc-title")
# (find-man "1 highlight" "-S, --syntax=<type>")
# (find-man "1 highlight" "-p, --list-langs")
# (find-sh "highlight -p")
# (find-sh "highlight -p" " el ")
ta 'foo (find-dn4 "ab" "cd")'
-- (find-es "highlight" "debian-package")
-- (find-fline "~/LUA/lua50init.lua")
PP(defuns)
PP(defuns["find-dn4"])
PP(defuns["find-dn4"]:f("a", "b"))
PP(sorted(keys(defuns)))
tah "foo"
tah 'foo (find-es "ab" "cd")'
ta2 'foo (find-es "ab" "cd")'
ta2 'foo (find-ep "ab" "cd")'
ta2 'foo (find-angg "ab" "cd")'
--]==]
q = function (str) return str end
qhref = function (u, t) return u and "(HREF "..u.." "..t..")" or t end
-- _ _ _
-- | |_ _ __(_)___ ___ ___| |_
-- | __| '__| / __|/ _ \/ __| __|
-- | |_| | | \__ \ __/ (__| |_
-- \__|_| |_|___/\___|\___|\__|
--
simplify_backslashes = function (s) return s:gsub("\\.", "__") end
simplify_quote_ = function (s) return '"'..string.rep("_", #s)..'"' end
simplify_quotes = function (s) return s:gsub('"([^"]-)"', simplify_quote_) end
simplify_subsexp = function (subsexp)
return "("..string.rep("_", #subsexp-2)..")"
end
simplify_subsexps = function (sexpskelin)
return sexpskelin:gsub("%b()", simplify_subsexp)
end
trisect = function (line)
local revskel = simplify_quotes(simplify_backslashes(line):reverse())
local secaps, lekspxes, erp = revskel:match("^([ \t]*)(%b)()(.*)")
if not secaps then return end
local pre = line:sub(1, #erp)
local sexpskel = lekspxes:reverse()
local sexp = line:sub(1+#pre, #pre+#sexpskel)
local spaces = secaps:reverse()
return pre, sexp, spaces, sexpskel
end
trisect_and_split = function (line)
local pre, sexp, spaces, sexpskel = trisect(line)
if sexp then
local sexp_in = sexp:sub(2, -2)
local sexpskel_in = sexpskel:sub(2, -2)
local sexpskelsimp_in = simplify_subsexps(sexpskel_in)
local sexpskelsimp = "("..sexpskelsimp_in..")"
local subsexps = {}
local capture = function (b, e)
subsexps[#subsexps + 1] = sexp_in:sub(b, e-1)
end
sexpskelsimp_in:gsub("()[^ \t]+()[ \t]*", capture)
-- local ret = {l=pre, s=sexp, r=spaces, unpack(subsexps)}
return pre, sexp, spaces, subsexps, sexpskelsimp
end
end
trisect_and_htmlize_ = function (line)
local pre, sexp, spaces, subsexps, sexpskel = trisect_and_split(line)
local head = pre and subsexps[1]
local defun = head and defuns[head]
local sexphtml = defun and defun:htmlize(sexp, subsexps, sexpskel)
return sexphtml and q(pre)..sexphtml..q(spaces)
end
trisect_and_htmlize = function (line)
return trisect_and_htmlize_(line) or q(line)
end
-- ____ __
-- | _ \ ___ / _|_ _ _ __
-- | | | |/ _ \ |_| | | | '_ \
-- | |_| | __/ _| |_| | | | |
-- |____/ \___|_| \__,_|_| |_|
--
isdir = function (fname) return fname:sub(-1) == "/" or fname == "" end
defuns = {}
Defun = Class {
type = "Defun",
__index = {
target_url = function () end,
help_url = function () end,
f = function (defun, stem, anchor)
return defun:target_url(stem, anchor)
end,
help = function (defun) return defun:help_url() end,
target = function (defun, a, b) return defun:target_url(a, b) end,
htmlize = function (defun, sexp, subsexps, sexpskel)
local a, b, c, d = sexp:match("^(%()([A-Za-z0-9_%-]+)(.-)(\"?%))$")
if not a then return end
local help = defun.help_url
local stem = subsexps[2] and subsexps[2]:match("^\"(.*)\"$")
local anchor = subsexps[3] and subsexps[3]:match("^\"(.*)\"$")
local target = defun:target_url(stem, anchor)
local result = a..qhref(help, b)..q(c)..qhref(target, d)
return result
end,
},
}
help_url_ = function (url) return function () return url end end
target_url_ = function (base, _html)
_html = _html or ".html"
return function (defun, stem, anchor)
if not stem then return nil
elseif isdir(stem) then return base..stem
elseif not anchor then return base..stem.._html
else return base..stem.._html.."#"..anchor
end
end
end
-- _ _
-- ___ ___ __| | ___ ___ __| |
-- / __/ _ \ / _` |/ _ \_____ / __|____ / _` |
-- | (_| (_) | (_| | __/_____| (_|_____| (_| |
-- \___\___/ \__,_|\___| \___| \__,_|
--
eevarticle = "eev-article.html"
pathto = function (d) return d end
code_c_d_angg = function (c, d)
defuns["find-"..c.."file"] = Defun {
help_url = help_url_(eevarticle.."#shorter-hyperlinks"),
target_url = target_url_(pathto(d), ""), --> change to no anchor
}
defuns["find-"..c] = Defun {
help_url = help_url_(eevarticle.."#shorter-hyperlinks"),
target_url = target_url_(pathto(d), ".html"),
}
defuns["find-"..c.."w3m"] = Defun {
help = eevarticle.."#shorter-hyperlinks",
target_url = target_url_(pathto(d), ""), --> change to no anchor
}
end
-- (find-blogme3 "angglisp.lua")
-- (find-blogme4 "angglisp.lua")
code_c_d_angg("angg", "") -- (find-angg "blogme4/")
code_c_d_angg("es", "e/") -- (find-es "lua5")
code_c_d_angg("dednat4", "dednat4/") -- (find-dednat4 "")
code_c_d_angg("dn4", "dednat4/")
code_c_d_angg("dn4ex", "dednat4/examples/")
code_c_d_angg("dn5", "dednat5/")
code_c_d_angg("blogme", "blogme/")
code_c_d_angg("blogme3", "blogme3/")
code_c_d_angg("blogme4", "blogme4/")
code_c_d_angg("eev", "eev-current/")
code_c_d_angg("flua", "flua/")
code_c_d_angg("rubyforth", "rubyforth/")
code_c_d_angg("vtutil", "vtutil/")
code_c_d_angg("vtutil4", "vtutil4/")
code_c_d_angg("RETRO", "RETRO/")
defuns["find-es"].target_url = target_url_(pathto("e/"), ".e.html")
-- _ _
-- | |_ ___ ___| |_ ___
-- | __/ _ \/ __| __/ __|
-- | || __/\__ \ |_\__ \
-- \__\___||___/\__|___/
--
trisect_test = function (li)
local ang = function (s) return "<"..s..">" end
local pre, sexp, spaces, subsexps, sexpskel = trisect_and_split(li)
if sexp then
print(sexp)
print(sexpskel)
print(" "..mapconcat(ang, subsexps, " "))
end
end
trisect_test_file = function (fname)
for li in io.lines(fname) do trisect_test(li) end
end
tah = function (li) print("__", trisect_and_htmlize(li)) end
ta2 = function (li)
local ht = trisect_and_htmlize_(li)
if ht then print(li); print(ht) end
end
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "elisp2.lua"
tah "foo"
tah 'foo (find-es "ab" "cd")'
ta2 'foo (find-es "ab" "cd")'
ta2 'foo (find-ep "ab" "cd")'
ta2 'foo (find-angg "ab" "cd")'
= string.sub("abcd", -1)
= string.sub("", -1)
defuns["find-es"] = Defun {
target_url = function (defun, stem, anchor)
PP("find-es", stem, anchor)
if stem
then if anchor
then return "http://angg.twu.net/e/"..stem..".e.html#"..anchor
else return "http://angg.twu.net/e/"..stem..".e.html"
end
end
end,
}
defuns["find-angg"] = Defun {
help_url = help_url_ "help_angg",
target_url = target_url_ "http://angg.twu.net/",
}
--]]
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "elisp2.lua"
trisect_test_file("/home/edrx/ORG/index.org")
test = trisect_test
test [=[ abcd (foo '(bar plic "foo") "bar") ]=]
test [=[ abcd (foo '(bar plic "foo") "bar") ]=]
--> (foo '(bar plic "foo") "bar") <- sexp
--> (foo '(______________) "___") <- sexp skeleton, simplified
--> <foo> <'(bar plic "foo")> <"bar"> <- its 3 subsexps
--]]
-- Local Variables:
-- coding: raw-text-unix
-- ee-anchor-format: "«%s»"
-- End: