@@ -46,10 +46,11 @@ is used.
4646module Text.Pandoc.Templates (renderTemplate, getDefaultTemplate) where
4747
4848import Text.ParserCombinators.Parsec
49−import Control.Monad (liftM)
49+import Control.Monad (liftM, when)
5050import qualified Control.Exception as E (try, IOException)
5151import System.FilePath
5252import Text.Pandoc.Shared (readDataFile)
53+import Data.List (intercalate)
5354
5455-- | Get the default template, either from the application's user data
5556-- directory (~/.pandoc on unix) or from the cabal data directory.
@@ -60,51 +61,67 @@ getDefaultTemplate "odt" = getDefaultTemplate "opendocument"
6061getDefaultTemplate format = do
6162 let format' = takeWhile (/='+') format -- strip off "+lhs" if present
6263 E.try $ readDataFile $ "templates" </> format' <.> "template"
63−
64+
65+data TemplateState = TemplateState Int [(String,String)]
66+
67+adjustPosition :: String -> GenParser Char TemplateState String
68+adjustPosition str = do
69+ let lastline = takeWhile (/= '\n') $ reverse str
70+ updateState $ \(TemplateState pos x) ->
71+ if str == lastline
72+ then TemplateState (pos + length lastline) x
73+ else TemplateState (length lastline) x
74+ return str
75+
6476-- | Renders a template
6577renderTemplate :: [(String,String)] -- ^ Assoc. list of values for variables
6678 -> String -- ^ Template
6779 -> String
6880renderTemplate vals templ =
69− case runParser (do x <- parseTemplate; eof; return x) vals "template" templ of
81+ case runParser (do x <- parseTemplate; eof; return x) (TemplateState 0 vals) "template" templ of
7082 Left e -> error $ show e
7183 Right r -> concat r
7284
7385reservedWords :: [String]
7486reservedWords = ["else","endif"]
7587
76−parseTemplate :: GenParser Char [(String,String)] [String]
88+parseTemplate :: GenParser Char TemplateState [String]
7789parseTemplate =
78− many $ plaintext <|> escapedDollar <|> conditional <|> variable
90+ many $ (plaintext <|> escapedDollar <|> conditional <|> variable)
91+ >>= adjustPosition
7992
80−plaintext :: GenParser Char [(String,String)] String
81−plaintext = many1 $ satisfy (/='$')
93+plaintext :: GenParser Char TemplateState String
94+plaintext = many1 $ noneOf "$"
8295
83−escapedDollar :: GenParser Char [(String,String)] String
96+escapedDollar :: GenParser Char TemplateState String
8497escapedDollar = try $ string "$$" >> return "$"
8598
86−conditional :: GenParser Char [(String,String)] String
99+conditional :: GenParser Char TemplateState String
87100conditional = try $ do
101+ TemplateState pos vars <- getState
88102 string "$if("
89103 id' <- ident
90104 string ")$"
91− skipMany (oneOf " \t")
92− optional newline
93− ifContents <- liftM concat parseTemplate
94− elseContents <- option "" $ do try (string "$else$")
95− skipMany (oneOf " \t")
96− optional newline
97− liftM concat parseTemplate
105+ -- if newline after the "if", then a newline after "endif" will be swallowed
106+ multiline <- option False $ try $
107+ newline >> count pos (char ' ') >> return True
108+ let conditionSatisfied = case lookup id' vars of
109+ Nothing -> False
110+ Just "" -> False
111+ Just _ -> True
112+ contents <- if conditionSatisfied
113+ then liftM concat parseTemplate
114+ else do
115+ parseTemplate -- skip if part, then reset position
116+ setState $ TemplateState pos vars
117+ option "" $ do try (string "$else$")
118+ optional newline
119+ liftM concat parseTemplate
98120 string "$endif$"
99− skipMany (oneOf " \t")
100− optional newline
101− st <- getState
102− return $ case lookup id' st of
103− Just "" -> elseContents
104− Just _ -> ifContents
105− Nothing -> elseContents
106−
107−ident :: GenParser Char [(String,String)] String
121+ when multiline $ optional $ newline
122+ return contents
123+
124+ident :: GenParser Char TemplateState String
108125ident = do
109126 first <- letter
110127 rest <- many (alphaNum <|> oneOf "_-")
@@ -113,12 +130,13 @@ ident = do
113130 then pzero
114131 else return id'
115132
116−variable :: GenParser Char [(String,String)] String
133+variable :: GenParser Char TemplateState String
117134variable = try $ do
118135 char '$'
119136 id' <- ident
120137 char '$'
121− st <- getState
122− return $ case lookup id' st of
123− Just val -> val
124− Nothing -> ""
138+ TemplateState pos vars <- getState
139+ let indent = replicate pos ' '
140+ return $ case lookup id' vars of
141+ Just val -> intercalate ('\n' : indent) $ lines val
142+ Nothing -> ""