git.iko.soy/typeable/pandoc
on master help sign in
Lua filters: add SimpleTable for backwards compatibility (#6575)

A new type `SimpleTable` is made available to Lua filters. It is similar to the `Table` type in pandoc versions before 2.10; conversion functions from and to the new Table type are provided. Old filters using tables now require minimal changes and can use, e.g., if PANDOC_VERSION > {2,10,1} then pandoc.Table = pandoc.SimpleTable end and function Table (tbl) tbl = pandoc.utils.to_simple_table(tbl) … return pandoc.utils.from_simple_table(tbl) end to work with the current pandoc version.

commitacbea6b8c610dba4b63c0f6063c51b26ab9d2b76 authorAlbert Krewinkel <albert@zeitkraut.de> dateMon 21 Sep 2020, 00:48 (6 years ago) parentb2decdf
10 files changed+313−7
.hlint.yaml+1 data/pandoc.lua+24 doc/lua-filters.md+115 pandoc.cabal+1 src/Text/Pandoc/Lua/Init.hs+1 src/Text/Pandoc/Lua/Marshaling/AST.hs+1−1 src/Text/Pandoc/Lua/Marshaling/SimpleTable.hs+59 src/Text/Pandoc/Lua/Module/Utils.hs+44−5 src/Text/Pandoc/Lua/Util.hs+1−1 test/lua/module/pandoc-utils.lua+66
.hlint.yaml+1
@@ -78,6 +78,7 @@
7878 - Tests.Writers.Native
7979 - Text.Pandoc.Extensions
8080 - Text.Pandoc.Lua.Marshaling.Version
81+ - Text.Pandoc.Lua.Module.Utils
8182 - Text.Pandoc.Readers.Odt.ContentReader
8283 - Text.Pandoc.Readers.Odt.Namespaces
8384
data/pandoc.lua+24
@@ -1058,6 +1058,30 @@ M.ListAttributes.behavior.__pairs = function(t)
10581058 return make_next_function(fields), t, nil
10591059end
10601060
1061+--
1062+-- Legacy and compatibility types
1063+--
1064+
1065+--- Creates a simple (old style) table element.
1066+-- @function SimpleTable
1067+-- @tparam {Inline,...} caption table caption
1068+-- @tparam {AlignDefault|AlignLeft|AlignRight|AlignCenter,...} aligns alignments
1069+-- @tparam {int,...} widths column widths
1070+-- @tparam {Block,...} headers header row
1071+-- @tparam {{Block,...}} rows table rows
1072+-- @treturn Block table element
1073+M.SimpleTable = function(caption, aligns, widths, headers, rows)
1074+ return {
1075+ caption = ensureInlineList(caption),
1076+ aligns = List:new(aligns),
1077+ widths = List:new(widths),
1078+ headers = List:new(headers),
1079+ rows = List:new(rows),
1080+ tag = "SimpleTable",
1081+ t = "SimpleTable",
1082+ }
1083+end
1084+
10611085
10621086------------------------------------------------------------------------
10631087-- Constants
doc/lua-filters.md+115
@@ -1744,6 +1744,36 @@ table into a List.
17441744A pandoc log message. Objects have no fields, but can be
17451745converted to a string via `tostring`.
17461746
1747+## SimpleTable {#type-simpletable}
1748+
1749+A simple table is a table structure which resembles the old (pre
1750+pandoc 2.10) Table type. Bi-directional conversion from and to
1751+[Tables](#type-table) is possible with the
1752+[`pandoc.utils.to_simple_table`](#pandoc.utils.to_simple_table)
1753+and
1754+[`pandoc.utils.from_simple_table`](#pandoc.utils.from_simple_table)
1755+function, respectively. Instances of this type can also be created
1756+directly with the [`pandoc.SimpleTable`](#pandoc.simpletable)
1757+constructor.
1758+
1759+Fields:
1760+
1761+`caption`:
1762+: [List] of [Inlines]
1763+
1764+`aligns`:
1765+: column alignments ([List] of [Alignments](#type-alignment))
1766+
1767+`widths`:
1768+: column widths; a ([List] of numbers)
1769+
1770+`headers`:
1771+: table header row ([List] of lists of [Blocks])
1772+
1773+`rows`:
1774+: table rows ([List] of rows, where a row is a list of lists of
1775+ [Blocks])
1776+
17471777## Version {#type-version}
17481778
17491779A version object. This represents a software version like
@@ -1816,6 +1846,8 @@ Usage:
18161846[Pandoc]: #type-pandoc
18171847[Para]: #type-para
18181848[Rows]: #type-row
1849+[SimpleTable]: #type-simpletable
1850+[Table]: #type-table
18191851[TableBody]: #type-tablebody
18201852[TableFoot]: #type-tablefoot
18211853[TableHead]: #type-tablehead
@@ -2491,6 +2523,51 @@ format, and functions to filter and modify a subtree.
24912523
24922524 Returns: [ListAttributes](#type-listattributes) object
24932525
2526+## Legacy types
2527+
2528+[`SimpleTable (caption, aligns, widths, headers, rows)`]{#pandoc.simpletable}
2529+
2530+: Creates a simple table resembling the old (pre pandoc 2.10)
2531+ table type.
2532+
2533+ Parameters:
2534+
2535+ `caption`:
2536+ : [List] of [Inlines]
2537+
2538+ `aligns`:
2539+ : column alignments ([List] of [Alignments](#type-alignment))
2540+
2541+ `widths`:
2542+ : column widths; a ([List] of numbers)
2543+
2544+ `headers`:
2545+ : table header row ([List] of lists of [Blocks])
2546+
2547+ `rows`:
2548+ : table rows ([List] of rows, where a row is a list of lists
2549+ of [Blocks])
2550+
2551+ Returns: [SimpleTable] object
2552+
2553+ Usage:
2554+
2555+ local caption = "Overview"
2556+ local aligns = {pandoc.AlignDefault, pandoc.AlignDefault}
2557+ local widths = {0, 0} -- let pandoc determine col widths
2558+ local headers = {"Language", "Typing"}
2559+ local rows = {
2560+ {{pandoc.Plain "Haskell"}, {pandoc.Plain "static"}},
2561+ {{pandoc.Plain "Lua"}, {pandoc.Plain "Dynamic"}},
2562+ }
2563+ simple_table = pandoc.SimpleTable(
2564+ caption,
2565+ aligns,
2566+ widths,
2567+ headers,
2568+ rows
2569+ )
2570+
24942571## Constants
24952572
24962573[`AuthorInText`]{#pandoc.authorintext}
@@ -2753,6 +2830,26 @@ Returns:
27532830
27542831- Whether the two objects represent the same element (boolean)
27552832
2833+### from\_simple\_table {#pandoc.utils.from_simple_table}
2834+
2835+`from_simple_table (table)`
2836+
2837+Creates a [Table] block element from a [SimpleTable]. This is
2838+useful for dealing with legacy code which was written for pandoc
2839+versions older than 2.10.
2840+
2841+Returns:
2842+
2843+- table block element ([Table])
2844+
2845+Usage:
2846+
2847+ local simple = pandoc.SimpleTable(table)
2848+ -- modify, using pre pandoc 2.10 methods
2849+ simple.caption = pandoc.SmallCaps(simple.caption)
2850+ -- create normal table block again
2851+ table = pandoc.utils.from_simple_table(simple)
2852+
27562853### make\_sections {#pandoc.utils.make_sections}
27572854
27582855`make_sections (number_sections, base_level, blocks)`
@@ -2872,6 +2969,24 @@ Usage:
28722969 local pandoc_birth_year = to_roman_numeral(2006)
28732970 -- pandoc_birth_year == 'MMVI'
28742971
2972+### to\_simple\_table {#pandoc.utils.to_simple_table}
2973+
2974+`to_simple_table (table)`
2975+
2976+Creates a [SimpleTable] out of a [Table] block.
2977+
2978+Returns:
2979+
2980+- a simple table object ([SimpleTable])
2981+
2982+Usage:
2983+
2984+ local simple = pandoc.utils.to_simple_table(table)
2985+ -- modify, using pre pandoc 2.10 methods
2986+ simple.caption = pandoc.SmallCaps(simple.caption)
2987+ -- create normal table block again
2988+ table = pandoc.utils.from_simple_table(simple)
2989+
28752990# Module pandoc.mediabag
28762991
28772992The `pandoc.mediabag` module allows accessing pandoc's media
pandoc.cabal+1
@@ -633,6 +633,7 @@ library
633633 Text.Pandoc.Lua.Marshaling.MediaBag,
634634 Text.Pandoc.Lua.Marshaling.PandocError,
635635 Text.Pandoc.Lua.Marshaling.ReaderOptions,
636+ Text.Pandoc.Lua.Marshaling.SimpleTable,
636637 Text.Pandoc.Lua.Marshaling.Version,
637638 Text.Pandoc.Lua.Module.MediaBag,
638639 Text.Pandoc.Lua.Module.Pandoc,
src/Text/Pandoc/Lua/Init.hs+1
@@ -80,6 +80,7 @@ putConstructorsInRegistry = liftPandocLua $ do
8080 putInReg "Attr" -- used for Attr type alias
8181 putInReg "ListAttributes" -- used for ListAttributes type alias
8282 putInReg "List" -- pandoc.List
83+ putInReg "SimpleTable" -- helper for backward-compatible table handling
8384 where
8485 constrsToReg :: Data a => a -> Lua ()
8586 constrsToReg = mapM_ (putInReg . showConstr) . dataTypeConstrs . dataTypeOf
src/Text/Pandoc/Lua/Marshaling/AST.hs+1−1
@@ -260,7 +260,7 @@ instance Peekable TableBody where
260260 return $ TableBody attr (RowHeadColumns rowHeadColumns) head' body
261261
262262instance Pushable TableHead where
263− push (TableHead attr cells) = Lua.push (attr, cells)
263+ push (TableHead attr rows) = Lua.push (attr, rows)
264264
265265instance Peekable TableHead where
266266 peek = fmap (uncurry TableHead) . Lua.peek
src/Text/Pandoc/Lua/Marshaling/SimpleTable.hsnew file+59
@@ -0,0 +1,59 @@
1+{- |
2+ Module : Text.Pandoc.Lua.Marshaling.SimpleTable
3+ Copyright : © 2020 Albert Krewinkel
4+ License : GNU GPL, version 2 or above
5+
6+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
7+ Stability : alpha
8+
9+Definition and marshaling of the 'SimpleTable' data type used as a
10+convenience type when dealing with tables.
11+-}
12+module Text.Pandoc.Lua.Marshaling.SimpleTable
13+ ( SimpleTable (..)
14+ , peekSimpleTable
15+ , pushSimpleTable
16+ )
17+ where
18+
19+import Foreign.Lua (Lua, Peekable, Pushable, StackIndex)
20+import Text.Pandoc.Definition
21+import Text.Pandoc.Lua.Util (defineHowTo, pushViaConstructor, rawField)
22+import Text.Pandoc.Lua.Marshaling.AST ()
23+
24+import qualified Foreign.Lua as Lua
25+
26+-- | A simple (legacy-style) table.
27+data SimpleTable = SimpleTable
28+ { simpleTableCaption :: [Inline]
29+ , simpleTableAlignments :: [Alignment]
30+ , simpleTableColumnWidths :: [Double]
31+ , simpleTableHeader :: [[Block]]
32+ , simpleTableBody :: [[[Block]]]
33+ }
34+
35+instance Pushable SimpleTable where
36+ push = pushSimpleTable
37+
38+instance Peekable SimpleTable where
39+ peek = peekSimpleTable
40+
41+-- | Push a simple table to the stack by calling the
42+-- @pandoc.SimpleTable@ constructor.
43+pushSimpleTable :: SimpleTable -> Lua ()
44+pushSimpleTable tbl = pushViaConstructor "SimpleTable"
45+ (simpleTableCaption tbl)
46+ (simpleTableAlignments tbl)
47+ (simpleTableColumnWidths tbl)
48+ (simpleTableHeader tbl)
49+ (simpleTableBody tbl)
50+
51+-- | Retrieve a simple table from the stack.
52+peekSimpleTable :: StackIndex -> Lua SimpleTable
53+peekSimpleTable idx = defineHowTo "get SimpleTable" $
54+ SimpleTable
55+ <$> rawField idx "caption"
56+ <*> rawField idx "aligns"
57+ <*> rawField idx "widths"
58+ <*> rawField idx "headers"
59+ <*> rawField idx "rows"
src/Text/Pandoc/Lua/Module/Utils.hs+44−5
@@ -1,3 +1,4 @@
1+{-# LANGUAGE LambdaCase #-}
12{-# LANGUAGE ScopedTypeVariables #-}
23{- |
34 Module : Text.Pandoc.Lua.Module.Utils
@@ -7,7 +8,7 @@
78 Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
89 Stability : alpha
910
10−Utility module for lua, exposing internal helper functions.
11+Utility module for Lua, exposing internal helper functions.
1112-}
1213module Text.Pandoc.Lua.Module.Utils
1314 ( pushModule
@@ -15,13 +16,17 @@ module Text.Pandoc.Lua.Module.Utils
1516
1617import Control.Applicative ((<|>))
1718import Control.Monad.Catch (try)
19+import Data.Data (showConstr, toConstr)
1820import Data.Default (def)
1921import Data.Version (Version)
20−import Foreign.Lua (Peekable, Lua, NumResults)
21−import Text.Pandoc.Definition ( Pandoc, Meta, MetaValue (..), Block, Inline
22− , Citation, Attr, ListAttributes)
22+import Foreign.Lua (Peekable, Lua, NumResults (..))
23+import Text.Pandoc.Definition
2324import Text.Pandoc.Error (PandocError)
2425import Text.Pandoc.Lua.Marshaling ()
26+import Text.Pandoc.Lua.Marshaling.SimpleTable
27+ ( SimpleTable (..)
28+ , pushSimpleTable
29+ )
2530import Text.Pandoc.Lua.PandocLua (PandocLua, addFunction, liftPandocLua)
2631
2732import qualified Data.Digest.Pure.SHA as SHA
@@ -31,19 +36,22 @@ import qualified Foreign.Lua as Lua
3136import qualified Text.Pandoc.Builder as B
3237import qualified Text.Pandoc.Filter.JSON as JSONFilter
3338import qualified Text.Pandoc.Shared as Shared
39+import qualified Text.Pandoc.Writers.Shared as Shared
3440
35−-- | Push the "pandoc.utils" module to the lua stack.
41+-- | Push the "pandoc.utils" module to the Lua stack.
3642pushModule :: PandocLua NumResults
3743pushModule = do
3844 liftPandocLua Lua.newtable
3945 addFunction "blocks_to_inlines" blocksToInlines
4046 addFunction "equals" equals
47+ addFunction "from_simple_table" from_simple_table
4148 addFunction "make_sections" makeSections
4249 addFunction "normalize_date" normalizeDate
4350 addFunction "run_json_filter" runJSONFilter
4451 addFunction "sha1" sha1
4552 addFunction "stringify" stringify
4653 addFunction "to_roman_numeral" toRomanNumeral
54+ addFunction "to_simple_table" to_simple_table
4755 addFunction "Version" (return :: Version -> Lua Version)
4856 return 1
4957
@@ -131,6 +139,37 @@ instance Peekable AstElement where
131139 Left (_ :: PandocError) -> Lua.throwMessage
132140 "Expected an AST element, but could not parse value as such."
133141
142+-- | Converts an old/simple table into a normal table block element.
143+from_simple_table :: SimpleTable -> Lua NumResults
144+from_simple_table (SimpleTable capt aligns widths head' body) = do
145+ Lua.push $ Table
146+ nullAttr
147+ (Caption Nothing [Plain capt])
148+ (zipWith (\a w -> (a, toColWidth w)) aligns widths)
149+ (TableHead nullAttr [blockListToRow head'])
150+ [TableBody nullAttr 0 [] $ map blockListToRow body]
151+ (TableFoot nullAttr [])
152+ return (NumResults 1)
153+ where
154+ blockListToRow :: [[Block]] -> Row
155+ blockListToRow = Row nullAttr . map (B.simpleCell . B.fromList)
156+
157+ toColWidth :: Double -> ColWidth
158+ toColWidth 0 = ColWidthDefault
159+ toColWidth w = ColWidth w
160+
161+-- | Converts a table into an old/simple table.
162+to_simple_table :: Block -> Lua NumResults
163+to_simple_table = \case
164+ Table _attr caption specs thead tbodies tfoot -> do
165+ let (capt, aligns, widths, headers, rows) =
166+ Shared.toLegacyTable caption specs thead tbodies tfoot
167+ pushSimpleTable $ SimpleTable capt aligns widths headers rows
168+ return (NumResults 1)
169+ blk ->
170+ Lua.throwMessage $
171+ "Expected Table, got " <> showConstr (toConstr blk) <> "."
172+
134173-- | Convert a number < 4000 to uppercase roman numeral.
135174toRomanNumeral :: Lua.Integer -> PandocLua T.Text
136175toRomanNumeral = return . Shared.toRomanNumeral . fromIntegral
src/Text/Pandoc/Lua/Util.hs+1−1
@@ -80,7 +80,7 @@ instance (Pushable a, PushViaCall b) => PushViaCall (a -> b) where
8080pushViaCall :: PushViaCall a => String -> a
8181pushViaCall fn = pushViaCall' fn (return ()) 0
8282
83−-- | Call a pandoc element constructor within lua, passing all given arguments.
83+-- | Call a pandoc element constructor within Lua, passing all given arguments.
8484pushViaConstructor :: PushViaCall a => String -> a
8585pushViaConstructor pandocFn = pushViaCall ("pandoc." ++ pandocFn)
8686
test/lua/module/pandoc-utils.lua+66
@@ -90,4 +90,70 @@ return {
9090 assert.is_falsy(pcall(utils.to_roman_numeral, 'not a number'))
9191 end)
9292 },
93+
94+ group 'to_simple_table' {
95+ test('convertes Table', function ()
96+ function simple_cell (blocks)
97+ return {
98+ attr = pandoc.Attr(),
99+ alignment = "AlignDefault",
100+ contents = blocks,
101+ col_span = 1,
102+ row_span = 1,
103+ }
104+ end
105+ local tbl = pandoc.Table(
106+ {long = {pandoc.Plain {
107+ pandoc.Str "the", pandoc.Space(), pandoc.Str "caption"}}},
108+ {{pandoc.AlignDefault, nil}},
109+ {pandoc.Attr(), {{pandoc.Attr(), {simple_cell{pandoc.Plain "head1"}}}}},
110+ {{
111+ attr = pandoc.Attr(),
112+ body = {{pandoc.Attr(), {simple_cell{pandoc.Plain "cell1"}}}},
113+ head = {},
114+ row_head_columns = 0
115+ }},
116+ {pandoc.Attr(), {}},
117+ pandoc.Attr()
118+ )
119+ local stbl = utils.to_simple_table(tbl)
120+ assert.are_equal('SimpleTable', stbl.t)
121+ assert.are_equal('head1', utils.stringify(stbl.headers[1]))
122+ assert.are_equal('cell1', utils.stringify(stbl.rows[1][1]))
123+ assert.are_equal('the caption', utils.stringify(pandoc.Span(stbl.caption)))
124+ end),
125+ test('fails on para', function ()
126+ assert.is_falsy(pcall(utils.to_simple_table, pandoc.Para "nope"))
127+ end),
128+ },
129+ group 'from_simple_table' {
130+ test('converts SimpleTable to Table', function ()
131+ local caption = {pandoc.Str "Overview"}
132+ local aligns = {pandoc.AlignDefault, pandoc.AlignDefault}
133+ local widths = {0, 0} -- let pandoc determine col widths
134+ local headers = {
135+ {pandoc.Plain "Language"},
136+ {pandoc.Plain "Typing"}
137+ }
138+ local rows = {
139+ {{pandoc.Plain "Haskell"}, {pandoc.Plain "static"}},
140+ {{pandoc.Plain "Lua"}, {pandoc.Plain "Dynamic"}},
141+ }
142+ local simple_table = pandoc.SimpleTable(
143+ caption,
144+ aligns,
145+ widths,
146+ headers,
147+ rows
148+ )
149+ local tbl = utils.from_simple_table(simple_table)
150+ assert.are_equal("Table", tbl.t)
151+ assert.are_same(
152+ {pandoc.Plain(caption)},
153+ tbl.caption.long
154+ )
155+ -- reversible
156+ assert.are_same(simple_table, utils.to_simple_table(tbl))
157+ end),
158+ }
93159}