@@ -1,4 +1,6 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE MultiParamTypeClasses #-}
2{-# LANGUAGE ScopedTypeVariables #-}
4{-# LANGUAGE ScopedTypeVariables #-}
4Copyright (C) 2006-2017 John MacFarlane <jgm@berkeley.edu>
6Copyright (C) 2006-2017 John MacFarlane <jgm@berkeley.edu>
@@ -39,10 +41,12 @@ import Control.Applicative (many, optional, (<|>))
39import Control.Monad
41import Control.Monad
40import Control.Monad.Except (throwError)
42import Control.Monad.Except (throwError)
41import Data.Char (chr, isAlphaNum, isLetter, ord, isDigit)
43import Data.Char (chr, isAlphaNum, isLetter, ord, isDigit)
42import Data.Text (Text, unpack)
45import Data.Text (Text, unpack)
43import qualified Data.Text as T
46import qualified Data.Text as T
44import Data.List (intercalate, isPrefixOf)
47import Data.List (intercalate, isPrefixOf)
45import qualified Data.Map as M
48import qualified Data.Map as M
49+import qualified Data.Set as Set
46import Data.Maybe (fromMaybe, maybeToList)
50import Data.Maybe (fromMaybe, maybeToList)
47import Safe (minimumDef)
51import Safe (minimumDef)
48import System.FilePath (addExtension, replaceExtension, takeExtension)
52import System.FilePath (addExtension, replaceExtension, takeExtension)
@@ -70,7 +74,7 @@ readLaTeX :: PandocMonad m
70 -> Text -- ^ String to parse (assumes @'\n'@ line endings)
74 -> Text -- ^ String to parse (assumes @'\n'@ line endings)
71 -> m Pandoc
75 -> m Pandoc
72readLaTeX opts ltx = do
76readLaTeX opts ltx = do
73− parsed <- runParserT parseLaTeX def{ stateOptions = opts } "source"
77+ parsed <- runParserT parseLaTeX def{ sOptions = opts } "source"
74 (tokenize (crFilter ltx))
78 (tokenize (crFilter ltx))
75 case parsed of
79 case parsed of
76 Right result -> return result
80 Right result -> return result
@@ -81,7 +85,7 @@ parseLaTeX = do
81 bs <- blocks
85 bs <- blocks
83 st <- getState
87 st <- getState
84− let meta = stateMeta st
88+ let meta = sMeta st
85 let doc' = doc bs
89 let doc' = doc bs
86 let headerLevel (Header n _ _) = [n]
90 let headerLevel (Header n _ _) = [n]
87 headerLevel _ = []
91 headerLevel _ = []
@@ -97,22 +101,85 @@ parseLaTeX = do
98testParser :: LP PandocIO a -> Text -> IO a
102testParser :: LP PandocIO a -> Text -> IO a
99testParser p t = do
103testParser p t = do
100− res <- runIOorExplode (runParserT p defaultParserState{
104+ res <- runIOorExplode (runParserT p defaultLaTeXState{
101− stateOptions = def{ readerExtensions =
105+ sOptions = def{ readerExtensions =
102 getDefaultExtensions "latex" }} "name" (tokenize t))
106 getDefaultExtensions "latex" }} "name" (tokenize t))
103 case res of
107 case res of
104 Left e -> error (show e)
108 Left e -> error (show e)
105 Right r -> return r
109 Right r -> return r
111+data Macro = Macro -- TODO
114+data LaTeXState = LaTeXState{ sOptions :: ReaderOptions
116+ , sQuoteContext :: QuoteContext
117+ , sMacros :: [Macro]
118+ , sContainers :: [String]
119+ , sHeaders :: M.Map Inlines String
120+ , sLogMessages :: [LogMessage]
121+ , sIdentifiers :: Set.Set String }
124+defaultLaTeXState :: LaTeXState
125+defaultLaTeXState = LaTeXState{ sOptions = def
127+ , sQuoteContext = NoQuote
130+ , sHeaders = M.empty
132+ , sIdentifiers = Set.empty }
134+instance PandocMonad m => HasQuoteContext LaTeXState m where
135+ getQuoteContext = sQuoteContext <$> getState
136+ withQuoteContext context parser = do
137+ oldState <- getState
138+ let oldQuoteContext = sQuoteContext oldState
139+ setState oldState { sQuoteContext = context }
141+ newState <- getState
142+ setState newState { sQuoteContext = oldQuoteContext }
145+instance HasLogMessages LaTeXState where
146+ addLogMessage msg st = st{ sLogMessages = msg : sLogMessages st }
147+ getLogMessages st = reverse $ sLogMessages st
149+instance HasIdentifierList LaTeXState where
150+ extractIdentifierList = sIdentifiers
151+ updateIdentifierList f st = st{ sIdentifiers = f $ sIdentifiers st }
153+instance HasIncludeFiles LaTeXState where
154+ getIncludeFiles = sContainers
155+ addIncludeFile f s = s{ sContainers = f : sContainers s }
156+ dropLatestIncludeFile s = s { sContainers = drop 1 $ sContainers s }
158+instance HasHeaderMap LaTeXState where
159+ extractHeaderMap = sHeaders
160+ updateHeaderMap f st = st{ sHeaders = f $ sHeaders st }
162+instance HasReaderOptions LaTeXState where
163+ extractReaderOptions = sOptions
165+instance HasMeta LaTeXState where
166+ setMeta field val st =
167+ st{ sMeta = setMeta field val $ sMeta st }
168+ deleteMeta field st =
169+ st{ sMeta = deleteMeta field $ sMeta st }
171+instance Default LaTeXState where
172+ def = defaultLaTeXState
107−type LP m = ParserT [Tok] ParserState m
174+type LP m = ParserT [Tok] LaTeXState m
109−rawLaTeXBlock :: PandocMonad m => ParserT String ParserState m String
176+rawLaTeXBlock :: PandocMonad m => ParserT String LaTeXState m String
110rawLaTeXBlock = mzero
177rawLaTeXBlock = mzero
112−rawLaTeXInline :: PandocMonad m => ParserT String ParserState m Inline
179+rawLaTeXInline :: PandocMonad m => ParserT String LaTeXState m Inline
113rawLaTeXInline = mzero
180rawLaTeXInline = mzero
115−inlineCommand :: PandocMonad m => ParserT String ParserState m Inlines
182+inlineCommand :: PandocMonad m => ParserT String LaTeXState m Inlines
116inlineCommand = mzero
183inlineCommand = mzero
118data TokType = CtrlSeq | Spaces | Newline | Symbol | Word | Comment |
185data TokType = CtrlSeq | Spaces | Newline | Symbol | Word | Comment |
@@ -206,11 +273,11 @@ satisfyTok f =
206 setSourceColumn (setSourceLine spos lin) col
273 setSourceColumn (setSourceLine spos lin) col
207 updatePos spos _ [] = spos
274 updatePos spos _ [] = spos
209−-- TODO use something other than ParserState
276+-- TODO use something other than LaTeXState
210doMacros :: PandocMonad m => LP m ()
277doMacros :: PandocMonad m => LP m ()
211doMacros = do
278doMacros = do
212 inp <- getInput
279 inp <- getInput
213− macros <- stateMacros <$> getState
280+ macros <- sMacros <$> getState
214 case inp of
281 case inp of
215 t@(Tok spos CtrlSeq txt) : ts
282 t@(Tok spos CtrlSeq txt) : ts
216 | txt == "\\macro" -> do -- TODO actually check macros
283 | txt == "\\macro" -> do -- TODO actually check macros
@@ -419,8 +486,8 @@ quoted' f starter ender = do
419enquote :: PandocMonad m => LP m Inlines
486enquote :: PandocMonad m => LP m Inlines
420enquote = do
487enquote = do
422− context <- stateQuoteContext <$> getState
489+ quoteContext <- sQuoteContext <$> getState
423− if context == InDoubleQuote
490+ if quoteContext == InDoubleQuote
424 then singleQuoted <$> withQuoteContext InSingleQuote tok
491 then singleQuoted <$> withQuoteContext InSingleQuote tok
425 else doubleQuoted <$> withQuoteContext InDoubleQuote tok
492 else doubleQuoted <$> withQuoteContext InDoubleQuote tok
@@ -1119,7 +1186,7 @@ ignoreBlocks name = (name, p)
1120addMeta :: PandocMonad m => ToMetaValue a => String -> a -> LP m ()
1187addMeta :: PandocMonad m => ToMetaValue a => String -> a -> LP m ()
1121addMeta field val = updateState $ \st ->
1188addMeta field val = updateState $ \st ->
1122− st{ stateMeta = addMetaField field val $ stateMeta st }
1189+ st{ sMeta = addMetaField field val $ sMeta st }
1124authors :: PandocMonad m => LP m ()
1191authors :: PandocMonad m => LP m ()
1125authors = try $ do
1192authors = try $ do
@@ -1165,7 +1232,7 @@ closing = do
1165 let extractInlines (MetaBlocks [Plain ys]) = ys
1232 let extractInlines (MetaBlocks [Plain ys]) = ys
1166 extractInlines (MetaBlocks [Para ys ]) = ys
1233 extractInlines (MetaBlocks [Para ys ]) = ys
1167 extractInlines _ = []
1234 extractInlines _ = []
1168− let sigs = case lookupMeta "author" (stateMeta st) of
1235+ let sigs = case lookupMeta "author" (sMeta st) of
1169 Just (MetaList xs) ->
1236 Just (MetaList xs) ->
1170 para $ trimInlines $ fromList $
1237 para $ trimInlines $ fromList $
1171 intercalate [LineBreak] $ map extractInlines xs
1238 intercalate [LineBreak] $ map extractInlines xs
@@ -1371,7 +1438,7 @@ blocks = mconcat <$> many block
1372-- addMeta :: PandocMonad m => ToMetaValue a => String -> a -> LP m ()
1439-- addMeta :: PandocMonad m => ToMetaValue a => String -> a -> LP m ()
1373-- addMeta field val = updateState $ \st ->
1440-- addMeta field val = updateState $ \st ->
1374−-- st{ stateMeta = addMetaField field val $ stateMeta st }
1441+-- st{ sMeta = addMetaField field val $ sMeta st }
1376-- splitBibs :: String -> [Inlines]
1443-- splitBibs :: String -> [Inlines]
1377-- splitBibs = map (str . flip replaceExtension "bib" . trim) . splitBy (==',')
1444-- splitBibs = map (str . flip replaceExtension "bib" . trim) . splitBy (==',')
@@ -1464,10 +1531,10 @@ blocks = mconcat <$> many block
1464-- where strToCode (Str s) = Code nullAttr s
1531-- where strToCode (Str s) = Code nullAttr s
1465-- strToCode x = x
1532-- strToCode x = x
1467−-- rawLaTeXBlock :: PandocMonad m => ParserT String ParserState String
1534+-- rawLaTeXBlock :: PandocMonad m => ParserT String LaTeXState String
1468-- rawLaTeXBlock = snd <$> try (withRaw (environment <|> blockCommand))
1535-- rawLaTeXBlock = snd <$> try (withRaw (environment <|> blockCommand))
1470−-- rawLaTeXInline :: PandocMonad m => ParserT String ParserState Inline
1537+-- rawLaTeXInline :: PandocMonad m => ParserT String LaTeXState Inline
1471-- rawLaTeXInline = do
1538-- rawLaTeXInline = do
1472-- raw <- (snd <$> withRaw inlineCommand)
1539-- raw <- (snd <$> withRaw inlineCommand)
1473-- <|> (snd <$> withRaw inlineEnvironment)
1540-- <|> (snd <$> withRaw inlineEnvironment)
@@ -1504,7 +1571,7 @@ blocks = mconcat <$> many block
1504-- bs <- blocks
1571-- bs <- blocks
1505-- st <- getState
1572-- st <- getState
1506-- -- add signature (author) and address (title)
1573-- -- add signature (author) and address (title)
1507−-- let addr = case lookupMeta "address" (stateMeta st) of
1574+-- let addr = case lookupMeta "address" (sMeta st) of
1508-- Just (MetaBlocks [Plain xs]) ->
1575-- Just (MetaBlocks [Plain xs]) ->
1509-- para $ trimInlines $ fromList xs
1576-- para $ trimInlines $ fromList xs
1510-- _ -> mempty
1577-- _ -> mempty