From 11bb8627677fb8b49af92d7c55aec07c69f95843 Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Wed, 12 Jun 2019 18:58:38 +0200 Subject: Lua: add a `clone()` method to all AST elements (#5572) Closes: #5568 --- data/pandoc.lua | 9 +++++++ doc/lua-filters.md | 15 ++++++++++++ src/Text/Pandoc/Lua/Marshaling/AST.hs | 5 +++- src/Text/Pandoc/Lua/Module/Types.hs | 46 +++++++++++++++++++++++++++++++++++ test/lua/module/pandoc.lua | 38 +++++++++++++++++++++++++++++ 5 files changed, 112 insertions(+), 1 deletion(-) diff --git a/data/pandoc.lua b/data/pandoc.lua index 859ecedc4..97e75efca 100644 --- a/data/pandoc.lua +++ b/data/pandoc.lua @@ -28,6 +28,7 @@ local M = {} M.List = require 'pandoc.List' M.mediabag = require 'pandoc.mediabag' M.system = require 'pandoc.system' +M.types = require 'pandoc.types' M.utils = require 'pandoc.utils' M.text = require 'text' @@ -280,6 +281,7 @@ end -- @tparam {Block,...} blocks document content -- @tparam[opt] Meta meta document meta data M.Pandoc = AstElement:make_subtype'Pandoc' +M.Pandoc.behavior.clone = M.types.clone.Pandoc function M.Pandoc:new (blocks, meta) return { blocks = ensureList(blocks), @@ -299,6 +301,7 @@ M.Doc = M.Pandoc -- @function Meta -- @tparam meta table table containing document meta information M.Meta = AstElement:make_subtype'Meta' +M.Meta.behavior.clone = M.types.clone.Meta function M.Meta:new (meta) return meta end @@ -306,6 +309,7 @@ function M.Meta:new (meta) return meta end -- MetaValue -- @section MetaValue M.MetaValue = AstElement:make_subtype('MetaValue') +M.MetaValue.behavior.clone = M.types.clone.MetaValue --- Meta blocks -- @function MetaBlocks @@ -369,6 +373,7 @@ end --- Block elements M.Block = AstElement:make_subtype'Block' +M.Block.behavior.clone = M.types.clone.Block --- Creates a block quote element -- @function BlockQuote @@ -542,6 +547,7 @@ M.Table = M.Block:create_constructor( --- Inline element class M.Inline = AstElement:make_subtype'Inline' +M.Inline.behavior.clone = M.types.clone.Inline --- Creates a Cite inline element -- @function Cite @@ -898,6 +904,7 @@ function M.Attr:new (identifier, classes, attributes) attributes = setmetatable(to_alist(attributes or {}), AttributeList) return {identifier, classes, attributes} end +M.Attr.behavior.clone = M.types.clone.Attr M.Attr.behavior._field_names = {identifier = 1, classes = 2, attributes = 3} M.Attr.behavior.__eq = utils.equals M.Attr.behavior.__index = function(t, k) @@ -922,6 +929,7 @@ end -- Citation M.Citation = AstElement:make_subtype'Citation' +M.Citation.behavior.clone = M.types.clone.Citation --- Creates a single citation. -- @function Citation @@ -944,6 +952,7 @@ end -- ListAttributes M.ListAttributes = AstElement:make_subtype 'ListAttributes' +M.ListAttributes.behavior.clone = M.types.clone.ListAttributes --- Creates a set of list attributes. -- @function ListAttributes diff --git a/doc/lua-filters.md b/doc/lua-filters.md index 3ac2a62d2..dadc9a2fc 100644 --- a/doc/lua-filters.md +++ b/doc/lua-filters.md @@ -644,6 +644,20 @@ This section describes the types of objects available to Lua filters. See the [pandoc module](#module-pandoc}) for functions to create these objects. +## Shared Properties + +### `clone` + +`clone ()` + +All instances of the types listed here, with the exception of +read-only objects, can be cloned via the `clone()` method. + +Usage: + + local emph = pandoc.Emph {pandoc.Str 'important'} + local cloned_emph = emph:clone() -- note the colon + ## Pandoc {#type-ref-pandoc} Pandoc document @@ -1247,6 +1261,7 @@ Object equality is determined via : delimiter of list numbers; one of `DefaultDelim`, `Period`, `OneParen`, and `TwoParens` (string) + ## Hierarchical Element {#type-ref-Element} Hierarchical elements can be either *Sec* (sections) or *Blk* diff --git a/src/Text/Pandoc/Lua/Marshaling/AST.hs b/src/Text/Pandoc/Lua/Marshaling/AST.hs index f18754ac2..7b428b5f0 100644 --- a/src/Text/Pandoc/Lua/Marshaling/AST.hs +++ b/src/Text/Pandoc/Lua/Marshaling/AST.hs @@ -14,7 +14,10 @@ Marshaling/unmarshaling instances for document AST elements. -} -module Text.Pandoc.Lua.Marshaling.AST () where +module Text.Pandoc.Lua.Marshaling.AST + ( LuaAttr (..) + , LuaListAttributes (..) + ) where import Prelude import Control.Applicative ((<|>)) diff --git a/src/Text/Pandoc/Lua/Module/Types.hs b/src/Text/Pandoc/Lua/Module/Types.hs index 641bde7d6..fdc63cd99 100644 --- a/src/Text/Pandoc/Lua/Module/Types.hs +++ b/src/Text/Pandoc/Lua/Module/Types.hs @@ -15,8 +15,11 @@ module Text.Pandoc.Lua.Module.Types import Prelude import Data.Version (Version) import Foreign.Lua (Lua, NumResults) +import Text.Pandoc.Definition +import Text.Pandoc.Lua.Marshaling.AST (LuaAttr, LuaListAttributes) import Text.Pandoc.Lua.Marshaling.Version () import Text.Pandoc.Lua.Util (addFunction) +import Text.Pandoc.Shared (Element (..)) import qualified Foreign.Lua as Lua @@ -25,4 +28,47 @@ pushModule :: Lua NumResults pushModule = do Lua.newtable addFunction "Version" (return :: Version -> Lua Version) + pushCloneTable + Lua.setfield (Lua.nthFromTop 2) "clone" return 1 + +pushCloneTable :: Lua NumResults +pushCloneTable = do + Lua.newtable + addFunction "Attr" cloneAttr + addFunction "Block" cloneBlock + addFunction "Citation" cloneCitation + addFunction "Element" cloneElement + addFunction "Inline" cloneInline + addFunction "Meta" cloneMeta + addFunction "MetaValue" cloneMetaValue + addFunction "ListAttributes" cloneListAttributes + addFunction "Pandoc" clonePandoc + return 1 + +cloneAttr :: LuaAttr -> Lua LuaAttr +cloneAttr = return + +cloneBlock :: Block -> Lua Block +cloneBlock = return + +cloneCitation :: Citation -> Lua Citation +cloneCitation = return + +cloneElement :: Element -> Lua Element +cloneElement = return + +cloneInline :: Inline -> Lua Inline +cloneInline = return + +cloneListAttributes :: LuaListAttributes -> Lua LuaListAttributes +cloneListAttributes = return + +cloneMeta :: Meta -> Lua Meta +cloneMeta = return + +cloneMetaValue :: MetaValue -> Lua MetaValue +cloneMetaValue = return + +clonePandoc :: Pandoc -> Lua Pandoc +clonePandoc = return diff --git a/test/lua/module/pandoc.lua b/test/lua/module/pandoc.lua index 1c02c8720..ca2168805 100644 --- a/test/lua/module/pandoc.lua +++ b/test/lua/module/pandoc.lua @@ -87,6 +87,44 @@ return { end) }, }, + + group 'clone' { + test('clones Attr', function () + local attr = pandoc.Attr('test', {'my-class'}, {foo = 'bar'}) + local cloned = attr:clone() + attr.identifier = '' + attr.classes = {} + attr.attributes = {} + assert.are_same(cloned.identifier, 'test') + assert.are_same(cloned.classes, {'my-class'}) + assert.are_same(cloned.attributes.foo, 'bar') + end), + test('clones ListAttributes', function () + local la = pandoc.ListAttributes(2, pandoc.DefaultStyle, pandoc.Period) + local cloned = la:clone() + la.start = 9 + assert.are_same(cloned.start, 2) + end), + test('clones Para', function () + local para = pandoc.Para {pandoc.Str 'Hello'} + local cloned = para:clone() + para.content[1].text = 'bye' + assert.are_same(cloned, pandoc.Para {pandoc.Str 'Hello'}) + end), + test('clones Str', function () + local str = pandoc.Str 'Hello' + local cloned = str:clone() + str.text = 'bye' + assert.are_same(cloned.text, 'Hello') + end), + test('clones Citation', function () + local cite = pandoc.Citation('leibniz', pandoc.AuthorInText) + local cloned = cite:clone() + cite.id = 'newton' + assert.are_same(cloned.id, 'leibniz') + end), + }, + group 'pipe' { test('external string processing', function () if os_is_windows() then -- cgit v1.2.3