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>
-- Version: 2025dec24
-- Public domain.
--
-- My current way of LaTeXing Maxima logs is, or would be,
-- explained in these places:
--   https://anggtwu.net/eev-emaxima.html
--   https://anggtwu.net/eev-maxima.html#embedding-in-LaTeX
--   (find-angg "MAXIMA/2025-emaxima.mac")
--
-- 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-split»			(to "MaximaIO-split")
--   «.MaximaIO-tex»			(to "MaximaIO-tex")
--   «.MaximaIO-changeinput»		(to "MaximaIO-changeinput")
-- «.MaximaIO-tests»			(to "MaximaIO-tests")
-- «.MaximaIO-tex-tests»		(to "MaximaIO-tex-tests")
-- «.MaximaIO-changeinput-tests»	(to "MaximaIO-changeinput-tests")
-- «.MaximaBlock»			(to "MaximaBlock")
-- «.MaximaBlock-tests»			(to "MaximaBlock-tests")
-- «.SplitIntoMIOs»			(to "SplitIntoMIOs")
-- «.SplitIntoMIOs-tests»		(to "SplitIntoMIOs-tests")
-- «.SplitIntoBlocks»			(to "SplitIntoBlocks")
-- «.SplitIntoBlocks-tests»		(to "SplitIntoBlocks-tests")
-- «.MaximaHead»			(to "MaximaHead")
-- «.MaximaHead-tests»			(to "MaximaHead-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")
-- This is one of the main data structures, and its methods are a
-- kitchen sink. When we parse the contents of a "*maxima*" buffer
-- each "pair of lines with complications" like this
--
--   (%i1) 2+3;
--   (%o1)        5
--
-- becomes a MaximaIO object; the basic "complications" are that the
-- output line is optional and that the input may span several lines.
-- When we export the "pair with complications" above to a Dednat7
-- block in a .tex file it becomes this,
--
--   %M (%i1) 2+3;
--   %M (%o1)        5
--
-- and the method `totexrect' converts that MaximaIO object to
-- something like this:
--
--   \maximablue{(\%i1)\ 2+3;}
--   \maximared{(\%o1)\ }{}
--   \maximared{}{       5}
--   \maximared{}{}
--
MaximaIO = Class {
  type    = "MaximaIO",
  __tostring = function (mio) return mio:tostructrect():tostring() end,
  __index = {
    -- The state machine in the parser uses `:push'
    -- to add lines to .i, .ip, or .o
    push = function (mio,name,line)
        mio[name] = mio[name] or Rect {}
        table.insert(mio[name], line)
        return mio
      end,
    --
    -- An output format that shows the structure
    rnamed = 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,
    tostructrect = function (mio)
        return mio:rnamed"i" / mio:rnamed"ip" / mio:rnamed"o"
      end,
    --
    -- An output format that reconstructs the original lines
    r = function (mio,name)
        if not mio[name] then return Rect {} end
        if #mio[name]==0 then return Rect {} end
        return Rect(copy(mio[name]))
      end,
    torect = function (mio,fmt)
        local rect = mio:r"i" / mio:r"ip" / mio:r"o"
        for i=1,#rect do rect[i] = format(fmt or "%s", rect[i]) end
        return rect
      end,
    toMrect = function (mio) return mio:torect("%%M %s") end,
    --
    -- «MaximaIO-split»  (to ".MaximaIO-split")
    -- Most functions in this block are used by both totexrect and changeinput
    match = function (mio,str,pat)
        local result = str:match(pat)
        if not result then PP("Doesn't match:", pat, str); error("") end
        return result
      end,
    left   = function (mio,line) return mio:match(line, "^(%(%%[io][0-9]+%) ?).*") end,
    right  = function (mio,line) return mio: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,
    --
    -- «MaximaIO-tex»  (to ".MaximaIO-tex")
    -- An output format that return `\maximablue' and `\maximared' lines
    co     = Co.new(" \\%{}$_", "^~"),
    cot    = function (mio,str) return mio.co:translate(str) end,
    blue0  = function (mio,a)   return format("\\maximablue{%s}", a) end,
    red0   = function (mio,a,b) return format("\\maximared{%s}{%s}", a,b) end,
    blue   = function (mio,a)   return mio:blue0(mio:cot(a)) end,
    red    = function (mio,a,b) return mio:red0 (mio:cot(a), b) end,
    blue1  = function (mio,iline) return mio:blue(iline) end,
    blue2  = function (mio,iline,ipline) return mio:blue1(mio:indent(iline,ipline)) end,
    red1     = function (mio,line) return mio:red(mio:left(line),mio:right(line)) end,
    redleft  = function (mio,line) return mio:red(mio:left(line),"") end,
    redright = function (mio,line) return mio:red("",mio:right(line)) end,
    totexrect = function (mio)
        local iline  = mio.i[1]
        local irect  = Rect {mio:blue1(iline)}
        local iprect = Rect {}
        local orect  = Rect {}
        for _,ipline in ipairs(mio.ip or {}) do
          table.insert(iprect, mio:blue2(iline,ipline))
        end
        for _,oline in ipairs(mio.o or {}) do
          table.insert(orect, mio:redleft(oline))
          table.insert(orect, mio:redright(oline))
          table.insert(orect, mio:red0("",""))
        end
        return irect / iprect / orect
      end,
    --
    -- «MaximaIO-changeinput»  (to ".MaximaIO-changeinput")
    -- The "input" is stored in:
    --    .i: the first line, like {"(%i42) [3,"}, and
    --   .ip: the other lines, line {" 4,", " 5];"}.
    -- The functions below are used by SplitIntoBlocks, that modifies
    -- the input lines in .i and .ip to delete some blank lines and
    -- the things like "/* block foo */"s.
    -- 
    ileft  = function (mio) return mio:left (mio.i[1]) end,
    iright = function (mio) return mio:right(mio.i[1]) end,
    toinputrect = function (mio)
        local irect  = Rect {mio:iright()}
        local iprect = mio.ip and Rect(copy(mio.ip)) or Rect {}
        return irect / iprect
      end,
    toinputstring = function (mio) return mio:toinputrect():tostring() end, 
    changeinput = function (mio,newinputstring)
        local r  = Rect.from(newinputstring)
        local r1 = table.remove(r, 1)
        local i1 = mio:ileft()..(r1 or "")
        mio = copy(mio)
        mio.i = Rect {i1}
        mio.ip = (#r > 0) and r or nil
        return mio
      end,
    cleanblockname0 = function (mio,inputstring)
        local blockname
        local pat = "^\n*/%* block ([ -~]+) %*/\n(.*)$"
        local bn,rest = inputstring:match(pat)
        if bn then blockname,inputstring = bn,rest end
        local newinputstring = inputstring:gsub("%$\n*$", "$")
        return newinputstring,blockname
      end,
    cleanblockname = function (mio)
        local inputstring = mio:toinputstring()
        local newinputstring,blockname = mio:cleanblockname0(inputstring)
        local newmio = mio:changeinput(newinputstring)
        return newmio,blockname
      end,
  },
}

