diff options
Diffstat (limited to 'rst_helpers.lua')
-rw-r--r-- | rst_helpers.lua | 293 |
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 |