summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Gesang <pgesang@ix.urz.uni-heidelberg.de>2010-09-07 18:32:22 +0200
committerPhilipp Gesang <pgesang@ix.urz.uni-heidelberg.de>2010-09-07 18:32:22 +0200
commitd7996cadc2e117cc163291abe953dec15cee6826 (patch)
treef6fc5aedfa5a9e2056140e42b16c92c8e2a1f3ec
parentf87e85ad1dd07bfb4f3c07f2571f5af6401733c9 (diff)
downloadcontext-rst-d7996cadc2e117cc163291abe953dec15cee6826.tar.gz
revised table implementation. helper module.
-rw-r--r--rst_context.lua49
-rw-r--r--rst_helpers.lua293
-rw-r--r--rst_parser.lua135
3 files changed, 397 insertions, 80 deletions
diff --git a/rst_context.lua b/rst_context.lua
index 7603509..fb69dfd 100644
--- a/rst_context.lua
+++ b/rst_context.lua
@@ -467,24 +467,59 @@ function rst_context.table (str)
]]
end
-function rst_context.grid_table (str)
- return [[
+function rst_context.grid_table (tab)
+ local head = [[
\\setupTABLE[c][first] [background=color, backgroundcolor=grey, style=\tt]
-\\setupTABLE[c][each] [frame=off]
-\\setupTABLE[r][each] [frame=off]
+\\setupTABLE[c][each] [frame=on]
+\\setupTABLE[r][each] [frame=on]
\\bTABLE[split=repeat,option=stretch]
\\bTABLEhead
\\bTR
- \\bTH Option \\eTH
- \\bTH Description \\eTH
+ \\bTH first \\eTH
+ \\bTH second \\eTH
+ \\bTH third \\eTH
+ \\bTH fourth \\eTH
\\eTR
\\eTABLEhead
\\bTABLEbody
-]] .. str .. [[
+]]
+ local tail = [[
\\eTABLEbody
\\eTABLE
]]
+ local test = ""
+ for i,r in ipairs(tab.rows) do
+ --if not r.ignore then
+ if r.newrow and not r.ignore then
+ --if r.newrow then
+ --test = test .. string.format("%2s>%s\n", i, #j)
+ --print(i, unpack(j))
+ local row = [[\\bTR]]
+ for n,c in ipairs(r) do
+ if not c.parent then
+ local celltext = c.stripped
+ if c.span.x or c.span.y then
+ local span_exp = "["
+ if c.span.x then
+ span_exp = span_exp .. "nc=" .. c.span.x .. ","
+ end
+ if c.span.y then
+ span_exp = span_exp .. "nr=" .. c.span.y
+ end
+ celltext = span_exp .. "] " .. celltext
+
+ end
+
+ row = row .. "\n " .. [[\\bTC ]] .. celltext .. [[\\eTC]]
+ --print(c.parent)
+ end
+ end
+ test = test .. row .. "\n" .. [[\\eTR]] .. "\n"
+ end
+ end
+ --return head .. test .. tail
+ return head .. test .. tail
end
function rst_context.table_row (tab)
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
diff --git a/rst_parser.lua b/rst_parser.lua
index 6630767..343b45c 100644
--- a/rst_parser.lua
+++ b/rst_parser.lua
@@ -11,11 +11,12 @@
--------------------------------------------------------------------------------
--
-require "lpeg"
+--require "lpeg"
rst = require "rst_context"
+helpers = require "rst_helpers"
-local rst_debug = true
+local rst_debug = false
local warn = function(str, ...)
if not rst_debug then return false end
@@ -54,7 +55,7 @@ tracklists.bullets.max = 0
tracklists.lastbullet = ""
tracklists.roman_cache = {} -- storing roman numerals that were already converted
tracklists.currentindent = "" -- used in definition lists and elsewhere
-tracklists.currentlayout = {} -- table layout
+tracklists.currentwidth = 0-- table layout
local enclosed_mapping = {
["'"] = "'",
@@ -221,16 +222,18 @@ local parser = P{
-- Grid table
--------------------------------------------------------------------------------
- grid_table = Cs(V"gt_first_row"
+ grid_table = Ct(V"gt_first_row"
* V"gt_other_rows")
* V"blank_line"^1
- / rst.grid_table
+ --/ rst.grid_table
+ / function(tab)
+ return rst.grid_table(helpers.table.create(tab))
+ end
,
gt_first_row = V"gt_setindent"
- * V"gt_setlayout"
+ * C(V"gt_sethorizontal")
* V"eol"
- / ""
,
--gt_setindent = Cg(V"space"^0, "tableindent"),
@@ -243,18 +246,12 @@ local parser = P{
gt_layoutmarkers = V"table_intersection" + V"table_hline" + V"table_header_hline",
- gt_setlayout = Cmt(V"gt_layoutmarkers"^3, function (s, i, layout)
- --warn("tab-l", layout)
- local l = {}
- for n, dimension in ipairs(string.explode(layout, "++")) do
- l[n] = #dimension
- end
- l["length"] = #layout
- warn("tab-l", unpack(l))
- tracklists.currentlayout = l
- return true
- end)
- ,
+ gt_sethorizontal = Cmt(V"gt_layoutmarkers"^3, function (s, i, width)
+ warn("tab-h", "width", "true", #width, "set", i)
+ tracklists.currentwidth = #width
+ return true
+ end)
+ ,
gt_other_rows = V"gt_head"^-1
* V"gt_body"
@@ -262,63 +259,55 @@ local parser = P{
--gt_matchindent = Cmt(V"space"^0 * Cb"tableindent", function (s, i, this, matchme)
gt_matchindent = Cmt(V"space"^0, function (s, i, this)
- local matchme = tracklists.currentindent
- warn("tab-m", this == matchme, #this, #matchme, i)
- return this == matchme
- end)
- ,
+ local matchme = tracklists.currentindent
+ warn("tab-m", "indent", #this == #matchme, #this, #matchme, i)
+ return #this == #matchme
+ end)
+ ,
- --gt_cell = Cmt(V"gt_content_cell" + V"gt_line_cell", function (s, i, cell)
- --print("NEXT CELL:",cell)
- --return true
- --end),
- gt_cell = C(V"gt_content_cell" + V"gt_line_cell"),
+ gt_cell = (V"gt_content_cell" + V"gt_line_cell")
+ * (V"table_intersection" + V"table_vline")
+ ,
- gt_content_cell = (V"table_vline" + V"table_intersection")
- * C((1 - V"table_vline" - V"table_intersection" - V"eol")^1),
+ gt_content_cell = ((1 - V"table_vline" - V"table_intersection" - V"eol")^1),
- gt_line_cell = V"table_intersection"
- --* C((V"table_hline" - V"table_intersection")^1)
- * C(V"table_hline"^1)
- ,
+ gt_line_cell = V"table_hline"^1,
- gt_contentrow = Ct(V"gt_matchindent"
- * V"gt_cell"^1
- * (V"table_vline" + V"table_intersection")
- * V"eol"
- )
- / rst.table_row
+ gt_contentrow = V"gt_matchindent"
+ * C((V"table_intersection" + V"table_vline")
+ * V"gt_cell"^1)
+ * V"whitespace"^-1 * V"eol"
,
- gt_body = V"gt_row"^1,
+ gt_body = ((V"gt_contentrow" - V"gt_bodysep")^1 * V"gt_bodysep")^1,
- gt_row = (V"gt_contentrow" - V"gt_bodysep")^1
- * Cmt(V"gt_bodysep", function(s,i,str)print(str)return true end),
+ --gt_row = (V"gt_contentrow" - V"gt_bodysep")^1
+ --* C(V"gt_bodysep")
+ --,
gt_bodysep = V"gt_matchindent"
- * Cmt(V"table_intersection"
- * (V"table_hline"^1 * V"table_intersection")^1, function(s, i, separator)
- warn("tab-s", #separator, #separator == tracklists.currentlayout.length, "",i)
- local l = {}
- for n, dimension in ipairs(string.explode(separator, "++")) do
- l[n] = #dimension
- end
- l["length"] = #separator
- --return l == tracklists.currentlayout
- return l.length == tracklists.currentlayout.length
- end)
- * V"eol"
+ * C(Cmt(V"table_intersection"
+ * (V"table_hline"^1 * V"table_intersection")^1, function(s, i, separator)
+ local matchme = tracklists.currentwidth
+ warn("tab-m", "body", #separator == matchme, #separator, matchme, i)
+ return #separator == matchme
+ end))
+ * V"whitespace"^-1 * V"eol"
,
gt_head = V"gt_contentrow"^1
- * Cmt(V"gt_headsep", function(s,i,str)print(str)return true end)
+ * V"gt_headsep"
,
gt_headsep = V"gt_matchindent"
- * V"table_intersection"
- * (V"table_header_hline"^1 * V"table_intersection")^1
- * V"eol"
+ * C(Cmt(V"table_intersection"
+ * (V"table_header_hline"^1 * V"table_intersection")^1, function(s, i, separator)
+ local matchme = tracklists.currentwidth
+ warn("tab-s", "head", #separator == matchme, #separator, matchme, i)
+ return #separator == matchme
+ end))
+ * V"whitespace"^-1 * V"eol"
,
@@ -341,7 +330,7 @@ local parser = P{
return true
end) / ""
* -V"attrib_dash"
- * V"text_elements"^1
+ * V"text_element"^1
* V"eol"
,
@@ -351,7 +340,7 @@ local parser = P{
return tracklists.currentindent == indent
end) / ""
* -V"attrib_dash"
- * V"text_elements"^1
+ * V"text_element"^1
* V"eol"
,
@@ -366,7 +355,7 @@ local parser = P{
t.currentindent = ret and indent or t.currentindent
return ret
end) / ""
- * V"text_elements"^1
+ * V"text_element"^1
* V"eol"
,
@@ -375,7 +364,7 @@ local parser = P{
indent, tracklists.currentindent, i)
return utf.len(tracklists.currentindent) == #indent
end) / ""
- * V"text_elements"^1
+ * V"text_element"^1
* V"eol"
,
@@ -418,7 +407,7 @@ local parser = P{
* V"line_block_line"
,
- line_block_line = Cs(V"text_elements"^1
+ line_block_line = Cs(V"text_element"^1
* V"line_block_cont"^0
* V"eol")
/ rst.line_block_line
@@ -429,7 +418,7 @@ local parser = P{
warn("lbk-c", #spaces, #tracklists.currentindent, spaces, tracklists.currentindent, i)
return #spaces >= #tracklists.currentindent
end) / ""
- * V"text_elements"^1
+ * V"text_element"^1
,
--------------------------------------------------------------------------------
@@ -532,12 +521,12 @@ local parser = P{
option_desc_single = V"space"^2
--* V"rest_of_line"
- * V"text_elements"^1
+ * V"text_element"^1
* V"eol",
option_desc_more = V"space"^2
--* V"rest_of_line"
- * V"text_elements"^1
+ * V"text_element"^1
* V"eol"
* V"indented_lines"
* (V"blank_line" * V"indented_lines")^0,
@@ -586,7 +575,7 @@ local parser = P{
field_name = (V"escaped_colon" + (1 - V"colon"))^1,
- field_body = C(V"text_elements"^1 * V"eol"
+ field_body = C(V"text_element"^1 * V"eol"
* V"indented_lines"^-1),
--------------------------------------------------------------------------------
@@ -850,11 +839,11 @@ local parser = P{
--paragraph = -(V"double_dot" + V"double_underscore") -- + V"bullet_indent")
paragraph = -V"punctuation"
- * Cs((V"text_elements" + (V"eol" - V"endpar"))^1)
+ * Cs((V"text_element" + (V"eol" - V"endpar"))^1)
* V"endpar"
/ rst.paragraph,
- text_elements = V"included_literal_block"
+ text_element = V"included_literal_block"
+ V"enclosed_inline"
+ V"inline_elements"
+ V"word"
@@ -981,14 +970,14 @@ local parser = P{
tracklists.currentindent = indent
return true
end)
- * V"text_elements"^1
+ * V"text_element"^1
* V"eol",
indented_other = Cmt(V"space"^1, function (s, i, indent)
warn("idt-m", indent, tracklists.currentindent, indent == tracklists.currentindent, i)
return indent == tracklists.currentindent
end)
- * V"text_elements"^1
+ * V"text_element"^1
* V"eol",
--------------------------------------------------------------------------------