summaryrefslogtreecommitdiff
path: root/rst_helpers.lua
diff options
context:
space:
mode:
Diffstat (limited to 'rst_helpers.lua')
-rw-r--r--rst_helpers.lua293
1 files changed, 293 insertions, 0 deletions
diff --git a/rst_helpers.lua b/rst_helpers.lua
new file mode 100644
index 0000000..e55112d
--- /dev/null
+++ b/rst_helpers.lua
@@ -0,0 +1,293 @@
+#!/usr/bin/env texlua
+--------------------------------------------------------------------------------
+-- FILE: rst_helpers.lua
+-- USAGE: ./rst_helpers.lua
+-- DESCRIPTION: Complement to the reStructuredText parser
+-- AUTHOR: Philipp Gesang (Phg), <megas.kapaneus@gmail.com>
+-- VERSION: 1.0
+-- CREATED: 07/09/10 01:03:08 CEST
+--------------------------------------------------------------------------------
+--
+
+local utf = unicode.utf8
+local P, R, S, V, match
+ = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.match
+
+local C, Carg, Cb, Cc, Cg, Cmt, Cp, Cs, Ct
+ = lpeg.C, lpeg.Carg, lpeg.Cb, lpeg.Cc, lpeg.Cg, lpeg.Cmt, lpeg.Cp, lpeg.Cs, lpeg.Ct
+
+local helpers = {}
+helpers.table = {}
+helpers.cell = {}
+
+local patterns = {}
+
+do
+ local p = patterns
+ p.dash = P"-"
+ p.equals = P"="
+ p.plus = P"+"
+ p.bar = P"|"
+ p.eol = P"\n"
+ p.last = -P(1)
+
+ p.celldelim = p.bar + p.plus
+ p.cellcontent = (1 - p.celldelim)
+ p.cell = p.celldelim * C((1 - p.celldelim)^1) * #p.celldelim
+ p.cell_line = p.plus * p.dash^1 * #p.plus
+ p.dashesonly = p.dash^1 * p.last
+
+ p.cells = P{
+ [1] = "cells",
+ cells = p.celldelim
+ * (C(V"in_cell")
+ * (V"matchwidth" * C(V"in_cell")) ^1),
+
+ in_cell = p.cellcontent^1
+ + (p.dash - p.cellcontent)^1,
+
+ matchwidth = Cmt(C(p.celldelim) * Carg(1), function(s,i,del, layout)
+ --print("~~~~~~~~~~~~~~ NEXT MATCH ~~~~~~~~~~~~~~")
+ local pos = 1
+ local lw = layout.widths
+ for n=1, #lw do
+ pos = pos + lw[n] + 1
+ --print(">",pos,i-1,i-1==pos)
+ if (i - 1) == pos then return true end
+ end
+ return false
+ end),
+ }
+
+ p.sep_line = p.plus * (p.dash^1 * p.plus)^1 * p.last
+ p.sep_head = p.plus * (p.equals^1 * p.plus)^1 * p.last
+
+ p.sep_part = ((1 - p.cell_line)^0 * p.cell_line) - p.sep_line
+
+ p.new_row = p.sep_line + p.sep_head + p.sep_part
+
+ p.whitespace = S" \t\v\r\n"^1
+ p.strip = p.whitespace^0 * C((1 - (p.whitespace * p.last))^1) * p.whitespace^0 * p.last
+end
+
+function helpers.cell.create(raw, n_row, n_col, continue)
+ local p = patterns
+ local cell = {}
+ cell.stripped = raw and p.strip:match(raw) or ""
+ cell.content = raw
+ cell.width = raw and utf.len(raw) or 0
+ cell.bytes = raw and #raw or 0
+ cell.variant = "normal" -- [normal|separator|y_continue|x_continue]
+ cell.pos = {}
+ cell.pos.x = n_col
+ cell.pos.y = n_row
+ cell.span = {}
+ cell.span.x = 1
+ cell.span.y = 1
+ cell.parent = nil
+ return cell
+end
+
+function helpers.cell.get_x_span(content, layout, init)
+ --print(#content,">"..content.."<")
+ --print(layout.widths[init],">"..layout.slices[init].."<")
+ local acc = 0
+ local lw = layout.widths
+ for n=init, #lw do
+ acc = acc + lw[n] + 1
+ --print(n, layout.slices[n], acc)
+ if utf.len(content) + 1 == acc then
+ return n - init
+ end
+ end
+ return false
+end
+
+
+-- Extending a cell by 1 cell horizontally.
+function helpers.cell.add_x (cell)
+ cell.span.x = cell.span.x + 1
+end
+
+
+local function set_layout (line)
+ local p = patterns
+ local layout = {}
+ local slice = Ct((p.plus * C(p.dash^1) * #p.plus)^1)
+
+ layout.widths = {}
+ layout.slices = {}
+ for n, elm in ipairs(slice:match(line)) do
+ layout.widths[n] = #elm
+ layout.slices[n] = elm
+ end
+ return layout
+end
+
+function helpers.table.create(raw)
+ local self = {}
+ self.rows = {}
+
+ local p = patterns
+
+ self.resolve_parent = function(row, col)
+ print(row, col)
+ local cell = self.rows[row][col]
+ local par_row, par_col
+ if cell.parent then
+ par_row, par_col = self.resolve_parent(cell.parent.y, cell.parent.x)
+ else
+ return par_row, par_col
+ end
+ end
+
+ self.__init = function()
+ local hc = helpers.cell
+ self.layout = set_layout(raw[1])
+ local rowcount = 0
+
+ -- first get the correct horizontal spans
+ local next_is_new_row = true
+ for n, line in ipairs(raw) do
+ -- caching the test results
+ local sepline = p.sep_line:match(line)
+ local sephead = p.sep_head:match(line)
+ local seppart = p.sep_part:match(line)
+ local newrow = sepline or sephead or seppart
+
+ if newrow and n > 1 then
+ if sephead then
+ self.has_head = true
+ end
+ rowcount = rowcount + 1
+ end
+
+ if not (sepline or
+ sephead) then
+ local row = {}
+ row.newrow = (newrow or next_is_new_row) and true or false
+ next_is_new_row = false
+ local sl = self.layout
+ local splitted = {p.cells:match(line, 1, sl)}
+ local pos_layout, pos_line = 1, 1
+ local last = nil
+ local ignore = {}
+ ignore.n, ignore.parent = 0, nil
+ while pos_layout <= #sl.slices do
+ --local splitpos = splitted[pos_line]
+ local splitpos = splitted[pos_layout]
+ local width_layout = sl.widths[pos_layout]
+ local span = 1
+ local this
+ if ignore.n > 0 then
+ ignore.n = ignore.n - 1
+ this = hc.create(false, n, pos_layout, true)
+ row[pos_layout] = this
+ this.parent = ignore.parent
+ else
+ local width_cell = utf.len(splitpos)
+ if width_cell > width_layout then
+ --print(splitpos, width_cell, sl.slices[pos_layout], width_layout)
+ -- check the horizontal span
+ span = span + hc.get_x_span(splitpos, sl, pos_layout)
+ end
+ pos_line = pos_line + span
+ this = hc.create(splitpos, n, pos_layout, false)
+ if p.dashesonly:match(splitpos) then
+ this.variant = "separator"
+ end
+ this.span.x = span
+ last = this
+ row[pos_layout] = this
+ ignore.n = span - 1
+ ignore.parent = ignore.n > 0 and { y = rowcount, x = pos_layout } or nil
+ end
+ pos_layout = pos_layout + 1
+ --print(">",this.pos.y,this.pos.x,this.span.y,this.span.x)
+ --if this.span.y > 1 then
+ --print(">"..this.content.."<")
+ --end
+ end
+ self.rows[#self.rows+1] = row
+ --print(#self.rows.."<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<")
+ --for i,j in ipairs(row) do print(i,j.content) end
+ --print(row.newrow)
+ else -- separator
+ next_is_new_row = true
+
+ end
+ --print(string.format("[t-%2s,%2s]> %s", n, m, cell))
+ end
+ --print("rc = "..rowcount, "nr = "..#self.rows)
+ self.rowcount = rowcount
+
+ if self.rowcount < #self.rows then -- some cells span vertically
+ local has_partsep = function(row)
+ for n, cell in ipairs(row) do
+ if cell.variant == "separator" then
+ return true
+ end
+ end
+ return false
+ end
+
+ local dont_do_next = false
+ for nr,row in ipairs(self.rows) do
+ local ps = has_partsep(row)
+
+ row.ignore = ps and true or false
+ if ps then
+ self.rows[nr+1].newrow = true
+ end
+ if (not row.newrow or ps) and not dont_do_next then
+ --print(">>>>>>>>>> NEXT <<<<<<<<<<<<")
+ --print(row.newrow and has_partsep(row))
+ -- continues last row either fully or partially
+ for nc, cell in ipairs(row) do
+ --print(nr, nc, cell.content)
+ if cell.content == false then
+ -- empty cell
+ elseif cell.variant ~= "separator" then
+ local par_row, par_col
+ if cell.parent then
+ par_row, par_col = self.resolve_parent(cell.parent.y, cell.parent.x)
+ --print("old parent: ", par_row, par_col)
+ else -- no previous span, setting parent to preceding row
+ par_row, par_col = nr -1, nc
+ --print("new parent: ", par_row, par_col)
+ end
+
+ print (nr, nc, cell.content, cell.parent, par_row, par_col)
+ local parent = self.rows[par_row][par_col]
+ --parent.span.y = parent.span.y + 1
+ parent.content = parent.content .. cell.content
+ parent.stripped = parent.stripped .. " " .. cell.stripped
+
+ if ps then
+ local successor = self.rows[nr+1][nc]
+ successor.parent = { x = par_col, y = par_row }
+ parent.span.y = parent.span.y + 1
+ parent.content = parent.content .. successor.content
+ parent.stripped = parent.stripped .. " " .. successor.stripped
+ dont_do_next = true
+ else
+ dont_do_next = false
+ end
+ print(cell.content, parent.content)
+ --add_y(cell)
+ end
+ end
+ elseif dont_do_next then
+ --row.ignore = true
+ dont_do_next = false
+ end
+ end
+ end -- vertical span handler
+ end -- end __init
+
+ self.__init()
+ return self
+end
+
+
+return helpers