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: