Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pipe table and table caption support (witiko/markdown backport) #39

Merged
merged 2 commits into from
Aug 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions bin/lunamark
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,14 @@ environment variable `LUNAMARK_EXTENSIONS` (see ENVIRONMENT below).
option by the same name: attributes cannot be set on links
and indirect images (i.e. only direct images support them).

`(-) pipe_tables`
: Support "Pipe Table", as with Pandoc's option by the same name,
following the syntax introduced in PHP Markdown Extra.

`(-) table_captions`
: Enable the Pandoc `table_captions` syntax extension for
tables.

# TEMPLATES

By default, lunamark will produce a fragment. If the
Expand Down Expand Up @@ -495,6 +503,8 @@ given in parentheses:
(-) raw_attribute Raw pass-through on code elements
(-) fenced_code_attributes Fenced code block attributes
(-) link_attributes Link attributes
(-) pipe_tables PHP Markdown Extra pipe table support
(-) table_captions Table caption syntax extension
The keyword 'all' may also be used, to set all extensions simultaneously.
Setting the environment variable LUNAMARK_EXTENSIONS can change the
defaults.
Expand Down Expand Up @@ -561,6 +571,8 @@ local extensions = { -- defaults
raw_attribute = false,
fenced_code_attributes = false,
link_attributes = false,
pipe_tables = false,
table_captions = false,
}

if optarg["0"] then
Expand Down
122 changes: 122 additions & 0 deletions lunamark/reader/markdown.lua
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ parsers.equal = P("=")
parsers.colon = P(":")
parsers.semicolon = P(";")
parsers.exclamation = P("!")
parsers.pipe = P("|")
parsers.tilde = P("~")
parsers.tab = P("\t")
parsers.newline = P("\n")
Expand Down Expand Up @@ -778,6 +779,13 @@ end
-- option by the same name: attributes cannot be set on links
-- and indirect images (i.e. only direct images support them).
--
-- `pipe_tables`
-- : Support "Pipe Tables", as with Pandoc's option by the same name,
-- following the syntax introduced in PHP Markdown Extra.
--
-- `table_captions`
-- : Enable the Pandoc `table_captions` syntax extension for
-- tables.
--
-- * Returns a converter function that converts a markdown string
-- using `writer`, returning the parsed document as first result,
Expand Down Expand Up @@ -1476,6 +1484,114 @@ function M.new(writer, options)
* parsers.optionalspace * parsers.newline
/ writer.header

------------------------------------------------------------------------------
-- PipeTable
------------------------------------------------------------------------------

local function make_pipe_table_rectangular(rows)
local num_columns = #rows[2]
local rectangular_rows = {}
for i = 1, #rows do
local row = rows[i]
local rectangular_row = {}
for j = 1, num_columns do
rectangular_row[j] = row[j] or ""
end
table.insert(rectangular_rows, rectangular_row)
end
return rectangular_rows
end

local function pipe_table_row(allow_empty_first_column
, nonempty_column
, column_separator
, column)
local row_beginning
if allow_empty_first_column then
row_beginning = -- empty first column
#(parsers.spacechar^4
* column_separator)
* parsers.optionalspace
* column
* parsers.optionalspace
-- non-empty first column
+ parsers.nonindentspace
* nonempty_column^-1
* parsers.optionalspace
else
row_beginning = parsers.nonindentspace
* nonempty_column^-1
* parsers.optionalspace
end

return Ct(row_beginning
* (-- single column with no leading pipes
#(column_separator
* parsers.optionalspace
* parsers.newline)
* column_separator
* parsers.optionalspace
-- single column with leading pipes or
-- more than a single column
+ (column_separator
* parsers.optionalspace
* column
* parsers.optionalspace)^1
* (column_separator
* parsers.optionalspace)^-1))
end

larsers.table_hline_separator = parsers.pipe + parsers.plus

larsers.table_hline_column = (parsers.dash
- #(parsers.dash
* (parsers.spacechar
+ larsers.table_hline_separator
+ parsers.newline)))^1
* (parsers.colon * Cc("r")
+ parsers.dash * Cc("d"))
+ parsers.colon
* (parsers.dash
- #(parsers.dash
* (parsers.spacechar
+ larsers.table_hline_separator
+ parsers.newline)))^1
* (parsers.colon * Cc("c")
+ parsers.dash * Cc("l"))

larsers.table_hline = pipe_table_row(false
, larsers.table_hline_column
, larsers.table_hline_separator
, larsers.table_hline_column)

larsers.table_caption_beginning = parsers.skipblanklines
* parsers.nonindentspace
* (P("Table")^-1 * parsers.colon)
* parsers.optionalspace

larsers.table_row = pipe_table_row(true
, (C((parsers.linechar - parsers.pipe)^1)
/ parse_inlines)
, parsers.pipe
, (C((parsers.linechar - parsers.pipe)^0)
/ parse_inlines))

if options.table_captions then
larsers.table_caption = #larsers.table_caption_beginning
* larsers.table_caption_beginning
* Ct(parsers.Inline^1) -- N.B. CAVEAT: It was IndentedInline in witiko/markdown
* parsers.newline
else
larsers.table_caption = parsers.fail
end