maximaio_test1 = MaximaIO {
  i  = {"(%i1) /* block foo */"},
  ip = {"[2,", " 3];"},
  o  = {"(%o1)    [2, 3]"}
}
maximaio_test2 = MaximaIO {
  i  = {"(%i2) 3+4;"},
  o  = {"(%o2)      7"}
}
maximaio_test3 = MaximaIO {
  i  = {"(%i2) 3+4$"}
}

-- «MaximaIO-tests»  (to ".MaximaIO-tests")
-- «MaximaIO-tex-tests»  (to ".MaximaIO-tex-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima3.lua"
m = maximaio_test2
m = maximaio_test3
m = maximaio_test1
= m:rnamed"i"
= m:rnamed"i" / m:rnamed"ip"
= m:rnamed"i" / m:rnamed"ip" / m:rnamed"foo"
= m:torect()
= m:toMrect()
= m:totexrect()

--]]


-- «MaximaIO-changeinput-tests»  (to ".MaximaIO-changeinput-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima3.lua"

PP(m:cleanblockname0 "\n\n\n/* block foo */\nabc\ndef$\n\n")
PP(m:cleanblockname0 "\n\n\n/* block foo */\nabc\ndef;")
PP(m:cleanblockname0                        "abc\ndef$\n\n")
PP(m:cleanblockname0                        "abc\ndef;")

= maximaio_test1;
= maximaio_test1:changeinput("a");
= maximaio_test1:changeinput("a\nb");
= maximaio_test1:changeinput("a\nb\nc");
= maximaio_test1;
= maximaio_test1:cleanblockname();
= maximaio_test2;
= maximaio_test2:cleanblockname();

m = deepcopy(maximaio_test1)
= m
= m:push("o","f")
= m:push("o","g")

m = maximaio_test1
= m
= m:totexrect(m)

= m:toinputrect()
= m:toinputstring()
= m:changeinput("bla")
= m:changeinput("bla\nbla")
= m

--]]



