{-# LANGUAGE OverloadedStrings #-}
module Text.Pandoc.CrossRef.Util.Template
( Template
, makeTemplate
, makeIndexedTemplate
, applyTemplate
, applyTemplate'
) where
import Text.Pandoc.Definition
import Text.Pandoc.Builder
import Text.Pandoc.Generic
import qualified Data.Map as M hiding (toList, fromList, singleton)
import Text.Pandoc.CrossRef.Util.Meta
import Control.Applicative
import Text.Read
import qualified Data.Text as T
type VarFunc = T.Text -> Maybe MetaValue
newtype Template = Template (VarFunc -> [Inline])
makeTemplate :: Meta -> [Inline] -> Template
makeTemplate :: Meta -> [Inline] -> Template
makeTemplate Meta
dtv [Inline]
xs' = (VarFunc -> [Inline]) -> Template
Template ((VarFunc -> [Inline]) -> Template)
-> (VarFunc -> [Inline]) -> Template
forall a b. (a -> b) -> a -> b
$ \VarFunc
vf -> VarFunc -> [Inline] -> [Inline]
scan (\Text
var -> VarFunc
vf Text
var Maybe MetaValue -> Maybe MetaValue -> Maybe MetaValue
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Text -> Meta -> Maybe MetaValue
lookupMeta Text
var Meta
dtv) [Inline]
xs'
where
scan :: VarFunc -> [Inline] -> [Inline]
scan = ([Inline] -> [Inline]) -> [Inline] -> [Inline]
forall a b. (Data a, Data b) => (a -> a) -> b -> b
bottomUp (([Inline] -> [Inline]) -> [Inline] -> [Inline])
-> (VarFunc -> [Inline] -> [Inline])
-> VarFunc
-> [Inline]
-> [Inline]
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)
, 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
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 -> []
applyTemplate' :: M.Map T.Text [Inline] -> Template -> [Inline]
applyTemplate' :: Map Text [Inline] -> Template -> [Inline]
applyTemplate' Map Text [Inline]
vars (Template VarFunc -> [Inline]
g) = VarFunc -> [Inline]
g VarFunc
internalVars
where
internalVars :: VarFunc
internalVars Text
x | Just [Inline]
v <- 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 = MetaValue -> Maybe MetaValue
forall a. a -> Maybe a
Just (MetaValue -> Maybe MetaValue) -> MetaValue -> Maybe MetaValue
forall a b. (a -> b) -> a -> b
$ [Inline] -> MetaValue
MetaInlines [Inline]
v
internalVars Text
_ = Maybe MetaValue
forall a. Maybe a
Nothing
applyTemplate :: [Inline] -> [Inline] -> Template -> [Inline]
applyTemplate :: [Inline] -> [Inline] -> Template -> [Inline]
applyTemplate [Inline]
i [Inline]
t =
Map Text [Inline] -> Template -> [Inline]
applyTemplate' ([(Text, [Inline])] -> Map Text [Inline]
forall k a. [(k, a)] -> Map k a
M.fromDistinctAscList [(Text
"i", [Inline]
i), (Text
"t", [Inline]
t)])