larsers.PipeTable = Ct(larsers.table_row * parsers.newline
* larsers.table_hline
* (parsers.newline * larsers.table_row)^0)
/ make_pipe_table_rectangular
* larsers.table_caption^-1
/ writer.table

------------------------------------------------------------------------------
-- Syntax specification
------------------------------------------------------------------------------
Expand All @@ -1493,6 +1609,7 @@ function M.new(writer, options)
Blank = larsers.Blank,

Block = V("Blockquote")
+ V("PipeTable")
+ V("Verbatim")
+ V("FencedCodeBlock")
+ V("FencedDiv")
Expand All @@ -1518,6 +1635,7 @@ function M.new(writer, options)
DefinitionList = larsers.DefinitionList,
DisplayHtml = larsers.DisplayHtml,
Paragraph = larsers.Paragraph,
PipeTable = larsers.PipeTable,
Plain = larsers.Plain,

Inline = V("Str")
Expand Down Expand Up @@ -1623,6 +1741,10 @@ function M.new(writer, options)
syntax.TaskList = parsers.fail
end

if not options.pipe_tables then
syntax.PipeTable = parsers.fail
end

if options.alter_syntax and type(options.alter_syntax) == "function" then
syntax = options.alter_syntax(syntax)
end
Expand Down
12 changes: 11 additions & 1 deletion lunamark/writer/generic.lua
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ function M.new(options)
-- `numdelim`, depending on options, may be one of "Default", "OneParen",
-- "Period".
-- (Those symbolic names are loosely taken from Pandoc.)
function W.orderedlist(items)
function W.orderedlist(items, _)
return util.intersperse(items,W.interblocksep)
end

Expand Down Expand Up @@ -341,6 +341,16 @@ function M.new(options)
return util.intersperse(buffer,W.interblocksep)
end

--- A table.
-- The two arguments are rows, caption:
-- `rows[1]` contains the headers,
-- `rows[2]` contains the aligments (r l c d = right, left, centered, default)
-- and the other rows follow...
-- `caption` is the optional caption,
function W.table(_, _)
return ""
end

--- A cosmo template to be used in producing a standalone document.
-- `$body` is replaced with the document body, `$title` with the
-- title, and so on.
Expand Down
43 changes: 43 additions & 0 deletions lunamark/writer/html.lua
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,49 @@ function M.new(options)
return {"<dl>", containersep, intersperse(buffer, containersep), containersep, "</dl>"}
end

local function tableCellAlign (align)
if align == 'l' then
return ' style="text-align: left;"'
elseif align == 'r' then
return ' style="text-align: right;"'
elseif align == 'c' then
return ' style="text-align: center;"'
end
return ''
end

function Html.table(rows, caption)
-- Mimic Pandoc output for such tables (in terms of carriage returns, class, styles, etc.)
local t = {}
local aligns = rows[2]

if caption then
t[#t+1] = { "<caption>", caption, "</caption>\n" }
end

local theadrow = { '<tr class="header">\n' }
for j, column in ipairs(rows[1]) do
local col = { "<th"..tableCellAlign(aligns[j])..">", column, "</th>\n" }
theadrow[#theadrow+1] = col
end
theadrow[#theadrow+1] = "</tr>\n"
t[#t+1] = { "<thead>\n", theadrow, "</thead>\n" }

t[#t+1] = "<tbody>\n"
for i = 3, #rows do
local tbodyrows = { '<tr class="', (i % 2 == 0) and "even" or "odd",'">\n' }
for j, column in ipairs(rows[i]) do
local col = { "<td"..tableCellAlign(aligns[j])..">", column, "</td>\n" }
tbodyrows[#tbodyrows+1] = col
end
tbodyrows[#tbodyrows+1]= "</tr>\n"
t[#t+1] = tbodyrows
end
t[#t+1] = "</tbody>\n"

return { "<table>\n", t, "</table>\n" }
end

Html.template = [[
<html>
<head>
Expand Down
38 changes: 38 additions & 0 deletions tests/lunamark/ext_pipe_tables.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
lunamark -Xpipe_tables,table_captions
<<<
Pipe table

| Right | Left | Default | Center |
|------:|:-----|---------|:------:|
| 12 | 12 | 12 | 12 |
| 123 | 123 | 123 | 123 |

: Demonstration of a pipe table.
>>>
<p>Pipe table</p>

<table>
<caption>Demonstration of a pipe table.</caption>
<thead>
<tr class="header">
<th style="text-align: right;">Right</th>
<th style="text-align: left;">Left</th>
<th>Default</th>
<th style="text-align: center;">Center</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: right;">12</td>
<td style="text-align: left;">12</td>
<td>12</td>
<td style="text-align: center;">12</td>
</tr>
<tr class="even">
<td style="text-align: right;">123</td>
<td style="text-align: left;">123</td>
<td>123</td>
<td style="text-align: center;">123</td>
</tr>
</tbody>
</table>