Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
-- This file:
--   http://anggtwu.net/LUA/Show2.lua.html
--   http://anggtwu.net/LUA/Show2.lua
--          (find-angg "LUA/Show2.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
-- Version: 2023nov09
--
-- Based on:
--   (find-angg "LUA/Show1.lua")
--   (find-angg "LUA/Pict2e1.lua" "Show")
--   (find-angg "LUA/tikz1.lua" "Show-class")
--   (find-LATEXfile "2022pict2e-body.tex")
--   (find-LATEXfile "2022pict2e.tex")
-- Used by:
--   (find-angg "LUA/Co1.lua")
--    (find-angg "LUA/Verbatim3.lua")
--    (find-angg "LUA/Und1.lua")
--    (find-angg "LUA/LPex1.lua")
--    (find-angg "LUA/ParseTree1.lua")
--    (find-angg "LUA/Maxima2.lua")
--   (find-angg "LUA/Pict3.lua")
--    (find-angg "LUA/Piecewise2.lua")
--    (find-angg "LUA/Numerozinhos1.lua")
--    (find-angg "LUA/Surface1.lua")
--    (find-angg "LUA/ExprDxDy1.lua")
-- See:
--   (find-angg "LUA/Show2-outer.tex")

-- (defun s1 () (interactive) (find-angg "LUA/Show1.lua"))
-- (defun s2 () (interactive) (find-angg "LUA/Show2.lua"))
--
-- «.introduction»	(to "introduction")
-- «.Dang»		(to "Dang")
-- «.Dang-tests»	(to "Dang-tests")
-- «.TeXSet»		(to "TeXSet")
-- «.TeXSet-tests»	(to "TeXSet-tests")
--   «.defs»		(to "defs")
--   «.defs_repl»	(to "defs_repl")
--   «.usepackages»	(to "usepackages")
-- «.middletexbody»	(to "middletexbody")
-- «.dednat6»		(to "dednat6")
-- «.texbody»		(to "texbody")
-- «.texbody-tests»	(to "texbody-tests")
-- «.Show»		(to "Show")
-- «.Show-tests»	(to "Show-tests")
-- «.StringShow»	(to "StringShow")
-- «.StringShow-tests»	(to "StringShow-tests")



--  ___       _                 _            _   _             
-- |_ _|_ __ | |_ _ __ ___   __| |_   _  ___| |_(_) ___  _ __  
--  | || '_ \| __| '__/ _ \ / _` | | | |/ __| __| |/ _ \| '_ \ 
--  | || | | | |_| | | (_) | (_| | |_| | (__| |_| | (_) | | | |
-- |___|_| |_|\__|_|  \___/ \__,_|\__,_|\___|\__|_|\___/|_| |_|
--                                                             
-- «introduction»  (to ".introduction")
-- In 2022 I found a nice way to edit TikZ code in a REPL. After
-- polishing the first prototype a bit I created this page explaining
-- how it worked and how people could test it,
--
--   http://angg.twu.net/eev-tikz.html
--   http://angg.twu.net/eev-tikz.html#introduction
--
-- and I recorded this video,
--
--   (find-2022tikzvideo "0:00")
--   (find-1stclassvideo-links "2022tikz")
--
-- and created this e-script with instructions:
--
--   (find-tikz1-links)
--
-- The central idea is that people would edit their diagrams in test
-- blocks - see:
--
--   http://anggtwu.net/eepitch.html#test-blocks
--
-- and then they would type <f8> on two lines like these:
--
--   show()
--   * (tikz-show)
--
-- The "show()" would:
--   a1) create a .tex file,
--   a2) compile the .tex with lualatex, and
--   a3) tell the user if the compilation was successful;
-- the "(tikz-show)" would:
--   b1) create the 3-window setting below, and
--   b2) refresh that PDF being displayed.
--      ___________________________
--     |           |               |
--     |           |  [t]arget     |
--     | the file  |   buffer      |
--     |   being   |_______________|
--     | [e]dited  |               |
--     | (a .lua)  |  [v]iew the   |
--     |           | resulting PDF |
--     |___________|_______________|
--
-- The "show()" would be sent to the Lua REPL in the target buffer and
-- would be run from there, and the "(tikz-show)" would be run from
-- elisp. This separation simplified the code a lot - but the user had
-- to wait for the success message from the "show()" before running
-- the "(tikz-show)".
--
-- In 2023 I saw that I needed some way to generalize that - I had
-- many Lua classes whose objects had nice LaTeX-ed representations,
-- and it would be better to use something like this,
--
--   o:show()
--   * (etv)
--
-- where each class would have a different ":show()" method... most of
-- my classes "represent" diagrams drawn with pict2e, several
-- represent diagrams drawn with "\underbrace"s, and only a few use
-- TikZ; I needed a way to handle these different ":show()" methods.
--
-- This file implements some tools for defining these ":show()"s, and
-- it also implements (the Lua side of) a simple way to configure
-- where the .tex and the .pdf file are to be put. To understand how
-- this configuration is done and how the Emacs side works, see:
--
--   (find-show2-intro "3. Show2.lua")
--
--
--
-- TODO: Explain this:
--   http://angg.twu.net/pict2e-lua.html
--   (find-1stclassvideo-links "2022pict2elua")
--   (find-angg "LUA/tikz1.lua" "Show-class")
--   (find-TH "pict2e-lua")
--   (find-TH "pict2e-lua" "try-it")


require "Dang1"     -- (find-angg "LUA/Dang1.lua")
-- TODO: Use Dang1, add shows

table.addentries(Dang.__index, {
    -- See below: (to "StringShow")
    show00   = function (da,...) return tostring(da):show00(...) end,
    show0    = function (da,...) return tostring(da):show0 (...) end,
    show     = function (da,...) return tostring(da):show  (...) end,
  })

-- TODO: Delete the block below, add tests



--  ____                    
-- |  _ \  __ _ _ __   __ _ 
-- | | | |/ _` | '_ \ / _` |
-- | |_| | (_| | | | | (_| |
-- |____/ \__,_|_| |_|\__, |
--                    |___/ 
--
-- An object is the class Dang "is" a string whose parts
-- between <<D>>ouble <<ANG>>le brackets "are to be expanded".
--
-- More precisely: each object of the class Dang contains a
-- field .bigstr with a string. When that object is "expanded"
-- by tostring all the parts between double angle brackets
-- in .bigstr are "expanded" by :eval(). The expansion
-- happens every time that the tostring is run, and so the
-- result of the expansion may change.
--
-- Note that I use these conventions:
--   a bigstr is a string that may contain newlines,
--   a str    is a string that does not contain newlines,
--   an s     is the argument for the function f when
--            we run bigstr:gsub(pat, f) or str:gsub(pat, f).
--
-- To understand the details, see the tests below, in:
--   (to "Dang-tests")
-- Based on: (find-angg "LUA/tikz1.lua" "Dang")
-- Uses:     (find-angg "LUA/lua50init.lua" "eval-and-L")
--
-- «Dang»  (to ".Dang")

Dang = Class {
  type = "Dang",
  from = function (bigstr) return Dang {bigstr=bigstr} end,
  __call = function (da,...) return da:tostring(...) end,
  __tostring = function (da) return da:tostring() end,
  __index = {
    code = function (da,s)
        if s:match"^::" then return Code.eval(s:sub(3)) end
        if s:match"^%." then return Code.ve("_ => _."..s:sub(2)) end
        if s:match"^:"  then return Code.ve(s:sub(2)) end
        return Code.expr(s)
      end,
    eval0 = function (da,s,...) return da:code(s)(...) end,
    eval  = function (da,s,...) return tostringe(da:eval0(s,...)) end,
    --
    pat = "<<(.-)>>",
    tostring = function (da,...)
        local args = pack(...)
        local f = function (s) return da:eval(s, myunpack(args)) end
        return (da.bigstr:gsub(da.pat, f))
      end,
    --
    -- See below: (to "StringShow")
    show00   = function (da,...) return tostring(da):show00(...) end,
    show0    = function (da,...) return tostring(da):show0 (...) end,
    show     = function (da,...) return tostring(da):show  (...) end,
  },
}

-- «Dang-tests»  (to ".Dang-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Show2.lua"
da = Dang {}
= da:code    "2+3"
= da:code    "2+3"  ()
= da:eval0  ("2+3")
= da:eval   ("2+3")
= da:code   ".foo"
= da:code   ".foo" ({foo="FOO", bar="BAR"})
= da:eval0 (".foo", {foo="FOO", bar="BAR"})
= da:eval  (".foo", {foo="FOO", bar="BAR"})
= da:code   ":a,b => a+b,a*b"
= da:code   ":a,b => a+b,a*b" (2, 3)
= da:eval0 (":a,b => a+b,a*b", 2, 3)
= da:eval  (":a,b => a+b,a*b", 2, 3)

= Dang.from "a<<2+3>>b"
= Dang.from "_<<2+3>>_<<: a,b => a*b   >>_" (4,5)
= Dang.from "_<<2+3>>_<<. foo          >>_" ({foo="FOO", bar="BAR"})
= Dang.from "_<<2+3>>_<<:: return true >>_"

--]==]





--  _____   __  ______       _   
-- |_   _|__\ \/ / ___|  ___| |_ 
--   | |/ _ \\  /\___ \ / _ \ __|
--   | |  __//  \ ___) |  __/ |_ 
--   |_|\___/_/\_\____/ \___|\__|
--                               
-- A variant of the class Set in which __tostring produces TeX code.
-- TODO: replace "usepackages" and "defs" by TeXSet objects.
--  See: (find-angg "LUA/Set.lua" "Set")
-- «TeXSet»  (to ".TeXSet")

TeXSet = Class {
  type = "TeXSet",
  create = function (name, sep)
      local ts = TeXSet {name=name, _=Set.new(), sep=(sep or "\n")}
      _G[name] = ts
      return ts
    end,
  __newindex = function (ts, key, val)
      if val == nil then ts._:del(key); return end
      if val == true then
        local globalname = ts.name.."_"..key
        local currentvalue = _G[globalname]
        if not currentvalue then error(globalname.." is nil") end
        ts._:add(key, currentvalue)
        return
      end
      ts._:add(key, val)
    end,
  __tostring = function (ts)
      local f = function (key) return tostring(ts._:get(key)) end
      local keys = ts._:ks()
      return mapconcat(f, keys, ts.sep)
    end,
  __index = {
  },
}

-- «TeXSet-tests»  (to ".TeXSet-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Show2.lua"
  usepackages     = TeXSet.create("usepackages")
  usepackages_foo = Dang.from "\\usepackage[<<foooptions>>]{foo}"
= usepackages
  usepackages.bar = "\\usepackage{bar}"    -- new
  usepackages.foo = true                   -- use the current usepackages_foo
= usepackages
   foooptions = TeXSet.create("foooptions", ",")
=  foooptions
   foooptions.blep = "blep"
   foooptions.blip = "blip"
=  foooptions
= usepackages
   foooptions.blip = nil                    -- delete this option
= usepackages

--]==]


-- «defs»  (to ".defs")
TeXSet.create("defs")

-- «defs_repl»  (to ".defs_repl")
-- Based on: (find-angg "LUA/tikz1.lua" "repl2")
-- See: (find-angg "LUA/DednatRequire1.lua")
--      (find-angg "LUA/lua50init.lua" "loaddednatrequire")
--      (find-angg "LUA/lua50init.lua" "Repl3.lua" "run_repl3_now =")
defs_repl = [=[
              \directlua{ dofile(os.getenv("LUA_INIT"):sub(2)) }
              \directlua{ loaddednatrequire()                  }
\def\repl    {\directlua{ print(); run_repl3_now()             }}
\def\condrepl{\directlua{ if os.getenv"REPL"=="1" then print(); run_repl3_now() end }}
]=]



-- «usepackages»  (to ".usepackages")
TeXSet.create("usepackages")
usepackages_edrx21 = [=[
\usepackage{edrx21}               % (find-LATEX "edrx21.sty")
\input edrxaccents.tex            % (find-LATEX "edrxaccents.tex")
\input edrx21chars.tex            % (find-LATEX "edrx21chars.tex")
%\input edrxheadfoot.tex          % (find-LATEX "edrxheadfoot.tex")
\input edrxgac2.tex               % (find-LATEX "edrxgac2.tex")
]=]
usepackages_hyperref = [=[
\usepackage[colorlinks,citecolor=red,urlcolor=red]{hyperref}
]=]
usepackages_pict2e = [=[
\usepackage{pict2e}
\def\pictgridstyle{\color{GrayPale}\linethickness{0.3pt}}
\def\pictaxesstyle{\linethickness{0.5pt}}
\def\pictnaxesstyle{\color{GrayPale}\linethickness{0.5pt}}
\def\closeddot{{\circle*{0.4}}}
\def\opendot  {{\circle*{0.4}\color{white}\circle*{0.25}}}
\unitlength=20pt
]=]
usepackages_tikz = [=[
\usepackage{tikz}
]=]

-- «middletexbody»  (to ".middletexbody")
middletexbody_bare = Dang.from [=[<<texbody>>]=]
middletexbody      = middletexbody_bare


-- «dednat6»  (to ".dednat6")
-- (find-angg "LUA/Maxima2.lua"   "show2-tests")
-- (find-angg "LUA/Verbatim2.lua" "vbt-head-tests")
TeXSet.create("dednat6")
dednat6_0 = [=[
\catcode`\^^J=10
\directlua{dofile "dednat6load.lua"}  % (find-LATEX "dednat6load.lua")
]=]
dednat6_Verbatim2 = [==[
% (find-Deps1-cps "Verbatim2")
%L dofile "Verbatim2.lua"            -- (find-LATEX "Verbatim2.lua")
\pu
]==]
dednat6_Verbatim3 = [==[
% (find-Deps1-cps "Verbatim3")
%L dofile "Verbatim3.lua"            -- (find-LATEX "Verbatim3.lua")
\pu
]==]



--  _            _               _       
-- | |_ _____  _| |__   ___   __| |_   _ 
-- | __/ _ \ \/ / '_ \ / _ \ / _` | | | |
-- | ||  __/>  <| |_) | (_) | (_| | |_| |
--  \__\___/_/\_\_.__/ \___/ \__,_|\__, |
--                                 |___/ 
-- «texbody»  (to ".texbody")
-- Based on: (find-angg "LUA/tikz1.lua" "texbody")

scale = "1.0"
geometry = "paperwidth=148mm, paperheight=88mm,\n            "..
           "top=1.5cm, bottom=.25cm, left=1cm, right=1cm, includefoot"
geometryhead = "paperwidth=148mm, paperheight=88mm, top=2cm"
saysuccess = "\\GenericWarning{Success:}{Success!!!}"

outertexbody = Dang.from [=[
\documentclass[<<documentclassoptions>>]{book}
\usepackage[x11names,svgnames]{xcolor}
\usepackage{colorweb}
\usepackage{graphicx}
\usepackage[<<geometry>>]{geometry}
<<usepackages>>
<<dednat6>>
\begin{document}
\pagestyle{empty}
<<defs>>
<<middletexbody>>
<<saysuccess>>
\end{document}
]=]

-- «texbody-tests»  (to ".texbody-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Show2.lua"
= outertexbody.bigstr
= outertexbody
  texbody = "FOO"
= outertexbody

--]==]



--  ____  _
-- / ___|| |__   _____      __
-- \___ \| '_ \ / _ \ \ /\ / /
--  ___) | | | | (_) \ V  V /
-- |____/|_| |_|\___/ \_/\_/
--
-- This class treats a bigstr as LaTeX code, preprocesses it in
-- certain configurable ways, tries to run lualatex on the result,
-- _ALMOST_ prints a status showing if the lualatex-ing was
-- successful, and _ALMOST_ shows the resulting PDF.
-- delegated to an elisp function called etv, that is run from a red
-- star line like this one,
--
--   * (show2-use "/tmp/Show2.tex")
--   * (eepitch-lua51)
--   * (eepitch-kill)
--   * (eepitch-lua51)
--   dofile "Show2.lua"
--     texbody = "FOO"
--   = outertexbody
--   = Show.try(tostring(outertexbody))
--   = Show.log
--   = Show.bigstr
--   * (etv)
--
-- that creates a 3-window setting whose windows are called [e]dit,
-- [t]arget, and [v]iew:
--    ___________________________
--   |           |     	       	 |
--   |           |  [t]arget	 |
--   | the file  |   buffer	 |
--   |   being   |_______________|
--   | [e]dited  |		 |
--   | (a .lua)  |  [v]iew the	 |
--   |           | resulting PDF |
--   |___________|_______________|
--
-- The function (etv) is usually defined by a call to `show2-use'.
--      See: (find-show2-intro "3. Show2.lua")
--           (find-show2-intro "3. Show2.lua" "show2-use")
-- Based on: (find-angg "LUA/tikz1.lua" "Show-class")
--
-- «Show»  (to ".Show")
--
Show = Class {
  type = "Show",
  new  = function (bigstr) Show.bigstr = bigstr; return Show{} end,
  save = function (bigstr) return Show.new(bigstr):write():fnametex() end,
  try  = function (bigstr) return Show.new(bigstr):write():compile() end,
  -- These variables are set at each call:
  bigstr  = "",
  log     = "",
  success = nil,
  --
  __tostring = function (s) return s:tostring() end,
  __index = {
    tostring = function (s)
        return format("Show: %s => %s", s:fnametex(), Show.success or "?")
      end,
    --
    nilify   = function (s, o) if o=="" then return nil else return o end end,
    getenv   = function (s, varname) return s:nilify(os.getenv(varname)) end,
    dir      = function (s) return s:getenv("SHOW2DIR")  or "/tmp/" end,
    stem     = function (s) return s:getenv("SHOW2STEM") or "Show2" end,
    fnametex = function (s) return s:dir()..s:stem()..".tex" end,
    fnamepdf = function (s) return s:dir()..s:stem()..".pdf" end,
    fnamelog = function (s) return s:dir()..s:stem()..".log" end,
    cmd      = function (s)
        return "cd "..s:dir().." && lualatex "..s:stem()..".tex < /dev/null"
      end,
    write = function (s)
        ee_writefile(s:fnametex(), Show.bigstr)
        return s
      end,
    compile = function (s)
        Show.log = getoutput(s:cmd())
        Show.success = Show.log:match "Success!!!"
        return s
      end,
  },
}

-- «Show-tests»  (to ".Show-tests")
--[==[
* (show2-use "/tmp/")
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Show2.lua"
s = Show {}
= s:dir()
= s:stem()
= s:fnametex()
= s:fnamepdf()
= s:cmd()

  texbody = "FOO"
= outertexbody
= Show.try(tostring(outertexbody))
= Show.log
= Show.bigstr
* (etv)

--]==]




--  ____  _        _             ____  _                   
-- / ___|| |_ _ __(_)_ __   __ _/ ___|| |__   _____      __
-- \___ \| __| '__| | '_ \ / _` \___ \| '_ \ / _ \ \ /\ / /
--  ___) | |_| |  | | | | | (_| |___) | | | | (_) \ V  V / 
-- |____/ \__|_|  |_|_| |_|\__, |____/|_| |_|\___/ \_/\_/  
--                         |___/                           
--
-- This class implements the basic way in which string objects are
-- (LaTeXed and) "shown". For example, in
--
--   ("a \\cdot b"):show00 {scale=4, em=true}
--   ("a \\cdot b"):show0  {scale=4, em=true}
--   ("a \\cdot b"):show   {scale=4, em=true}
--
-- the third line wraps the "a \\cdot b" in an "\ensuremath" and in a
-- "\scalebox", sets the global variable "texbody" to the result of
-- that, and then runs this,
--
--   Show.try(tostring(outertexbody))
--
-- that runs lualatex and returns a status message.
--
-- Note that ":show" treats the string "a \\cdot b" of the example
-- above as an ("inner") "body", and it works like this:
--
--   body,opts --:show00--> texbody --> tostring(outertexbody) --> status
--          \ \--:show0----------------^                          ^
--           \---:show-------------------------------------------/
-- 
-- so we can use ":show00" and ":show0" to inspect how ":show" works.
--
-- Compare with:
--   (find-angg "LUA/Pict3.lua" "Pict-show")
--
-- «StringShow»  (to ".StringShow")
StringShow = Class {
  type = "StringShow",
  new  = function () return StringShow {} end,
  __index = {
    show00 = function (ss, body, opts)
        opts = opts or {}
        local s = body
        if opts.D     then s = format("\\displaystyle %s", s) end
        if opts.em    then s = format("\\ensuremath{%s}", s) end
        if opts.scale then s = format("\\scalebox{%s}{%s}", opts.scale, s) end
        return s
      end,
    show0 = function (ss, body, opts)
        texbody = ss:show00(body, opts)
        return tostring(outertexbody)
      end,
    show = function (ss, body, opts)
        return Show.try(ss:show0(body, opts))
      end,
    save = function (ss, body, opts)
        return Show.save(ss:show0(body, opts))
      end,
  },
}

string.show00 = function (body, opts) return StringShow.new():show00(body, opts) end
string.show0  = function (body, opts) return StringShow.new():show0 (body, opts) end
string.show   = function (body, opts) return StringShow.new():show  (body, opts) end
string.save   = function (body, opts) return StringShow.new():save  (body, opts) end

-- «StringShow-tests»  (to ".StringShow-tests")
--[[
* (show2-use "/tmp/")
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Show2.lua"
= StringShow.new():show00("foo")
= StringShow.new():show00("foo", {scale=2, em=true})
= StringShow.new():show0 ("foo", {scale=2, em=true})
= StringShow.new():show  ("foo", {scale=2, em=true})
* (etv)

= ("a \\cdot b"):show00 ()
= ("a \\cdot b"):show00 {scale=2, em=true}
= ("a \\cdot b"):show0  {scale=2, em=true}
= ("a \\cdot b"):show   {scale=2, em=true}
* (etv)

= Show.log
= Show.bigstr
= outertexbody
= outertexbody.bigstr

--]]







-- (defun e () (interactive) (find-angg "LUA/Show2.lua"))

-- Local Variables:
-- coding:  utf-8-unix
-- End: