Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
-- This file:
--   http://anggtwu.net/LUA/Maxima3.lua.html
--   http://anggtwu.net/LUA/Maxima3.lua
--          (find-angg "LUA/Maxima3.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
--
-- See: (find-angg "MAXIMA/2025-baf-qparts.mac")
--      (find-Maxima3-links)
--
-- (defun e () (interactive) (find-angg "LUA/Maxima3.lua"))
-- (defun o () (interactive) (find-angg "LUA/Maxima2.lua"))
-- (defun oe () (interactive) (find-2a '(o) '(e)))
--
-- «.MaximaIO»			(to "MaximaIO")
-- «.MaximaIO-tests»		(to "MaximaIO-tests")
-- «.MaximaParse»		(to "MaximaParse")
-- «.MaximaParse-tests»		(to "MaximaParse-tests")
-- «.MaximaTeX»			(to "MaximaTeX")
-- «.MaximaTeX-tests»		(to "MaximaTeX-tests")
-- «.MaximaHead»		(to "MaximaHead")
-- «.MaximaHead-tests»		(to "MaximaHead-tests")
-- «.SplitMaximaLog1»		(to "SplitMaximaLog1")
-- «.SplitMaximaLog1-tests»	(to "SplitMaximaLog1-tests")
-- «.SplitMaximaLog»		(to "SplitMaximaLog")
-- «.SplitMaximaLog-tests»	(to "SplitMaximaLog-tests")
-- «.log-to-i»			(to "log-to-i")

require "Co1"             -- (find-angg "LUA/Co1.lua")
require "Pict3"           -- (find-angg "LUA/Pict3.lua")


--  __  __            _                 ___ ___  
-- |  \/  | __ ___  _(_)_ __ ___   __ _|_ _/ _ \ 
-- | |\/| |/ _` \ \/ / | '_ ` _ \ / _` || | | | |
-- | |  | | (_| |>  <| | | | | | | (_| || | |_| |
-- |_|  |_|\__,_/_/\_\_|_| |_| |_|\__,_|___\___/ 
--                                               
-- «MaximaIO»  (to ".MaximaIO")
MaximaIO = Class {
  type    = "MaximaIO",
  __tostring = function (mio) return mio:torect():tostring() end,
  __index = {
    r = function (mio,name)
        if not mio[name] then return Rect {} end
        if #mio[name]==0 then return Rect {} end
        local right = Rect(copy(mio[name]))
        local left  = Rect {format("%-3s ", name..":")}
        return left..right
      end,
    torect = function (mio)
        return mio:r"i" / mio:r"ip" / mio:r"o"
      end,
    push = function (mio,name,line)
        mio[name] = mio[name] or VTable {}
        table.insert(mio[name], line)
        return mio
      end,
  },
}

-- «MaximaIO-tests»  (to ".MaximaIO-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima3.lua"
m = MaximaIO {i={"a","b"}, ip={"c"}, o={"d","e"}, op={}}
= m:r"i"
= m:r"i" / m:r"ip"
= m:r"i" / m:r"ip" / m:r"foo"
= m:torect()
= m
= m:push("o","f")
= m:push("op","g")

--]]


--  __  __            _                 ____                     
-- |  \/  | __ ___  _(_)_ __ ___   __ _|  _ \ __ _ _ __ ___  ___ 
-- | |\/| |/ _` \ \/ / | '_ ` _ \ / _` | |_) / _` | '__/ __|/ _ \
-- | |  | | (_| |>  <| | | | | | | (_| |  __/ (_| | |  \__ \  __/
-- |_|  |_|\__,_/_/\_\_|_| |_| |_|\__,_|_|   \__,_|_|  |___/\___|
--                                                               
-- «MaximaParse»  (to ".MaximaParse")
MaximaParse = Class {
  type    = "MaximaParse",
  fromlines = function (lines) return MaximaParse{}:parselines(lines) end,
  __tostring = function (mp) return mp:torect():tostring() end,
  __index = {
    torect = function (mp)
        local rect = Rect {}
	local mios = mp.mios or {}
        for i=1,#mios do
	  local mio = MaximaIO(copy(mios[i]))
          local left = Rect {format("%-4s ", "("..i.."):")}
          local right = mio:torect()
          rect = rect / (left..right)
        end
        return rect
      end,  
    addmio = function (mp)
        mp.mios = mp.mios or {}
        table.insert(mp.mios, MaximaIO {})
        return mp
      end,
    lastmio = function (mp) return MaximaIO(mp.mios[#mp.mios]) end, -- set metatable
    push = function (mp,name,line) mp:lastmio():push(name,line); return mp end,
    --
    -- The state machine
    splitline = function (mp,line)
        local kind,n,body = line:match("^%(%%([io])([0-9]+)%) ?(.*)")
        if kind then return kind,n,body end
        return nil,nil,line   -- the whole line becomes the body
      end,
    parseline_inner = function (mp,state,kind,line)
        if kind=="i" then mp:addmio():push("i",line); return "i" end
        if kind=="o" then mp         :push("o",line); return "o" end
        if kind==nil and state=="i" then mp:push("ip",line); return "i" end
        error("Bad transition: state=%s, kind=%s", state, kind)
      end,
    parseline = function (mp,line)
        local kind,n,body = mp:splitline(line)
        local state = mp.state
        local newstate = mp:parseline_inner(state,kind,line)
        mp.state = newstate
        return mp
      end,
    parselines = function (mp,lines)
        if type(lines)=="string" then lines = splitlines(lines) end
        for _,line in ipairs(lines) do mp:parseline(line) end
        return mp
      end,
  },
}

maximaparse_iines = Rect {
  "(%i1) a,",
  "      b;",
  "(%o1) a b",
  "(%i2) c$",
}

-- «MaximaParse-tests»  (to ".MaximaParse-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima3.lua"
mp = MaximaParse {}
mp = MaximaParse {mios={{i={"a"}},
                        {i={"b"}}}}
= mp:push("i", "c")
= mp:push("i", "d"):push("o", "e"):addmio():push("i", "f")

= mp:splitline("(%i42) foo")
= mp:splitline("(%i42)foo")
= mp:splitline("(%i42)")
= mp:splitline("bla")

mp = MaximaParse.fromlines(maximaparse_iines)
= mp

--]]





--  __  __            _                _____   __  __
-- |  \/  | __ ___  _(_)_ __ ___   __ |_   _|__\ \/ /
-- | |\/| |/ _` \ \/ / | '_ ` _ \ / _` || |/ _ \\  / 
-- | |  | | (_| |>  <| | | | | | | (_| || |  __//  \ 
-- |_|  |_|\__,_/_/\_\_|_| |_| |_|\__,_||_|\___/_/\_\
--                                                   
-- «MaximaTeX»  (to ".MaximaTeX")
-- (find-angg "LUA/Maxima2.lua" "MaximaLine")

MaximaTeX = Class {
  type = "MaximaTeX",
  linestorect = function (lines)
      local mp = MaximaParse{}:parselines(lines)
      local mios = mp.mios
      return MaximaTeX{}:miosrect(mios)
    end,
  linestovbox = function (lines)
      return MaximaTeX{}:vbox(MaximaTeX.linestorect(lines))
    end,
  linestopict = function (lines)
      return Pict { MaximaTeX.linestovbox(lines) }
    end,
  __index = {
    match = function (mt,str,pat)
        local result = str:match(pat)
        if not result then PP("Doesn't match:", pat, str); error("") end
        return result
      end,
    left   = function (mt,line) return mt:match(line, "^(%(%%[io][0-9]+%) ?).*") end,
    right  = function (mt,line) return mt:match(line, "^%(%%[io][0-9]+%) ?(.*)") end,
    spaces = function (mt,line) return (mt:left(line):gsub(".", " ")) end,
    indent = function (mt,iline,ipline) return mt:spaces(iline)..ipline end,
    --
  --co     = Co.new(" \\%{}$_", "^~"),
    co     = Co.new("\\%{}$_", " ^~"),
    cot    = function (mt,str) return mt.co:translate(str) end,
    blue0  = function (mt,a)   return format("\\maximablue{%s}", a) end,
    red0   = function (mt,a,b) return format("\\maximared{%s}{%s}", a,b) end,
    blue   = function (mt,a)   return mt:blue0(mt:cot(a)) end,
    red    = function (mt,a,b) return mt:red0 (mt:cot(a), b) end,
    blue1  = function (mt,iline) return mt:blue(iline) end,
    blue2  = function (mt,iline,ipline) return mt:blue1(mt:indent(iline,ipline)) end,
    red1     = function (mt,line) return mt:red(mt:left(line),mt:right(line)) end,
    redleft  = function (mt,line) return mt:red(mt:left(line),"") end,
    redright = function (mt,line) return mt:red("",mt:right(line)) end,
    --
    miorect = function (mt,mio)
        local iline  = mio.i[1]
        local irect  = Rect {mt:blue1(iline)}
        local iprect = Rect {}
        local orect  = Rect {}
        for _,ipline in ipairs(mio.ip or {}) do
          table.insert(iprect, mt:blue2(iline,ipline))
        end
        for _,oline in ipairs(mio.o or {}) do
          table.insert(orect, mt:redleft(oline))
          table.insert(orect, mt:redright(oline))
          table.insert(orect, mt:red0("",""))
        end
        return irect / iprect / orect
      end,
    miosrect = function (mt,mios)
        local bigrect = Rect {}
        for _,mio in ipairs(mios) do bigrect = bigrect / mt:miorect(mio) end
        return bigrect
      end,
    vbox = function (mt,rect)
        return format("\\vbox{%s}", table.concat(rect))
      end,
  },
}

-- «MaximaTeX-tests»  (to ".MaximaTeX-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)

* (eepitch-lua54)
* (eepitch-kill)
* (eepitch-lua54)
dofile "Maxima3.lua"

mt = MaximaTeX {}
iline  = "(%i1) 42"
ipline = "33"
oline  = "(%o1) 99"
PP(iline)
PP(mt:left(iline))
PP(mt:right(iline))
PP(mt:spaces(iline))
PP(mt:indent(iline, ipline))
PP(mt:blue1(iline))
PP(mt:blue2(iline, ipline))
PP(mt:red1(oline))

lines = {
  "(%i1) a,",
        "b;",
  "(%o1) a b",
  "(%i2) c$"
}
= MaximaTeX.linestorect(lines)
= MaximaTeX.linestovbox(lines)
MaximaTeX.__index.co = Co.new("", "")
= MaximaTeX.linestorect(lines)
= MaximaTeX.linestovbox(lines)
= MaximaTeX.linestopict(lines)
= MaximaTeX.linestopict(lines):sa"foo"

--]]




--  __  __            _                 _   _                _ 
-- |  \/  | __ ___  _(_)_ __ ___   __ _| | | | ___  __ _  __| |
-- | |\/| |/ _` \ \/ / | '_ ` _ \ / _` | |_| |/ _ \/ _` |/ _` |
-- | |  | | (_| |>  <| | | | | | | (_| |  _  |  __/ (_| | (_| |
-- |_|  |_|\__,_/_/\_\_|_| |_| |_|\__,_|_| |_|\___|\__,_|\__,_|
--                                                             
-- «MaximaHead»  (to ".MaximaHead")
-- (find-angg "LUA/Maxima2.lua" "MaximaHead")

MaximaHead = Class {
  type    = "MaximaHead",
  __index = {
    sa = function (mh, name)
        MaximaTeX.linestopict(mh.lines):sa(name):output()
      end,
  },
}
maximahead = MaximaHead {}

registerhead = registerhead or function () return nop end
registerhead "%M" {
  name   = "maxima",
  action = function ()
      local i,j,lines = tf:getblock(3)
      maximahead.lines = VTable(lines)
    end,
}

-- «MaximaHead-tests»  (to ".MaximaHead-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima3.lua"
maximahead.lines = VTable {
  "(%i1) a,",
        "b;",
  "(%o1) ab",
  "(%i2) c$"
}
output = output or print
maximahead:sa("foo")

maximahead.lines = table.concat(maximahead.lines, "\n")
maximahead:sa("foo")

--]]



--  ____        _ _ _   __  __            _                 _                _ 
-- / ___| _ __ | (_) |_|  \/  | __ ___  _(_)_ __ ___   __ _| |    ___   __ _/ |
-- \___ \| '_ \| | | __| |\/| |/ _` \ \/ / | '_ ` _ \ / _` | |   / _ \ / _` | |
--  ___) | |_) | | | |_| |  | | (_| |>  <| | | | | | | (_| | |__| (_) | (_| | |
-- |____/| .__/|_|_|\__|_|  |_|\__,_/_/\_\_|_| |_| |_|\__,_|_____\___/ \__, |_|
--       |_|                                                           |___/   
--
-- «SplitMaximaLog1»  (to ".SplitMaximaLog1")
SplitMaximaLog1 = Class {
  type = "SplitMaximaLog1",
  __tostring = function (sl) return sl:tostring() end,
  __index = {
    tostring = function (sl) return sl:torect():tostring() end,
    torect   = function (sl) return sl.name..": "..Rect(splitlines(sl.bigstr)) end,
    sa       = function (sl)
        local addM = function (line) return format("%%M %s\n", line) end
        local linesM = mapconcat(addM, splitlines(sl.bigstr))
        return format("%s%%L\n%%L maximahead:sa(\"%s\", \"\")\n\\pu", linesM, sl.name)
      end,
    ga = function (sl)
        local fmt = "\\vspace*{0cm}\n\\def\\hboxthreewidth{9cm}\n\\ga{%s}"
        return format(fmt, sl.name)
      end,
  },
}

-- «SplitMaximaLog1-tests»  (to ".SplitMaximaLog1-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima3.lua"
sl = SplitMaximaLog1 {name="aaa", bigstr="(%i1) foo\n(%o1) bar"}
= sl
= sl:sa()
= sl:ga()

--]]




--  ____        _ _ _   __  __            _                 _                
-- / ___| _ __ | (_) |_|  \/  | __ ___  _(_)_ __ ___   __ _| |    ___   __ _ 
-- \___ \| '_ \| | | __| |\/| |/ _` \ \/ / | '_ ` _ \ / _` | |   / _ \ / _` |
--  ___) | |_) | | | |_| |  | | (_| |>  <| | | | | | | (_| | |__| (_) | (_| |
-- |____/| .__/|_|_|\__|_|  |_|\__,_/_/\_\_|_| |_| |_|\__,_|_____\___/ \__, |
--       |_|                                                           |___/ 
--
-- «SplitMaximaLog»  (to ".SplitMaximaLog")
SplitMaximaLog = Class {
  type = "SplitMaximaLog",
  from = function (bigstr)
      if type(bigstr) == "table" then bigstr = table.concat(bigstr, "\n") end
      return SplitMaximaLog({bigstr=bigstr}):calcdivs():getlog1s()
    end,
  __tostring = function (sml) return sml:tostring() end,
  __index = {
    tostring = function (sml)
        return mapconcat(tostring, sml, "\n\n")
      end,
    calcdivs = function (sml)
        sml.divs = VTable {}
        local pat = "()%(%%i[0-9]+%) ()/%* block (.-) %*/\n()"
	for p0,p1,name,p2 in sml.bigstr:gmatch(pat) do
          table.insert(sml.divs, {name=name, p0=p0, p1=p1, p2=p2})
        end
        table.insert(sml.divs, {p0=#sml.bigstr})
        return sml
      end,
    getlog1 = function (sml,n)
        local str01 = sml.bigstr:sub(sml.divs[n].p0, sml.divs[n].p1   - 1)
        local str23 = sml.bigstr:sub(sml.divs[n].p2, sml.divs[n+1].p0 - 1)
	local name = sml.divs[n].name
	return SplitMaximaLog1 {name=name, bigstr=str01..str23}
      end,
    getlog1s = function (sml)
        local blocks = VTable {}
        sml:calcdivs()
        for i=1,#sml.divs-1 do sml[i] = sml:getlog1(i) end
        return sml
      end,
    sas = function (sml, sep)
        local f = function (sml1) return sml1:sa() end
	if sep then return mapconcat(f, sml, sep) else return map(s, sml) end
      end,
    gas = function (sml, sep)
        local f = function (sml1) return sml1:ga() end
	if sep then return mapconcat(f, sml, sep) else return map(s, sml) end
      end,
    all_gas_in_one_slide = function (sml)
        local body = sml:gas("\n\n}\\def\\colwidth{7.5cm}\\anothercol{\n\n")
        return "\\scalebox{0.6}{\\def\\colwidth{9cm}\\firstcol{\n\n"..body.."\n\n}}"
      end,
    all_in_one_slide = function (sml)
        return sml:sas("\n\n").."\n\n"..sml:all_gas_in_one_slide()
      end,
  },
}

lines_maximalog = Rect {
  "(%i42) linenum : 0$",
  "(%i1) /* block aaaaa */",
  "a+b;",
  "(%o1)    b + a",
  "(%i2) /* block bbbbb */",
  "foo;",
  "(%o2)    foo",
  "(%i3) ",
}

-- «SplitMaximaLog-tests»  (to ".SplitMaximaLog-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima3.lua"
s = SplitMaximaLog.from(lines_maximalog)
= s
= s.bigstr
= s.divs
= s:sas("\n\n")
= s:gas("\n\n")
= s:all_gas_in_one_slide()
= s:    all_in_one_slide()

--]==]



-- «log-to-i»  (to ".log-to-i")
-- Converts a log of a Maxima session to some LaTeX/Dednat code
-- that can be inserted into a .tex file with `M-x i'. See:
--   (find-efunction 'find-Maxima3-links)
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima3.lua"
bigstr = ee_readfile "/tmp/o"
  s = SplitMaximaLog.from(bigstr)
= s
  o2 = s:sas("\n\n")
= o2
  o2 = s:all_in_one_slide()
= o2
ee_writefile("/tmp/o2", o2)
** (find-fline "/tmp/o2")
* (defun i () (interactive) (insert-file "/tmp/o2"))

--]]





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