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: