Warning: this is an htmlized version!
The original is across this link,
and the conversion rules are here.
-- rect.lua: concatenable ascii rectangles, for building trees in ascii.
-- This file:
-- http://angg.twu.net/dednat6/rect.lua
-- http://angg.twu.net/dednat6/rect.lua.html
--  (find-angg        "dednat6/rect.lua")
--
-- Example:
--
--   > = synttorect {[0]="+", {[0]="*", "2", "3"}, {[0]="*", "4", "5"}}
--   +_____.
--   |     |
--   *__.  *__.
--   |  |  |  |
--   2  3  4  5

-- «.Rect»		(to "Rect")
-- «.Rect-tests»	(to "Rect-tests")
-- «.syntotorect»	(to "syntotorect")
-- «.synttorect-tests»	(to "synttorect-tests")
-- «.dedtorect»		(to "dedtorect")
-- «.dedtorect-tests»	(to "dedtorect-tests")



--  ____           _   
-- |  _ \ ___  ___| |_ 
-- | |_) / _ \/ __| __|
-- |  _ <  __/ (__| |_ 
-- |_| \_\___|\___|\__|
--                     
-- This is a total rewrite (different data structures, methods, etc) of:
-- (find-dn6 "gab.lua" "Rect")
-- «Rect» (to ".Rect")

copy = function (A)
    local B = {}
    for k,v in pairs(A) do B[k] = v end
    setmetatable(B, getmetatable(A))
    return B
  end

torect = function (o)
    if otype(o) == "Rect" then return o end
    if type(o) == "string" then return Rect.new(o) end
    error()
  end

Rect = Class {
  type = "Rect",
  new  = function (str) return Rect(splitlines(str)) end,
  rep  = function (str, n) local r=Rect{}; for i=1,n do r[i]=str end; return r end,
  __tostring = function (rect) return rect:tostring() end,
  __concat = function (r1, r2) return torect(r1):concat(torect(r2)) end,
  __index = {
    tostring = function (rect) return table.concat(rect, "\n") end,
    copy = function (rect) return copy(rect) end,
    width = function (rect) return foldl(max, 0, map(string.len, rect)) end,
    push1 = function (rect, str) table.insert(rect, 1, str); return rect end,
    push2 = function (rect, str1, str2) return rect:push1(str2):push1(str1) end,
    pad0  = function (rect, y, w, c, rstr)
        rect[y] = ((rect[y] or "")..(c or " "):rep(w)):sub(1, w)..(rstr or "")
        return rect
      end,
    lower = function (rect, n, str)
        for i=1,n do rect:push1(str or "") end
        return rect
      end,
    concat = function (r1, r2, w, dy)
        r1 = r1:copy()
        w = w or r1:width()
        dy = dy or 0
        for y=#r1+1,#r2+dy do r1[y] = "" end
        for y=1,#r2 do r1:pad0(y+dy, w, nil, r2[y]) end
        return r1
      end,
    prepend = function (rect, str) return Rect.rep(str, #rect)..rect end,
    --
    syn1 = function (r1, opname) return r1:copy():push2(opname or ".", "|") end,
    synconcat = function (r1, r2)
        return r1:copy():pad0(1, r1:width()+2, "_")..r2:copy():push2(".", "|")
      end,
    --
    dedconcat = function (r1, r2)
        local w = r1:width() + 2
        if #r1 <  #r2 then return r1:copy():lower(#r2-#r1):concat(r2, w) end
        if #r1 == #r2 then return r1:copy():concat(r2, w) end
        if #r1  > #r2 then return r1:copy():concat(r2, w, #r1-#r2) end
      end,
    dedroot = function (rect, str)
        table.insert(rect, ""); table.insert(rect, str); return rect
      end,
    dedbar = function (rect, c, label)
        local abovebar, belowbar = rect[#rect-2], rect[#rect]
        local w = max(#(abovebar or ""), #belowbar)
        rect:pad0(#rect-1, w, c or "-", label)
        return rect
      end,
  },
}

-- «Rect-tests» (to ".Rect-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "rect.lua"

r = Rect.new "a\nbb\nccc"
= r
PP(r)
= r:width()
= r:copy():pad0(1, 4, nil, "d")
= r:copy():pad0(1, 4, "_", "d")
= r:copy():push2("op", "|")
= r:copy():push2("op", "|"):pad0(1, r:width()+1, "_")..r:copy():push2(".", "|")
= "This => "..r.." <="

-- Low-level tests for synconcat, dedconcat, dedroot, dedbar
= torect("2"):syn1("*"):synconcat(torect("3"))
= torect("a"):dedconcat(torect("b"))
= torect("a"):dedconcat(torect("b")):dedroot("c"):dedbar("-", "foo")
= torect("a"):dedconcat(torect("bbbbbb")):dedroot("c"):dedbar("-", "foo")
= torect("a"):dedconcat(torect("b")):dedroot("cccccc"):dedbar("-", "foo")

* (ex "rect-0")

--]]



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

synttorect = function (o)
    if type(o) == "string" then return torect(o) end
    if type(o) == "table" then
      local r = synttorect(o[1]):syn1(o[0])
      for i=2,#o do r = r:synconcat(synttorect(o[i])) end
      return r
    end
    error()
  end

-- «synttorect-tests» (to ".synttorect-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "rect.lua"
tree = {[0]="+", {[0]="*", "2", "3"}, {[0]="*", "4", "5"}}
tree = {[0]="+", {[0]="*", "2", "3"}, {[0]="*", "4", "5"}, bar="=", label="hi"}
= synttorect(tree)
= dedtorect (tree)

* (ex "rect-synt")

--]]


--      _          _ _                      _   
--   __| | ___  __| | |_ ___  _ __ ___  ___| |_ 
--  / _` |/ _ \/ _` | __/ _ \| '__/ _ \/ __| __|
-- | (_| |  __/ (_| | || (_) | | |  __/ (__| |_ 
--  \__,_|\___|\__,_|\__\___/|_|  \___|\___|\__|
--                                              
-- «dedtorect» (to ".dedtorect")
dedtorect = function (o)
    if type(o) == "string" then return torect(o) end
    if type(o) == "table" then
      if #o==0 and not o.bar and not o.label then return torect(o[0]) end
      local r
      if #o > 0 then
        r = dedtorect(o[1])
        for i=2,#o do r = r:dedconcat(dedtorect(o[i])) end
      else
        r = torect("\n")
      end
      return r:dedroot(o[0] or "?"):dedbar(o.bar or "-", o.label)
    end
    error()
  end

-- «dedtorect-tests» (to ".dedtorect-tests")
-- See: (find-dn6 "treesegs.lua" "allsegments-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "rect.lua"
tree = { [0]="P&Q->P&R", label="1", 
         { [0]="P&R",
           { [0]="P", "[P&Q]^1" },
           { [0]="R", {[0]="Q", "[P&Q]^1"}, "Q->R" }
         } }                                        
= dedtorect(tree)
tree = {[0]="P&Q->P&Q", label="1", {[0]="P&R", "P", {[0]="R", bar=":", {[0]="Q", "[P&Q]^1"}}}}
= dedtorect(tree)
PP(tree)

tree = {[0]="P&Q->Q&P", bar="=", "?"}
= dedtorect(tree)
tree = {[0]="P&Q->Q&P", bar="="}
= dedtorect(tree)

* (ex "rect-ded")

--]]



--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "rect.lua"

--]]


-- Local Variables:
-- coding: raw-text-unix
-- End: