diff options
Diffstat (limited to 'src/Text')
-rw-r--r-- | src/Text/Pandoc/Lua/Marshaling/AST.hs | 298 | ||||
-rw-r--r-- | src/Text/Pandoc/Lua/Module/Pandoc.hs | 110 |
2 files changed, 345 insertions, 63 deletions
diff --git a/src/Text/Pandoc/Lua/Marshaling/AST.hs b/src/Text/Pandoc/Lua/Marshaling/AST.hs index 9bb956ba2..1e635483c 100644 --- a/src/Text/Pandoc/Lua/Marshaling/AST.hs +++ b/src/Text/Pandoc/Lua/Marshaling/AST.hs @@ -3,6 +3,7 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeApplications #-} {- | Module : Text.Pandoc.Lua.Marshaling.AST @@ -21,12 +22,18 @@ module Text.Pandoc.Lua.Marshaling.AST , peekBlocks , peekCaption , peekCitation + , peekFormat , peekInline , peekInlines , peekListAttributes , peekMeta , peekMetaValue , peekPandoc + , peekMathType + , peekQuoteType + + , peekFuzzyInlines + , peekFuzzyBlocks , pushAttr , pushBlock @@ -37,9 +44,13 @@ module Text.Pandoc.Lua.Marshaling.AST ) where import Control.Applicative ((<|>), optional) +import Control.Monad.Catch (throwM) import Control.Monad ((<$!>), (>=>)) +import Data.Data (showConstr, toConstr) +import Data.Text (Text) import HsLua hiding (Operation (Div)) import Text.Pandoc.Definition +import Text.Pandoc.Error (PandocError (PandocLuaError)) import Text.Pandoc.Lua.Util (pushViaConstr', pushViaConstructor) import Text.Pandoc.Lua.Marshaling.Attr (peekAttr, pushAttr) import Text.Pandoc.Lua.Marshaling.List (pushPandocList) @@ -94,10 +105,13 @@ instance Pushable Inline where -- Citation instance Pushable Citation where - push (Citation cid prefix suffix mode noteNum hash) = - pushViaConstr' "Citation" - [ push cid, push mode, push prefix, push suffix, push noteNum, push hash - ] + push = pushCitation + +pushCitation :: LuaError e => Pusher e Citation +pushCitation (Citation cid prefix suffix mode noteNum hash) = + pushViaConstr' "Citation" + [ push cid, push mode, push prefix, push suffix, push noteNum, push hash + ] peekCitation :: LuaError e => Peeker e Citation peekCitation = fmap (retrieving "Citation") @@ -119,7 +133,10 @@ instance Pushable CitationMode where push = Lua.push . show instance Pushable Format where - push (Format f) = Lua.push f + push = pushFormat + +pushFormat :: LuaError e => Pusher e Format +pushFormat (Format f) = pushText f peekFormat :: LuaError e => Peeker e Format peekFormat idx = Format <$!> peekText idx @@ -134,7 +151,19 @@ instance Pushable MathType where push = Lua.push . show instance Pushable QuoteType where - push = Lua.push . show + push = pushQuoteType + +pushMathType :: LuaError e => Pusher e MathType +pushMathType = pushString . show + +peekMathType :: LuaError e => Peeker e MathType +peekMathType = peekRead + +pushQuoteType :: LuaError e => Pusher e QuoteType +pushQuoteType = pushString . show + +peekQuoteType :: LuaError e => Peeker e QuoteType +peekQuoteType = peekRead -- | Push an meta value element to the top of the lua stack. pushMetaValue :: LuaError e => MetaValue -> LuaE e () @@ -354,66 +383,213 @@ peekCell = fmap (retrieving "Cell") blks <- peekFieldRaw peekBlocks "contents" idx return $! Cell attr algn rs cs blks +getInlineText :: Inline -> Possible Text +getInlineText = \case + Code _ lst -> Actual lst + Math _ str -> Actual str + RawInline _ raw -> Actual raw + Str s -> Actual s + _ -> Absent + +setInlineText :: Inline -> Text -> Possible Inline +setInlineText = \case + Code attr _ -> Actual . Code attr + Math mt _ -> Actual . Math mt + RawInline f _ -> Actual . RawInline f + Str _ -> Actual . Str + _ -> const Absent + +data Content + = ContentBlocks [Block] + | ContentInlines [Inline] + +setInlineContent :: Inline -> Content -> Possible Inline +setInlineContent = \case + -- inline content + Cite cs _ -> Actual . Cite cs . inlineContent + Emph _ -> Actual . Emph . inlineContent + Quoted qt _ -> Actual . Quoted qt . inlineContent + SmallCaps _ -> Actual . SmallCaps . inlineContent + Span attr _ -> Actual . Span attr . inlineContent + Strong _ -> Actual . Strong . inlineContent + Subscript _ -> Actual . Subscript . inlineContent + Superscript _ -> Actual . Superscript . inlineContent + Underline _ -> Actual . Underline . inlineContent + -- block content + Note _ -> Actual . Note . blockContent + _ -> const Absent + where + inlineContent = \case + ContentInlines inlns -> inlns + ContentBlocks _ -> throwM $ + PandocLuaError "expected Inlines, got Blocks" + blockContent = \case + ContentBlocks blks -> blks + ContentInlines [] -> [] + ContentInlines _ -> throwM $ + PandocLuaError "expected Blocks, got Inlines" + +getInlineContent :: Inline -> Possible Content +getInlineContent = \case + Cite _ inlns -> Actual $ ContentInlines inlns + Emph inlns -> Actual $ ContentInlines inlns + Quoted _ inlns -> Actual $ ContentInlines inlns + SmallCaps inlns -> Actual $ ContentInlines inlns + Span _ inlns -> Actual $ ContentInlines inlns + Strong inlns -> Actual $ ContentInlines inlns + Subscript inlns -> Actual $ ContentInlines inlns + Superscript inlns -> Actual $ ContentInlines inlns + Underline inlns -> Actual $ ContentInlines inlns + Note blks -> Actual $ ContentBlocks blks + _ -> Absent + +-- title +getInlineTitle :: Inline -> Possible Text +getInlineTitle = \case + Image _ _ (_, tit) -> Actual tit + Link _ _ (_, tit) -> Actual tit + _ -> Absent + +setInlineTitle :: Inline -> Text -> Possible Inline +setInlineTitle = \case + Image attr capt (src, _) -> Actual . Image attr capt . (src,) + Link attr capt (src, _) -> Actual . Link attr capt . (src,) + _ -> const Absent + +-- attr +getInlineAttr :: Inline -> Possible Attr +getInlineAttr = \case + Code attr _ -> Actual attr + Image attr _ _ -> Actual attr + Link attr _ _ -> Actual attr + Span attr _ -> Actual attr + _ -> Absent + +setInlineAttr :: Inline -> Attr -> Possible Inline +setInlineAttr = \case + Code _ cs -> Actual . (`Code` cs) + Image _ cpt tgt -> Actual . \attr -> Image attr cpt tgt + Link _ cpt tgt -> Actual . \attr -> Link attr cpt tgt + Span _ inlns -> Actual . (`Span` inlns) + _ -> const Absent + +showInline :: LuaError e => DocumentedFunction e +showInline = defun "show" + ### liftPure (show @Inline) + <#> parameter peekInline "inline" "Inline" "Object" + =#> functionResult pushString "string" "stringified Inline" + +pushContent :: LuaError e => Pusher e Content +pushContent = \case + ContentBlocks blks -> pushPandocList pushBlock blks + ContentInlines inlns -> pushPandocList pushInline inlns + +peekContent :: LuaError e => Peeker e Content +peekContent idx = + (ContentInlines <$!> peekList peekInline idx) <|> + (ContentBlocks <$!> peekList peekBlock idx) + +typeInline :: LuaError e => DocumentedType e Inline +typeInline = deftype "Inline" + [ operation Tostring showInline + , operation Eq $ defun "__eq" + ### liftPure2 (==) + <#> parameter peekInline "a" "Inline" "" + <#> parameter peekInline "b" "Inline" "" + =#> functionResult pushBool "boolean" "whether the two are equal" + ] + [ possibleProperty "attr" "element attributes" + (pushAttr, getInlineAttr) + (peekAttr, setInlineAttr) + , possibleProperty "caption" "image caption" + (pushPandocList pushInline, \case + Image _ capt _ -> Actual capt + _ -> Absent) + (peekInlines, \case + Image attr _ target -> Actual . (\capt -> Image attr capt target) + _ -> const Absent) + , possibleProperty "citations" "list of citations" + (pushPandocList pushCitation, \case {Cite cs _ -> Actual cs; _ -> Absent}) + (peekList peekCitation, \case + Cite _ inlns -> Actual . (`Cite` inlns) + _ -> const Absent) + , possibleProperty "content" "element contents" + (pushContent, getInlineContent) + (peekContent, setInlineContent) + , possibleProperty "format" "format of raw text" + (pushFormat, \case {RawInline fmt _ -> Actual fmt; _ -> Absent}) + (peekFormat, \case + RawInline _ txt -> Actual . (`RawInline` txt) + _ -> const Absent) + , possibleProperty "mathtype" "math rendering method" + (pushMathType, \case {Math mt _ -> Actual mt; _ -> Absent}) + (peekMathType, \case + Math _ txt -> Actual . (`Math` txt) + _ -> const Absent) + , possibleProperty "quotetype" "type of quotes (single or double)" + (pushQuoteType, \case {Quoted qt _ -> Actual qt; _ -> Absent}) + (peekQuoteType, \case + Quoted _ inlns -> Actual . (`Quoted` inlns) + _ -> const Absent) + , possibleProperty "src" "image source" + (pushText, \case + Image _ _ (src, _) -> Actual src + _ -> Absent) + (peekText, \case + Image attr capt (_, title) -> Actual . Image attr capt . (,title) + _ -> const Absent) + , possibleProperty "target" "link target URL" + (pushText, \case + Link _ _ (tgt, _) -> Actual tgt + _ -> Absent) + (peekText, \case + Link attr capt (_, title) -> Actual . Image attr capt . (,title) + _ -> const Absent) + , possibleProperty "title" "title text" + (pushText, getInlineTitle) + (peekText, setInlineTitle) + , possibleProperty "text" "text contents" + (pushText, getInlineText) + (peekText, setInlineText) + , readonly "tag" "type of Inline" + (pushString, showConstr . toConstr ) + + , alias "t" "tag" ["tag"] + , alias "c" "content" ["content"] + , alias "identifier" "element identifier" ["attr", "identifier"] + , alias "classes" "element classes" ["attr", "classes"] + , alias "attributes" "other element attributes" ["attr", "attributes"] + + , method $ defun "clone" + ### return + <#> parameter peekInline "inline" "Inline" "self" + =#> functionResult pushInline "Inline" "cloned Inline" + ] + -- | Push an inline element to the top of the lua stack. pushInline :: forall e. LuaError e => Inline -> LuaE e () -pushInline = \case - Cite citations lst -> pushViaConstructor @e "Cite" lst citations - Code attr lst -> pushViaConstr' @e "Code" - [push lst, pushAttr attr] - Emph inlns -> pushViaConstructor @e "Emph" inlns - Underline inlns -> pushViaConstructor @e "Underline" inlns - Image attr alt (src,tit) -> pushViaConstr' @e "Image" - [push alt, push src, push tit, pushAttr attr] - LineBreak -> pushViaConstructor @e "LineBreak" - Link attr lst (src,tit) -> pushViaConstr' @e "Link" - [push lst, push src, push tit, pushAttr attr] - Note blcks -> pushViaConstructor @e "Note" blcks - Math mty str -> pushViaConstructor @e "Math" mty str - Quoted qt inlns -> pushViaConstructor @e "Quoted" qt inlns - RawInline f cs -> pushViaConstructor @e "RawInline" f cs - SmallCaps inlns -> pushViaConstructor @e "SmallCaps" inlns - SoftBreak -> pushViaConstructor @e "SoftBreak" - Space -> pushViaConstructor @e "Space" - Span attr inlns -> pushViaConstr' @e "Span" - [push inlns, pushAttr attr] - Str str -> pushViaConstructor @e "Str" str - Strikeout inlns -> pushViaConstructor @e "Strikeout" inlns - Strong inlns -> pushViaConstructor @e "Strong" inlns - Subscript inlns -> pushViaConstructor @e "Subscript" inlns - Superscript inlns -> pushViaConstructor @e "Superscript" inlns +pushInline = pushUD typeInline -- | Return the value at the given index as inline if possible. peekInline :: forall e. LuaError e => Peeker e Inline -peekInline = retrieving "Inline" . \idx -> do - -- Get the contents of an AST element. - let mkBlock :: (a -> Inline) -> Peeker e a -> Peek e Inline - mkBlock f p = f <$!> peekFieldRaw p "c" idx - LuaUtil.getTag idx >>= \case - "Cite" -> mkBlock (uncurry Cite) $ - peekPair (peekList peekCitation) peekInlines - "Code" -> mkBlock (uncurry Code) (peekPair peekAttr peekText) - "Emph" -> mkBlock Emph peekInlines - "Underline" -> mkBlock Underline peekInlines - "Image" -> mkBlock (\(attr, lst, tgt) -> Image attr lst tgt) - $ peekTriple peekAttr peekInlines - (peekPair peekText peekText) - "Link" -> mkBlock (\(attr, lst, tgt) -> Link attr lst tgt) $ - peekTriple peekAttr peekInlines (peekPair peekText peekText) - "LineBreak" -> return LineBreak - "Note" -> mkBlock Note peekBlocks - "Math" -> mkBlock (uncurry Math) (peekPair peekRead peekText) - "Quoted" -> mkBlock (uncurry Quoted) (peekPair peekRead peekInlines) - "RawInline" -> mkBlock (uncurry RawInline) (peekPair peekFormat peekText) - "SmallCaps" -> mkBlock SmallCaps peekInlines - "SoftBreak" -> return SoftBreak - "Space" -> return Space - "Span" -> mkBlock (uncurry Span) (peekPair peekAttr peekInlines) - "Str" -> mkBlock Str peekText - "Strikeout" -> mkBlock Strikeout peekInlines - "Strong" -> mkBlock Strong peekInlines - "Subscript" -> mkBlock Subscript peekInlines - "Superscript"-> mkBlock Superscript peekInlines - Name tag -> Lua.failPeek ("Unknown inline type: " <> tag) +peekInline = retrieving "Inline" . \idx -> peekUD typeInline idx + +-- | Try extra-hard to return the value at the given index as a list of +-- inlines. +peekFuzzyInlines :: LuaError e => Peeker e [Inline] +peekFuzzyInlines = choice + [ peekList peekInline + , fmap pure . peekInline + , \idx -> pure . Str <$!> peekText idx + ] + +peekFuzzyBlocks :: LuaError e => Peeker e [Block] +peekFuzzyBlocks = choice + [ peekList peekBlock + , fmap pure . peekBlock + , \idx -> pure . Plain . pure . Str <$!> peekText idx + ] + pushListAttributes :: forall e. LuaError e => ListAttributes -> LuaE e () pushListAttributes (start, style, delimiter) = diff --git a/src/Text/Pandoc/Lua/Module/Pandoc.hs b/src/Text/Pandoc/Lua/Module/Pandoc.hs index 34317276d..ef1d6f078 100644 --- a/src/Text/Pandoc/Lua/Module/Pandoc.hs +++ b/src/Text/Pandoc/Lua/Module/Pandoc.hs @@ -1,5 +1,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeApplications #-} {- | Module : Text.Pandoc.Lua.Module.Pandoc Copyright : Copyright © 2017-2021 Albert Krewinkel @@ -16,7 +17,7 @@ module Text.Pandoc.Lua.Module.Pandoc import Prelude hiding (read) import Control.Applicative (optional) -import Control.Monad ((>=>), when) +import Control.Monad ((>=>), forM_, when) import Control.Monad.Except (throwError) import Data.Default (Default (..)) import Data.Maybe (fromMaybe) @@ -54,11 +55,116 @@ pushModule = do addFunction "walk_block" (walkElement peekBlock pushBlock) addFunction "walk_inline" (walkElement peekInline pushInline) -- Constructors - addFunction "Pandoc" mkPandoc addFunction "Attr" (liftPandocLua mkAttr) addFunction "AttributeList" (liftPandocLua mkAttributeList) + addFunction "Pandoc" mkPandoc + liftPandocLua $ do + let addConstr fn = do + pushName (functionName fn) + pushDocumentedFunction fn + rawset (nth 3) + forM_ inlineConstructors addConstr + -- add constructors to Inlines.constructor + newtable -- constructor + forM_ (inlineConstructors @PandocError) $ \fn -> do + let name = functionName fn + pushName name + pushName name + rawget (nth 4) + rawset (nth 3) + -- set as pandoc.Inline.constructor + pushName "Inline" + newtable *> pushName "constructor" *> pushvalue (nth 4) *> rawset (nth 3) + rawset (nth 4) + pop 1 -- remaining constructor table return 1 +inlineConstructors :: LuaError e => [DocumentedFunction e] +inlineConstructors = + [ defun "Cite" + ### liftPure2 Cite + <#> parameter (peekList peekCitation) "citations" "list of Citations" "" + <#> parameter peekFuzzyInlines "content" "Inline" "placeholder content" + =#> functionResult pushInline "Inline" "cite element" + , defun "Code" + ### liftPure2 (flip Code) + <#> parameter peekText "code" "string" "code string" + <#> parameter peekAttr "attr" "Attr" "additional attributes" + =#> functionResult pushInline "Inline" "code element" + , mkInlinesConstr "Emph" Emph + , defun "Image" + ### liftPure4 (\caption src mtitle mattr -> + let attr = fromMaybe nullAttr mattr + title = fromMaybe mempty mtitle + in Image attr caption (src, title)) + <#> parameter peekFuzzyInlines "Inlines" "caption" "image caption / alt" + <#> parameter peekText "string" "src" "path/URL of the image file" + <#> optionalParameter peekText "string" "title" "brief image description" + <#> optionalParameter peekAttr "Attr" "attr" "image attributes" + =#> functionResult pushInline "Inline" "image element" + , defun "LineBreak" + ### return LineBreak + =#> functionResult pushInline "Inline" "line break" + , defun "Link" + ### liftPure4 (\content target mtitle mattr -> + let attr = fromMaybe nullAttr mattr + title = fromMaybe mempty mtitle + in Link attr content (target, title)) + <#> parameter peekFuzzyInlines "Inlines" "content" "text for this link" + <#> parameter peekText "string" "target" "the link target" + <#> optionalParameter peekText "string" "title" "brief link description" + <#> optionalParameter peekAttr "Attr" "attr" "link attributes" + =#> functionResult pushInline "Inline" "link element" + , defun "Math" + ### liftPure2 Math + <#> parameter peekMathType "quotetype" "Math" "rendering method" + <#> parameter peekText "text" "string" "math content" + =#> functionResult pushInline "Inline" "math element" + , defun "Note" + ### liftPure Note + <#> parameter peekFuzzyBlocks "content" "Blocks" "note content" + =#> functionResult pushInline "Inline" "note" + , defun "Quoted" + ### liftPure2 Quoted + <#> parameter peekQuoteType "quotetype" "QuoteType" "type of quotes" + <#> parameter peekFuzzyInlines "content" "Inlines" "inlines in quotes" + =#> functionResult pushInline "Inline" "quoted element" + , defun "RawInline" + ### liftPure2 RawInline + <#> parameter peekFormat "format" "Format" "format of content" + <#> parameter peekText "text" "string" "string content" + =#> functionResult pushInline "Inline" "raw inline element" + , mkInlinesConstr "SmallCaps" SmallCaps + , defun "SoftSpace" + ### return SoftBreak + =#> functionResult pushInline "Inline" "soft break" + , defun "Space" + ### return Space + =#> functionResult pushInline "Inline" "new space" + , defun "Span" + ### liftPure2 (\inlns mattr -> Span (fromMaybe nullAttr mattr) inlns) + <#> parameter peekFuzzyInlines "content" "Inlines" "inline content" + <#> optionalParameter peekAttr "attr" "Attr" "additional attributes" + =#> functionResult pushInline "Inline" "span element" + , defun "Str" + ### liftPure (\s -> s `seq` Str s) + <#> parameter peekText "text" "string" "" + =#> functionResult pushInline "Inline" "new Str object" + , mkInlinesConstr "Strong" Strong + , mkInlinesConstr "Strikeout" Strikeout + , mkInlinesConstr "Subscript" Subscript + , mkInlinesConstr "Superscript" Superscript + , mkInlinesConstr "Underline" Underline + ] + +mkInlinesConstr :: LuaError e + => Name -> ([Inline] -> Inline) -> DocumentedFunction e +mkInlinesConstr name constr = defun name + ### liftPure (\x -> x `seq` constr x) + <#> parameter peekFuzzyInlines "content" "Inlines" "" + =#> functionResult pushInline "Inline" "new object" + + walkElement :: (Walkable (SingletonsList Inline) a, Walkable (SingletonsList Block) a, Walkable (List Inline) a, |