--  __  __            _                 ____  _            _    
-- |  \/  | __ ___  _(_)_ __ ___   __ _| __ )| | ___   ___| | __
-- | |\/| |/ _` \ \/ / | '_ ` _ \ / _` |  _ \| |/ _ \ / __| |/ /
-- | |  | | (_| |>  <| | | | | | | (_| | |_) | | (_) | (__|   < 
-- |_|  |_|\__,_/_/\_\_|_| |_| |_|\__,_|____/|_|\___/ \___|_|\_\
--                                                              
-- A MaximaBlock contains a list of MaximaIO objects and an optional
-- block name. MaximaBlocks without names and MaximaBlocks with names
-- serve different purposes, and one stage of the parsing process
-- converts, or splits, a MaximaBlock without name into several
-- MaximaBlocks with names. For example, suppose that we ran Maxima
-- and it produced a "*maxima*" buffer whose "log" part is this:
--
--   (%i1) /* block n-ary `=' */
--         nary("=.")$
--   (%i2) a =. b =. c;
--   (%o2)      a =. b =. c
--   (%i3) /* block etc */
--         2+3;
--   (%o3)           5
--
-- The class SplitIntoMIOs parses that and returns a single MaximaBlock
-- with no block name; the class SplitIntoBlocks parses that and returns
-- two `MaximaBlock's with names, that correspond to:
--
--   (block n-ary `=')
--   (%i1) nary("=.")$
--   (%i2) a =. b =. c;
--   (%o2)      a =. b =. c
--
--   (block etc)
--   (%i3) 2+3;
--   (%o3)           5
--
-- Note that the MaximaIOs for (%i1) had their input parts modified.
--
-- «MaximaBlock»  (to ".MaximaBlock")
MaximaBlock = Class {
  type = "MaximaBlock",
  __tostring = function (mb) return mb:struct():tostring() end,
  __index = {
    methodrect = function (mb,method)
        local bigrect = Rect {}
        for _,mio in ipairs(mb) do bigrect = bigrect / mio[method](mio) end
        return bigrect
      end,
    --
    namestr = function (mb) return mb.name or "<nil>" end,
    struct  = function (mb)
        return Rect {"",
                     format("(block %s)", mb:namestr())}
               / mb:methodrect("tostructrect")
      end,
    --
    ML = function (mb)
        return mb:methodrect("toMrect")
               / Rect {"%L",
		       format('%%L maximahead:sa("%s", "")', mb:namestr()),
                       "\\pu"}
      end,
    -- 
    ga = function (mb)
        return Rect {format("\\maximagavbox{0cm}{9cm}{%s}", mb:namestr())}
      end,
    --
    maximaboxes  = function (mb) return mb:methodrect("totexrect") end,
    maximaboxes1 = function (mb) return table.concat(mb:maximaboxes()) end,
    vbox = function (mb,vbox)
        return format("%s{%s}", vbox or "\\maximavbox", mb:maximaboxes1())
      end,
    sa = function (mb,altname)
        return format("\\sa{%s}{%s}", altname or mb:namestr(), mb:vbox())
      end,
  },
}

