Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
-- -*- coding: raw-text-unix -*-
-- elisp.lua - convert elisp hyperlinks (in e-scripts) to html.
-- This is part of blogme3.
--
-- The ascii files at http://anggtwu.net/ are all e-scripts
-- (see <http://anggtwu.net/eev-article.html#e-scripts>); the code in
-- blogme3 that converts them to HTML is spread over three files:
--     (find-blogme3 "escripts.lua")
--     (find-blogme3 "elisp.lua")
--     (find-blogme3 "angglisp.lua")
-- and this one is the second of them. The files escripts.lua and
-- elisp.lua can be loaded independently of one another, and
-- escripts.lua needs lpeg; because of this I'm currently making
-- blogme3.lua always load elisp.lua, even though I'm not using its
-- functions elsewhere... At some point I will clean this.
--
-- Author: Eduardo Ochs <[email protected]>
-- Version: 2014jan24
-- <http://anggtwu.net/blogme3/elisp.lua>
-- <http://anggtwu.net/blogme3/elisp.lua.html>
-- License: GPL.

-- (find-es "lua5" "sheadsymbol-roberto")
-- (find-angg "LUA/lua50init.lua")
-- (find-angg "LUA/lua50init.lua" "loadlpeg")
-- (find-lpegw3m "doc.html" "function anywhere (p)")
-- (find-blogmefile "blogme2-outer.lua" "entities and quoting (Q)")

-- (find-anggfile "TH/Generate")
-- (find-anggfile "TH/Generate" "txt2html")

-- Quick index:
-- «.tools»		(to "tools")
-- «.makesexphtml»	(to "makesexphtml")
-- «.maketarget»	(to "maketarget")
-- «.relative-links»	(to "relative-links")
-- «._E»		(to "_E")
-- «._E_intro»		(to "_E_intro")
-- «.Tgt»		(to "Tgt")
-- «.TGT»		(to "TGT")
-- «.set_E4»		(to "set_E4")
-- «.set_EHELP»		(to "set_EHELP")
-- «.code_c_d_local»	(to "code_c_d_local")
-- «.code_c_d_remote»	(to "code_c_d_remote")
-- «._E4s_as_lua»	(to "_E4s_as_lua")




--------[ Some tools ]--------
-- «tools»  (to ".tools")

null    = function (obj) return obj == nil or obj == "" end
isdir   = function (str) return str == "" or string.sub(str, -1, -1) == "/" end
-- dequote = function (sstr) return sstr and string.sub(sstr, 2, -2) end
dequote    = function (qstr) return qstr and qstr:match "^\"(.*)\"$" end
href = function (target, text)
    if target then return format("<a href=\"%s\">%s</a>", target, text) end
    return text     -- if target is nil then return text unchanged, not an href
  end

--------[ makesexphtml ]--------
-- «makesexphtml»  (to ".makesexphtml")
-- Sexp hyperlinks are usually htmlized like this:
--
--   (find-eev "eev-mini.el")
--    \------/             \/
--   this points       this points to
--   to help on        the result of
--   "find-eev"       evaluating the sexp
--
-- The html for them is produced by the function "makesexphtml".
-- It receives four arguments:
--   (name)     (sample value or description)
--    all       [[(find-eev "eev-mini.el")]]
--    funname    "find-eev"
--    help       URL of the help link, or nil
--    target     URL of the "result" link, or nil

makesexphtml = function (all, funname, help, target)
    if all == 1 then return help   end    -- hack, 2007apr20 (unused)
    if all == 2 then return target end    -- hack, 2007apr20 (for Tgt)
    if help then help = pathto(help) end  -- hack, 2019feb20
    local raw0, raw1, raw2, raw3 = "(", funname
    if string.sub(all, -2, -1) == "\")" then
      raw2, raw3 = string.sub(all, 2 + #funname, -3), "\")"
    else
      raw2, raw3 = string.sub(all, 2 + #funname, -2), ")"
    end
    return raw0 .. href(help, raw1) .. Q(raw2) .. href(target, raw3)
  end

--------[ maketarget, makelocaltarget ]--------
-- «maketarget»  (to ".maketarget")
-- "maketarget" and "makelocaltarget" add a suffix (usually ".html")
-- when the base url that they receive is not a directory, and add a
-- "#tag" when their "tag" argument is not nil.

maketarget = function (baseurl, suffix, tag)
    local url = baseurl
    if suffix and not isdir(baseurl) then
      url = url .. suffix
    end
    if not null(tag) then
      url = url .. "#" .. tag
    end
    return url
  end

makelocaltarget = function (base, fname, suffix, tag)
    if fname then return maketarget(pathto(base..fname), suffix, tag) end
  end

--------[ Relative links ]--------
-- «relative-links»  (to ".relative-links")
-- A link from
--   "http://anggtwu.net/foo/bar/plic.html" to
--   "http://anggtwu.net/ploc/bletch.html" should be relative:
--                 "../../ploc/bletch.html".
-- For simplicity, a link from
--   "http://anggtwu.net/foo/bar/plic.html" to
--   "http://anggtwu.net/foo/blop.html" is relativized as
--                 "../../foo/blop.html", not as
--                        "../blop.html".
-- My current convention is that I always run blogme3.lua from the
-- "root of the output tree"; to generate
--     http://anggtwu.net/foo/bar/plic.html
-- I run something like, say,
--     blogme3.lua -o foo/bar/plic.html -i ~/PAGESRC/foo/bar/plic.blogme
-- from the directory "~/PAGE" or "/var/www/"...
-- The function "getpathtoroot" can be used to set pathtoroot from the
-- argument to "-o" - see blogme3.lua.

pathtoroot = ""
pathto = function (path) return pathtoroot .. path end

getpathtoroot = function (path)
    local _, nslashes = string.gsub(path, "/", "/")
    return string.rep("../", nslashes)
  end

--------[ _E_localanchor and friends ]--------
-- «_E»  (to "._E")
-- The functions in the table "_E" have signatures like
-- "all,funname,qarg1,qarg2|->html"; here we define some of these
-- functions, using "makesexphtml" and "maketarget"/"makelocaltarget"
-- to do most of the work. We avoid using closures in _E because the
-- code with them would be a bit harder to debug (and to explain...) -
-- instead we use three extra tables, _EHELP, _EBASE, and _ESUFFIX.
-- The values in _EBASE are interpreted differently by different
-- "_E_kindoflink" functions.
--
-- An example: when I generate the pages at angg I have this:
--   _E      ["find-eev"] = _E_localanchor
--   _EHELP  ["find-eev"] = eevarticle.."#shorter-hyperlinks"
--   _EBASE  ["find-eev"] = "eev-current/"
--   _ESUFFIX["find-eev"] = ".html"
-- and to produce the html for a link like
--
--   (find-eev "eev-mini.el" "ee-code-c-d")
--
-- the function "_E_localanchor" first "dequotes" its arguments qarg1
-- and qarg2 - that are [["eev-mini.el"]] and [["ee-code-c-d"]] - to
-- remove the outer double-quotes from them. The results of the
-- dequoting become the "fname" and the "tag" in the diagram below;
-- they would be nil if the function "dequote" had received arguments
-- that were not double-quoted strings. The values of "help", "base",
-- and "suffix" are obtained from the entries for the funname
-- ("find-eev", in this case) in the tables _EHELP, _EBASE, and
-- _ESUFFIX. The first "}->" with four inputs and one output is
-- "makelocaltarget", the second is "makesexphtml".
--
-- Diagram from "_E_localanchor":
--                                          all     \
--                                          funname |---> sexphtml
--      funname --_HELP-------------------> help    |
--      funname --_EBASE-----> base   \---> target  /
--             \               fname  |
--              --_ESUFFIX---> suffix |
--                             tag    /
--
-- The other "_E_kindoflink" functions are similar, but simpler.

_E       = _E       or {}
_EBASE   = _EBASE   or {}
_ESUFFIX = _ESUFFIX or {}
_EHELP   = _EHELP   or {}

_Es = _Es or {}
-- eevarticle = pathto("eev-article.html")

_E_localanchor = function (all, funname, qfname, qtag)
    local fname, tag = dequote(qfname), dequote(qtag)
    return makesexphtml(all, funname, _EHELP[funname],
        makelocaltarget(_EBASE[funname], fname, _ESUFFIX[funname], tag))
  end

_E_localfile = function (all, funname, qfname)
    local fname = dequote(qfname)
    return makesexphtml(all, funname, _EHELP[funname],
        makelocaltarget(_EBASE[funname], fname, _ESUFFIX[funname]))
  end

_E_remoteanchor = function (all, funname, qfname, qtag)
    local fname, tag = dequote(qfname), dequote(qtag)
    if fname == nil then PP(all, funname, qfname, qtag) end
    return makesexphtml(all, funname, _EHELP[funname],
        maketarget(_EBASE[funname]..fname, _ESUFFIX[funname], tag))
  end

_E_remotefile = function (all, funname, qfname)
    local fname = dequote(qfname)
    return makesexphtml(all, funname, _EHELP[funname],
        maketarget(_EBASE[funname]..fname, _ESUFFIX[funname]))
  end

_E_helponly = function (all, funname)
    return makesexphtml(all, funname, _EHELP[funname], nil)
  end

_E_info = function (all, funname)       -- a stub: info links are not working
    return makesexphtml(all, funname, _EHELP[funname], nil)
  end


-- «_E_intro» (to "._E_intro")
-- Added in 2019feb28
_E_intro = function (all, funname, qarg1, qarg2)
    local intro = "eev-intros/"..funname..".html"
    local posspec = dequote(qarg1)
    local sec = posspec and posspec:match "^(%d[%d%.]*)%. "
    local introsec = sec and intro.."#"..sec or intro
    return makesexphtml(all, funname, introsec, pathto(introsec))
  end


--------[ Tgt ]--------
-- «Tgt»  (to ".Tgt")
-- A hack. An example of usage: this block in blogme,
--   [Tgt find-angg ".zshrc" "an_anchor" etc etc]
-- evaluates to the target link of this sexp:
--   (find-angg ".zshrc" "an_anchor")

_A["Tgt"] = _AA["4"]
_G["Tgt"] = function (funname, qarg1, qarg2, rest)
    if not _E[funname] then error(format("Tgt: not in _E: %q", funname)) end
    return _E[funname](2, funname, qarg1, qarg2) or
           error(format("Tgt: empty target for (%s %s %s)", funname,
                        qarg1 or "nil", qarg2 or "nil"))
  end

-- «TGT»  (to ".TGT")
-- 2007jul24: TGT is more natural to use than Tgt...
-- Example: [TGT (find-enode "M-x")]
def [[ ONESPACE 1  body string.gsub(body, "%s+", " ") ]]
-- def [[ TGT 1 sexp Tgt(string.match(ONESPACE(sexp), "^%(([^%s]+) (.*)%)$")) ]]

-- 2007sep29: (find-es "blogme" "_TARGETS" "SexpLink:match")
-- the definition of TGT above is a hack that will not work always...
-- When we need a "full TGT" we need to replace it like this:
require "escripts"
def [[ TGT 1 sexp Tgt(SexpLink:match(sexp)) ]]

--------[ code_c_d ]--------
-- «set_E4»    (to ".set_E4")
-- «set_EHELP» (to ".set_EHELP")
-- Functions to set many entries in the _Exxx tables at once.
-- The top-level syntax - code_c_d_anchor(c, d) - is similar to the
-- one that I use to define many hyperlink functions at once in elisp.
-- Example:
--   code_c_d_anchor("eev", "eev-current/")
-- works as this:
--   _E      ["find-eev"]     = _E_localanchor
--   _EHELP  ["find-eev"]     = eevarticle.."#anchors"
--   _EBASE  ["find-eev"]     = "eev-current/"
--   _ESUFFIX["find-eev"]     = ".html"
--   _E      ["find-eevfile"] = _E_localfile
--   _EHELP  ["find-eevfile"] = eevarticle.."#long"
--   _EBASE  ["find-eevfile"] = "eev-current/"
--   _ESUFFIX["find-eevfile"] = ""

set_E4 = function (funname, _e, _ehelp, _ebase, _esuffix)
    _E      [funname] = _e
    _EHELP  [funname] = _ehelp
    _EBASE  [funname] = _ebase
    _ESUFFIX[funname] = _esuffix
    table.insert(_Es, funname)
  end

set_EHELP = function (funname, help)    -- set only _E and _EHELP
    set_E4(funname, _E_helponly, help)  -- base and suffix are nil
  end


--------[ code_c_d_local and code_c_d_remote ]--------
-- «code_c_d_local» (to ".code_c_d_local")
-- «code_c_d_remote» (to ".code_c_d_remote")
-- (find-blogme3 "angglisp.lua" "code_c_d_angg")
-- (find-eev-quick-intro "9. Shorter hyperlinks")

code_c_d_local = function (c, d)
    -- local h = eevarticle.."#shorter-hyperlinks"
    -- local h = eevintro "code-c-d"
    local h = "eev-intros/find-eev-quick-intro.html#9"
    set_E4("find-"..c.."file", _E_localfile,   h, d, "")
    set_E4("find-"..c,         _E_localanchor, h, d, ".html")
    set_E4("find-"..c.."w3m",  _E_localfile,   h, d, "")
  end

code_c_d_remote = function (c, d)
    -- local h = eevarticle.."#shorter-hyperlinks"
    -- local h = eevintro "code-c-d"
    local h = "eev-intros/find-eev-quick-intro.html#9"
    set_E4("find-"..c.."file", _E_remotefile,   h, d, "")
    set_E4("find-"..c,         _E_remoteanchor, h, d, ".html")
    set_E4("find-"..c.."w3m",  _E_remotefile,   h, d, "")
  end

--------[ Dump the four _E tables ]--------
-- «_E4s_as_lua»  (to "._E4s_as_lua")
-- (find-blogme3file "definers.lua" "def_as_lua =")

_E4_as_lua = function (funname)
    if not f2n then f2n = preparef2n() end
    local _e       = _E      [funname]
    local _ehelp   = _EHELP  [funname]
    local _ebase   = _EBASE  [funname]
    local _esuffix = _ESUFFIX[funname]
    local _ename   = f2n and f2n[_e] or mytostring(_e)
    return format([[
_E      [%q] = %s
_EHELP  [%q] = %q
_EBASE  [%q] = %q
_ESUFFIX[%q] = %q
]], funname, _ename,
    funname, _ehelp,
    funname, _ebase,
    funname, _esuffix)
  end

_E4s_as_lua = function ()
    return table.concat(map(_E4_as_lua, _Es), "\n")
  end


--------[ Elisp hyperlinks that are not angg-specific ]--------

-- _EHELP["to"] = eevarticle.."#anchors"
-- _E    ["to"] = function (all, funname, qtag)
--     local tag = dequote(qtag)
--     return makesexphtml(all, funname, eevarticle.."#anchors", tag and "#"..tag)
--   end