Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
-- This file:
--   http://anggtwu.net/LUA/Und2D1.lua.html
--   http://anggtwu.net/LUA/Und2D1.lua
--          (find-angg "LUA/Und2D1.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
--
-- Supersedes:
--   (excp 30 "typing")
--   (exca    "typing")
--   (exca    "typing" "%L defub")
--   (find-LATEXgrep "grep --color=auto -nH --null -e defub *.tex *.sty *.lua")
--   (find-dn6 "underbrace2d.lua" "UB-head" "defub =")
--
-- (defun e  () (interactive) (find-angg "LUA/Und2D1.lua"))
-- (defun u1 () (interactive) (find-angg "LUA/Und2D1.lua"))
-- (defun u2 () (interactive) (find-angg "LUA/Und2D2.lua"))

require "Pratt1"    -- (find-angg "LUA/Pratt1.lua")

-- «.u8split»		(to "u8split")
-- «.u8split-tests»	(to "u8split-tests")
-- «.Grid»		(to "Grid")
-- «.Grid-tests»	(to "Grid-tests")
--   «.bigstr»		(to "bigstr")
-- «.Und2D»		(to "Und2D")
-- «.Und2D-tests»	(to "Und2D-tests")
--   «.show2-test»	(to "show2-test")


--         ___            _ _ _   
--  _   _ ( _ ) ___ _ __ | (_) |_ 
-- | | | |/ _ \/ __| '_ \| | | __|
-- | |_| | (_) \__ \ |_) | | | |_ 
--  \__,_|\___/|___/ .__/|_|_|\__|
--                 |_|            
--
-- «u8split»  (to ".u8split")
-- (find-angg "LUA/lua50init.lua" "strlen8")
-- (find-angg "LUA/lua50init.lua" "u8c_to_l1")
u8split = function (str, pat)
    local pat = pat or ".[\128-\191]*"
    local result = HTable {}
    for s in str:gmatch(pat) do table.insert(result, s) end
    return result
  end

-- «u8split-tests»  (to ".u8split-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Und2D1.lua"
foo = "a·b"
= foo
= #foo
= u8split(foo)
= u8split(foo, ".")

--]==]