maximablock_test = MaximaBlock {
  maximaio_test1,
  maximaio_test2,
  maximaio_test3
}

-- «MaximaBlock-tests»  (to ".MaximaBlock-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima3.lua"
= maximablock_test
= maximablock_test:struct()
= maximablock_test:ML()
= maximablock_test:ga()
= maximablock_test:maximaboxes()
= maximablock_test:vbox()
= maximablock_test:sa()

--]]



--  ____        _ _ _   ___       _        __  __ ___ ___      
-- / ___| _ __ | (_) |_|_ _|_ __ | |_ ___ |  \/  |_ _/ _ \ ___ 
-- \___ \| '_ \| | | __|| || '_ \| __/ _ \| |\/| || | | | / __|
--  ___) | |_) | | | |_ | || | | | || (_) | |  | || | |_| \__ \
-- |____/| .__/|_|_|\__|___|_| |_|\__\___/|_|  |_|___\___/|___/
--       |_|                                                   
--
-- The class SplitIntoMIOs parses the lines of a "*maxima*" buffer and
-- uses a state machine to discard the initial lines and split the
-- other ones into "mio"s, i.e., into MaximaIO objects. For example,
-- suppose that our "*maxima*" buffer contained this,
--
--   Maxima 5.49
--   Distributed under the GNU GPL
--   (%i1) [2,
--          3];
--   (%o1)       [2,3]
--
-- and we saved that into a file, and we are using SplitIntoMIOs to
-- process the lines of that file. Then:
--
--   a) in its lines 1, 2 and 4 the "io character", or "ioc", is nil,
--   b) in the line 3 the ioc is "i",
--   c) in the line 5 the ioc is "o",
--   d) the initial "state" is nil.
--
-- Here's how the state machine handles all that...
--
--   e) in the lines 1 and 2 we have state==nil and ioc==nil; these
--      lines are discarded. Internally what happens there is that in
--      :addline_inner(...) these lines run the case associated with
--      "_->_", that just returns newstate=nil;
--
--   f) in the line 3 we have state==nil and ioc=="i". This runs the
--      case tr=="_->i", that runs :addmio(), then makes that line the
--      only element in the .i of that mio, and returns newstate="i";
--
--   g) in the line 4 we have state=="i" and ioc==nil; this runs the
--      case tr=="i->_", that pushes that line into the .ip of the
--      current mio, and keeps the state as "i"...
--
-- etc, etc, etc - the actions of the other lines are easy to
-- understand.
--
-- «SplitIntoMIOs»  (to ".SplitIntoMIOs")
SplitIntoMIOs = Class {
  type         = "SplitIntoMIOs",
  new          = function () return SplitIntoMIOs {mios=MaximaBlock{}} end,
  fromlines    = function (lines) return SplitIntoMIOs.new():addlines(lines) end,
  linestoblock = function (lines) return SplitIntoMIOs.fromlines(lines).mios end,
  __tostring   = function (sim) return sim:tostructrect():tostring() end,
  __index = {
    tostructrect = function (sim)
        local bigrect = Rect {}
        for i=1,#sim.mios do
          local leftrect  = Rect {format("mios[%d]: ", i)}
          local rightrect = MaximaIO(copy(sim.mios[i])):tostructrect()
          bigrect = bigrect / (leftrect .. rightrect)
        end
        return bigrect
      end,  
    addmio  = function (sim) table.insert(sim.mios, MaximaIO{}); return sim end,
    lastmio = function (sim) return sim.mios[#sim.mios] end,
    push    = function (sim,name,line) sim:lastmio():push(name,line); return sim end,
    splitline = function (sim,line)
        local ioc,n,body = line:match("^%(%%([io])([0-9]+)%) ?(.*)")
        if ioc
        then return ioc,n,body
        else return nil,nil,line -- if ioc==nil the whole line becomes the body
        end
      end,
    addline_inner = function (sim,state,ioc,line)    -- returns newstate
        local tr = (state or "_").."->"..(ioc or "_")
        if tr=="_->_" then                               return nil end
        if tr=="_->i" then sim:addmio():push("i", line); return "i" end
        if tr=="i->i" then sim:addmio():push("i", line); return "i" end
        if tr=="o->i" then sim:addmio():push("i", line); return "i" end
        if tr=="i->_" then sim         :push("ip",line); return "i" end
        if tr=="i->o" then sim         :push("o", line); return "o" end
        error("Bad transition: %s", tr)
      end,
    addline = function (sim,line)
        local ioc,n,body = sim:splitline(line)
        local state = sim.state
        local newstate = sim:addline_inner(state,ioc,line)
        sim.state = newstate
        return sim
      end,
    addlines = function (sim,lines)
        if type(lines)=="string" then lines = splitlines(lines) end
        for _,line in ipairs(lines) do sim:addline(line) end
        return sim
      end,
  },
}

splitintomios_test = Rect {
  "(%i1) /* block n-ary `=' */",
        "nary(\"=.\")$",
  "(%i2) a =. b =. c;",
  "(%o2)      a =. b =. c",
  "(%i3) /* block etc */",
        "2+3",
        " +4;",
  "(%o3)           9"
}

-- «SplitIntoMIOs-tests»  (to ".SplitIntoMIOs-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima3.lua"
sim = SplitIntoMIOs {mios={
  maximaio_test1,
  maximaio_test2,
  maximaio_test3,
}}

= sim
= sim:tostructrect()

sim = SplitIntoMIOs.fromlines(splitintomios_test)
= sim

--]]



