{-# LANGUAGE OverloadedStrings, MultiParamTypeClasses #-}
module Text.Pandoc.CrossRef.Util.Template
( Template
, BlockTemplate
, makeTemplate
, makeIndexedTemplate
, applyTemplate
, applyTemplate'
) where
import Control.Applicative
import Data.Data
import qualified Data.Map as M hiding (fromList, singleton, toList)
import qualified Data.Text as T
import Text.Pandoc.Builder
import Text.Pandoc.CrossRef.Util.Meta
import Text.Pandoc.Generic
import Text.Read
type VarFunc = T.Text -> Maybe MetaValue
newtype Template = Template (VarFunc -> [Inline])
newtype BlockTemplate = BlockTemplate (VarFunc -> [Block])
class Data a => MkTemplate a b where
mkTemplate :: (VarFunc -> [a]) -> b
applyTemplate' :: M.Map T.Text [Inline] -> b -> [a]
instance MkTemplate Inline Template where
mkTemplate :: (VarFunc -> [Inline]) -> Template
mkTemplate = (VarFunc -> [Inline]) -> Template
Template
applyTemplate' :: Map Text [Inline] -> Template -> [Inline]
applyTemplate' Map Text [Inline]
vars (Template VarFunc -> [Inline]
g) = VarFunc -> [Inline]
g (Map Text [Inline] -> VarFunc
internalVars Map Text [Inline]
vars)
instance MkTemplate Block BlockTemplate where
mkTemplate :: (VarFunc -> [Block]) -> BlockTemplate
mkTemplate = (VarFunc -> [Block]) -> BlockTemplate
BlockTemplate
applyTemplate' :: Map Text [Inline] -> BlockTemplate -> [Block]
applyTemplate' Map Text [Inline]
vars (BlockTemplate VarFunc -> [Block]
g) = VarFunc -> [Block]
g (Map Text [Inline] -> VarFunc
internalVars Map Text [Inline]
vars)
makeTemplate :: MkTemplate a b => Meta -> [a] -> b
makeTemplate :: forall a b. MkTemplate a b => Meta -> [a] -> b
makeTemplate Meta
dtv [a]
xs' = (VarFunc -> [a]) -> b
forall a b. MkTemplate a b => (VarFunc -> [a]) -> b
mkTemplate ((VarFunc -> [a]) -> b) -> (VarFunc -> [a]) -> b
forall a b. (a -> b) -> a -> b
$ \VarFunc
vf -> VarFunc -> [a] -> [a]
scan (\Text
var -> VarFunc
vf Text
var Maybe MetaValue -> Maybe MetaValue -> Maybe MetaValue
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Text -> Meta -> Maybe MetaValue
lookupMeta Text
var Meta
dtv) [a]
xs'
where
scan :: VarFunc -> [a] -> [a]
scan = ([Inline] -> [Inline]) -> [a] -> [a]
forall a b. (Data a, Data b) => (a -> a) -> b -> b
bottomUp (([Inline] -> [Inline]) -> [a] -> [a])
-> (VarFunc -> [Inline] -> [Inline]) -> VarFunc -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VarFunc -> [Inline] -> [Inline]
go
go :: VarFunc -> [Inline] -> [Inline]
go VarFunc
vf (x :: Inline
x@(Math MathType
DisplayMath Text
var):[Inline]
xs)
| (Text
vn, Text
idxBr) <- (Char -> Bool) -> Text -> (Text, Text)
T.span (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/=Char
'[') Text
var
, Bool -> Bool
not (Text -> Bool
T.null Text
idxBr)
, HasCallStack => Text -> Char
Text -> Char
T.last Text
idxBr Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
']'
= let idxVar :: Text
idxVar = Int -> Text -> Text
T.drop Int
1 (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Text -> Text
T.takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/=Char
']') Text
idxBr
idx :: Maybe Int
idx = String -> Maybe Int
forall a. Read a => String -> Maybe a
readMaybe (String -> Maybe Int)
-> (MetaValue -> String) -> MetaValue -> Maybe Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
T.unpack (Text -> String) -> (MetaValue -> Text) -> MetaValue -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> MetaValue -> Text
toString (Text
"index variable " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
idxVar) (MetaValue -> Maybe Int) -> Maybe MetaValue -> Maybe Int
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< VarFunc
vf Text
idxVar
arr :: Maybe MetaValue
arr = do
Int
i <- Maybe Int
idx
MetaValue
v <- Text -> Meta -> Maybe MetaValue
lookupMeta Text
vn Meta
dtv
Int -> MetaValue -> Maybe MetaValue
getList Int
i MetaValue
v
in Many Inline -> [Inline]
forall a. Many a -> [a]
toList (Many Inline -> [Inline]) -> Many Inline -> [Inline]
forall a b. (a -> b) -> a -> b
$ [Inline] -> Many Inline
forall a. [a] -> Many a
fromList (Text -> Maybe MetaValue -> [Inline] -> [Inline]
replaceVar Text
var Maybe MetaValue
arr [Inline
x]) Many Inline -> Many Inline -> Many Inline
forall a. Semigroup a => a -> a -> a
<> [Inline] -> Many Inline
forall a. [a] -> Many a
fromList [Inline]
xs
| Bool
otherwise = Many Inline -> [Inline]
forall a. Many a -> [a]
toList (Many Inline -> [Inline]) -> Many Inline -> [Inline]
forall a b. (a -> b) -> a -> b
$ [Inline] -> Many Inline
forall a. [a] -> Many a
fromList (Text -> Maybe MetaValue -> [Inline] -> [Inline]
replaceVar Text
var (VarFunc
vf Text
var) [Inline
x]) Many Inline -> Many Inline -> Many Inline
forall a. Semigroup a => a -> a -> a
<> [Inline] -> Many Inline
forall a. [a] -> Many a
fromList [Inline]
xs
go VarFunc
_ (Inline
x:[Inline]
xs) = Many Inline -> [Inline]
forall a. Many a -> [a]
toList (Many Inline -> [Inline]) -> Many Inline -> [Inline]
forall a b. (a -> b) -> a -> b
$ Inline -> Many Inline
forall a. a -> Many a
singleton Inline
x Many Inline -> Many Inline -> Many Inline
forall a. Semigroup a => a -> a -> a
<> [Inline] -> Many Inline
forall a. [a] -> Many a
fromList [Inline]
xs
go VarFunc
_ [] = []
replaceVar :: Text -> Maybe MetaValue -> [Inline] -> [Inline]
replaceVar Text
var Maybe MetaValue
val [Inline]
def' = [Inline] -> (MetaValue -> [Inline]) -> Maybe MetaValue -> [Inline]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Inline]
def' (Text -> MetaValue -> [Inline]
toInlines (Text
"variable " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
var)) Maybe MetaValue
val
makeIndexedTemplate :: T.Text -> Meta -> T.Text -> Template
makeIndexedTemplate :: Text -> Meta -> Text -> Template
makeIndexedTemplate Text
name Meta
meta Text
subname =
Meta -> [Inline] -> Template
forall a b. MkTemplate a b => Meta -> [a] -> b
makeTemplate Meta
meta ([Inline] -> Template) -> [Inline] -> Template
forall a b. (a -> b) -> a -> b
$ case Text -> Meta -> Maybe MetaValue
lookupMeta Text
name Meta
meta of
Just (MetaMap Map Text MetaValue
m) -> case Text -> Meta -> Maybe MetaValue
lookupMeta Text
subname (Map Text MetaValue -> Meta
Meta Map Text MetaValue
m) of
Just MetaValue
x -> Text -> MetaValue -> [Inline]
toInlines Text
name MetaValue
x
Maybe MetaValue
Nothing -> Text -> Meta -> [Inline]
getMetaInlines Text
"default" (Map Text MetaValue -> Meta
Meta Map Text MetaValue
m)
Just MetaValue
x -> Text -> MetaValue -> [Inline]
toInlines Text
name MetaValue
x
Maybe MetaValue
Nothing -> []
internalVars :: M.Map T.Text [Inline] -> T.Text -> Maybe MetaValue
internalVars :: Map Text [Inline] -> VarFunc
internalVars Map Text [Inline]
vars Text
x = [Inline] -> MetaValue
MetaInlines ([Inline] -> MetaValue) -> Maybe [Inline] -> Maybe MetaValue
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> Map Text [Inline] -> Maybe [Inline]
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Text
x Map Text [Inline]
vars
applyTemplate :: MkTemplate a b => [Inline] -> [Inline] -> b -> [a]
applyTemplate :: forall a b. MkTemplate a b => [Inline] -> [Inline] -> b -> [a]
applyTemplate [Inline]
i [Inline]
t =
Map Text [Inline] -> b -> [a]
forall a b. MkTemplate a b => Map Text [Inline] -> b -> [a]
applyTemplate' ([(Text, [Inline])] -> Map Text [Inline]
forall k a. [(k, a)] -> Map k a
M.fromDistinctAscList [(Text
"i", [Inline]
i), (Text
"t", [Inline]
t)])