--   ____      _     _ 
--  / ___|_ __(_) __| |
-- | |  _| '__| |/ _` |
-- | |_| | |  | | (_| |
--  \____|_|  |_|\__,_|
--                     
-- «Grid»  (to ".Grid")

Grid = Class {
  type = "Grid",
  from = function (lines)
      if type(lines) == "string" then lines = splitlines(lines) end
      lines = VTable(lines)
      local wd = 0
      local ht = #lines
      local grid = VTable {}
      for y=1,ht do
        local linechars = u8split(lines[y])
        wd = max(wd, #linechars)
        grid[y] = linechars
      end
      return Grid {lines=lines, wd=wd, ht=ht, grid=grid}
    end,
  __index = {
    yx  = function (gr,y,x) return gr.grid[y][x] or "" end,
    yxx = function (gr,y,x0,x1)
        local f = function (x) return gr:yx(y,x) end
        return mapconcat(f, seq(x0,x1))
      end,
    blank  = function (gr,y,x) local c=gr:yx(y,x); return c==" " or c=="" end,
    ranges = function (gr,y)
        local ranges = Ranges {}
        local blank = function (x) return gr:blank(y,x) end
        local x=1
        while x<gr.wd do
          while blank(x) and x<gr.wd do x=x+1 end
          if not blank(x) then
            local a,b=x,x
            while b<gr.wd and not blank(b+1) do b=b+1 end
            table.insert(ranges, Range {a=a, b=b})
            x = b + 1
          end
        end
        return ranges
      end,
  },
}

-- «Grid-tests»  (to ".Grid-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Und2D1.lua"
gr0 = Grid.from "abc\nd\nefgh"
= gr0
= gr0.grid
= gr0.wd
= gr0.ht
= gr0.lines
PP(gr0:yx(1,1))
PP(gr0:yx(1,3))
PP(gr0:yx(1,5))
PP(gr0:yxx(3,2,3))

gr0 = Grid.from(bigstr)
= gr0.lines
= gr0:ranges(2)
= gr0:ranges(4)
= gr0.grid[1]    -- note the \cdot

--]==]


-- «bigstr»  (to ".bigstr")
--
bigstr = [=[
  f(t ) = 45 + ((t -23)/(34-23))·56
    --           --
    23           23
  ----           -----
   45              0
                ---------------
                        0
               --------------------- 
                          0
          --------------------------
                    45+0
]=]


--  _   _           _ ____  ____  
-- | | | |_ __   __| |___ \|  _ \ 
-- | | | | '_ \ / _` | __) | | | |
-- | |_| | | | | (_| |/ __/| |_| |
--  \___/|_| |_|\__,_|_____|____/ 
--                                
-- «Und2D»  (to ".Und2D")

Und2D = Class {
  type    = "Und2D",
  from = function (lines)
      local grid = Grid.from(lines)
      local wd,ht = grid.wd,grid.ht
      local ranges = Ranges {}
      for x=1,wd do
        table.insert(ranges, Range{a=x, b=x, tex=grid:yx(1,x)})
      end
      return Und2D {grid=grid, wd=wd, ht=ht, ranges=ranges}
    end,
  __index = {
    uptex = function (u,a,b)
        local i,j = u.ranges:abtoij(a, b)
        local f = function (k) return u.ranges[k].tex end
        return mapconcat(f, seq(i,j))
      end,
    downtex = function (u,y,a,b)
        return u.grid:yxx(y,a,b)
      end,
    tex = function (u)
        return u:uptex(1, u.wd)
      end,
    --
    packab0 = function (u,ysub,a,b)
        local i,j = u.ranges:abtoij(a, b)
        local utex = u:uptex(a, b)
        local dtex = u:downtex(ysub, a, b)
        u.ranges:packij(i, j)
        local newrange = u.ranges[i]
        return utex,dtex,newrange
      end,
    packab = function (u,ysub,a,b)
        local utex,dtex,newrange = u:packab0(ysub, a, b)
        local tex = format("\\und{%s}{%s}", bitrim(utex), bitrim(dtex))
        newrange.tex = tex
      end,
    barranges = function (u,ybar)
        return u.grid:ranges(ybar)
      end,
    packbar = function (u, ybar, range)
        local ysub = ybar + 1
        local a,b = range.a,range.b
        u:packab(ysub, a, b)
      end,
    packbars = function (u, ybar)
        local ranges = u:barranges(ybar)
        for _,range in ipairs(ranges) do
          u:packbar(ybar, range)
        end
      end,
    packallbars = function (u)
        for ybar=2,u.ht-1,2 do
          u:packbars(ybar)
        end
        return u
      end,
  },
}

-- «Und2D-tests»  (to ".Und2D-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Und2D1.lua"

u = Und2D.from(bigstr)
= u
= u.grid.lines
= u.wd
= u.ht
= u.ranges
= u:uptex(3,7)
= u:downtex(3,5,6)

= u.grid:ranges(2)
= u.grid:ranges(4)
  utex,dtex,newrange = u:packab0(3, 18, 19)
= utex,dtex,newrange

u = Und2D.from(bigstr)
= u:uptex(1, u.wd)
= u.grid:ranges(2)
  u:packab(3, 18, 19)
= u.ranges
= u.ranges[18]
PP(u.ranges[18])
= u:uptex(1, u.wd)

u = Und2D.from(bigstr)
= u.grid.lines
= u:barranges(2)
= u:barranges(4)
= u:barranges(2)[2]
  range = u:barranges(2)[2]
= range
PP(range)
= u:packbar(2, range)
= u:uptex(1, u.wd)

u = Und2D.from(bigstr)
= u.grid.lines
= u:packbars(2)
= u:uptex(1, u.wd)
= u:packbars(4)
= u:uptex(1, u.wd)

--]==]




-- «show2-test»  (to ".show2-test")
--[==[
* (show2-use "~/LATEX/Show2.tex")
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Und2D1.lua"
loadshow2()
usepackages.edrx21 = true
defs.und = [=[ \def\und#1#2{\underbrace{#1}_{#2}} ]=]

  ut = Und2D.from(bigstr):packallbars():tex()
= ut

= ut:show0 {em=1, scale=1.5}
= ut:show  {em=1, scale=1.5}
* (etv)

--]==]




--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Und2D1.lua"
bigstr2 = [=[
  f(t ) = ef
    --
    ab
  ----
  c+d
]=]

Und2D.__index.wrapUP   = function (u,str) return str end
Und2D.__index.wrapDOWN = function (u,str) return str end
Und2D.__index.wrapTEX  = function (u,str) return str end

Und2D.__index.uptex = function (u,a,b)
    local i,j = u.ranges:abtoij(a, b)
    local f = function (k) return u.ranges[k].tex end
    return u:wrapUP(mapconcat(f, seq(i,j)))
  end
Und2D.__index.downtex = function (u,y,a,b)
    return u:wrapDOWN(u.grid:yxx(y,a,b))
  end
Und2D.__index.downtex = function (u,y,a,b)
    return u:wrapTEX(u:uptex(1, u.wd))
  end

  ut = Und2D.from(bigstr2):packallbars():tex()
= ut

Und2D.__index.wrapUP   = function (u,str) return "\\UP{"  ..str.."}" end
Und2D.__index.wrapDOWN = function (u,str) return "\\DOWN{"..str.."}" end
Und2D.__index.wrapTEX  = function (u,str) return "\\TEX{" ..str.."}" end

  ut = Und2D.from(bigstr2):packallbars():tex()
= ut



function (u,a,b) end



    downtex = function (u,y,a,b)


--]==]










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