--  ____        _ _ _   ___       _        ____  _            _        
-- / ___| _ __ | (_) |_|_ _|_ __ | |_ ___ | __ )| | ___   ___| | _____ 
-- \___ \| '_ \| | | __|| || '_ \| __/ _ \|  _ \| |/ _ \ / __| |/ / __|
--  ___) | |_) | | | |_ | || | | | || (_) | |_) | | (_) | (__|   <\__ \
-- |____/| .__/|_|_|\__|___|_| |_|\__\___/|____/|_|\___/ \___|_|\_\___/
--       |_|                                                           
--
-- «SplitIntoBlocks»  (to ".SplitIntoBlocks")
SplitIntoBlocks = Class {
  type          = "SplitIntoBlocks",
  new           = function () return SplitIntoBlocks {blocks={}} end,
  frombigblock  = function (bigblock) return SplitIntoBlocks.new():addmios(bigblock) end,
  splitbigblock = function (bigblock) return SplitIntoBlocks.frombigblock(bigblock).blocks end,
  fromlines     = function (lines)
      local bigblock = SplitIntoMIOs.linestoblock(lines)
      return SplitIntoBlocks.frombigblock(bigblock)
    end,
  __tostring = function (sib) return sib:tostructrect():tostring() end,
  __index = {
    tostructrect = function (sib)
        local bigrect = Rect {"Named blocks:"}
        for _,block in ipairs(sib.blocks) do
          bigrect = bigrect / block:struct()
        end
        return bigrect
      end,  
    --
    lastblock = function (sib) return sib.blocks[#sib.blocks] end,
    addmio_named = function (sib,newmio,blockname)
        local newblock = MaximaBlock {name=blockname, newmio}
        table.insert(sib.blocks, newblock)
      end,
    addmio_unnamed = function (sib,newmio)
        if not sib:lastblock() then return end  -- discard
        table.insert(sib:lastblock(), newmio)
      end,
    addmio = function (sib,mio)
        local newmio,blockname = mio:cleanblockname()
        if   blockname
        then sib:addmio_named  (newmio,blockname)
        else sib:addmio_unnamed(newmio)
        end
      end,
    addmios = function (sib,bigblock)
        for _,mio in ipairs(bigblock) do sib:addmio(mio) end
        return sib
      end,
    --
    MLs = function (sib)
        local f = function (block) return block:ML():tostring() end
        return mapconcat(f, sib.blocks, "\n\n")
      end,
    gas_in_one_slide = function (sib)
        local pre  = "\\scalebox{0.6}{\\def\\colwidth{9cm}\\firstcol{\n  "
        local mid  = "\n}\\def\\colwidth{9cm}\\anothercol{\n  "
        local post = "\n}}"
        local f    = function (block) return block:ga():tostring() end
        return pre .. mapconcat(f, sib.blocks, mid) .. post
      end,
    all_in_one_slide = function (sib)
        return sib:MLs() .. "\n\n" .. sib:gas_in_one_slide()
      end,
  },
}

splitintoblocks_test = Rect {
  "(%i0) discard_this$;",
  "(%i1) /* block foo */",
        "foo$",
  "(%i2) /* block bar */",
        "bar$",
  "(%i3) plic$"
}

-- «SplitIntoBlocks-tests»  (to ".SplitIntoBlocks-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima3.lua"
sim = SplitIntoMIOs  .fromlines(splitintoblocks_test)
sib = SplitIntoBlocks.fromlines(splitintoblocks_test)
= sim
= sib
= sib.blocks[1]
= sib.blocks[1].name
= sib.blocks[1]:ML()
= sib.blocks[1]:ga()
= sib:MLs()
= sib:gas_in_one_slide()
= sib:all_in_one_slide()

--]]



--  __  __            _                 _   _                _ 
-- |  \/  | __ ___  _(_)_ __ ___   __ _| | | | ___  __ _  __| |
-- | |\/| |/ _` \ \/ / | '_ ` _ \ / _` | |_| |/ _ \/ _` |/ _` |
-- | |  | | (_| |>  <| | | | | | | (_| |  _  |  __/ (_| | (_| |
-- |_|  |_|\__,_/_/\_\_|_| |_| |_|\__,_|_| |_|\___|\__,_|\__,_|
--                                                             
-- When Dednat7 processes a block of "%M"-lines like this one
--
--   %M (%i1) sin(x);
--   %M (%o1) \sin x
--
-- it simply saves those lines, minus the "%M"s, into the variable
-- "maximahead.lines". An "%M"-block is usually followed by an
-- "%L"-block and a \pu, like this:
--
--   %M (%i1) sin(x);
--   %M (%o1) \sin x
--   %L
--   %L maximahead:sa("foo", "")
--   \pu
--
-- and that "maximahead:sa("foo", "")" produces/outputs/runs this
-- LaTeX code:
--
--   \sa{foo}{\maximavbox{%
--     \maximablue{(\%i1)\ sin(x);}%
--     \maximared{(\%o1)\ }{}%
--     \maximared{}{\sin x}%
--     \maximared{}{}%
--     }}
--
-- Then running "\ga{foo}" retrieves that \maximavbox.
-- "\sa" and "\ga" are explained here:
--   (find-LATEX "edrx21.sty" "sa-and-ga")
--
-- «MaximaHead»  (to ".MaximaHead")
MaximaHead = Class {
  type    = "MaximaHead",
  __index = {
    sa = function (mh, name)
        local block = SplitIntoMIOs.linestoblock(maximahead.lines)
        output(block:sa(name))
      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_test = Rect {
  "(%i1) a,",
        "b;",
  "(%o1) ab",
  "(%i2) c$"
}


-- «MaximaHead-tests»  (to ".MaximaHead-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima3.lua"
output = print
maximahead.lines = maximahead_test
maximahead:sa("TEST", "")

bl = SplitIntoMIOs.linestoblock(maximahead.lines)
= bl
= bl:ML()
= bl:sa()

--]]


delete_all_before_first_block = function (bigstr)
    local pat = "^.-(%(%%i[0-9]+%)[ \t\n]+/%*)"
    return (bigstr:gsub(pat, "%1"))
  end


-- «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"
= bigstr
  bigstr = delete_all_before_first_block(bigstr)
= bigstr
  bl = SplitIntoMIOs.linestoblock(bigstr)
= bl
= bl:struct()
  bls = SplitIntoBlocks.fromlines(bigstr)
= bls
= bls.blocks[1]
= bls.blocks[1]:maximaboxes()
= bls.blocks[1]:sa()
= bls.blocks[1]:ga()
  o2 = bls: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: