@@ -199,8 +199,23 @@ blockCommand = try $ do
199199inBrackets :: Inlines -> Inlines
200200inBrackets x = (str "[") <> x <> (str "]")
201201
202+-- eat an optional argument and one or more arguments in braces
203+ignoreInlines :: String -> (String, LP Inlines)
204+ignoreInlines name = (name, doraw <|> (mempty <$ optargs))
205+ where optargs = optional opt *> skipMany (optional sp *> braced)
206+ contseq = '\\':name
207+ doraw = (rawInline "latex" . (contseq ++) . snd) <$>
208+ (getState >>= guard . stateParseRaw >> (withRaw optargs))
209+
210+ignoreBlocks :: String -> (String, LP Blocks)
211+ignoreBlocks name = (name, doraw <|> (mempty <$ optargs))
212+ where optargs = optional opt *> skipMany (optional sp *> braced)
213+ contseq = '\\':name
214+ doraw = (rawBlock "latex" . (contseq ++) . snd) <$>
215+ (getState >>= guard . stateParseRaw >> (withRaw optargs))
216+
202217blockCommands :: M.Map String (LP Blocks)
203−blockCommands = M.fromList
218+blockCommands = M.fromList $
204219 [ ("par", pure mempty)
205220 , ("title", mempty <$ (tok >>= addTitle))
206221 , ("subtitle", mempty <$ (tok >>= addSubtitle))
@@ -209,11 +224,7 @@ blockCommands = M.fromList
209224 , ("address", mempty <$ (tok >>= addTitle))
210225 , ("signature", mempty <$ authors)
211226 , ("date", mempty <$ (tok >>= addDate))
212− , ("maketitle", pure mempty)
213− -- \ignore{} is used conventionally in literate haskell for definitions
214− -- that are to be processed by the compiler but not printed.
215− , ("ignore", mempty <$ tok)
216− , ("hyperdef", mempty <$ (tok *> tok))
227+ -- sectioning
217228 , ("chapter", updateState (\s -> s{ stateHasChapters = True }) *> section 0)
218229 , ("section", section 1)
219230 , ("subsection", section 2)
@@ -221,23 +232,27 @@ blockCommands = M.fromList
221232 , ("paragraph", section 4)
222233 , ("subparagraph", section 5)
223234 , ("opening", (para . trimInlines) <$> tok)
224− , ("closing", (para . trimInlines) <$> tok)
235+ , ("closing", closing)
225236 , ("rule", optional opt *> tok *> tok *> pure horizontalRule)
226237 , ("begin", mzero) -- these are here so they won't be interpreted as inline
227238 , ("end", mzero)
228239 , ("item", loose_item)
229240 , ("documentclass", optional opt *> braced *> preamble)
230− -- should be parsed by macro, but we need this
231− -- here so these aren't parsed as inline
232− , ("newcommand", mempty <$ (tok *> optional opt *> tok))
233− , ("renewcommand", mempty <$ (tok *> optional opt *> tok))
234− , ("newenvironment", mempty <$ (tok *> tok *> tok))
235− , ("renewenvironment", mempty <$ (tok *> tok *> tok))
236− , ("special", pure mempty)
237− , ("pdfannot", pure mempty)
238− , ("pdfstringdef", pure mempty)
239− , ("index", pure mempty)
240− , ("bibliography", pure mempty)
241+ ] ++ map ignoreBlocks
242+ -- these commands will be ignored unless --parse-raw is specified,
243+ -- in which case they will appear as raw latex blocks
244+ [ "newcommand", "renewcommand", "newenvironment", "renewenvironment"
245+ -- newcommand, etc. should be parsed by macro, but we need this
246+ -- here so these aren't parsed as inline commands to ignore
247+ , "special", "pdfannot", "pdfstringdef"
248+ , "bibliography", "maketitle", "makeindex", "makeglossary"
249+ , "addcontentsline", "addtocontents", "addtocounter"
250+ -- \ignore{} is used conventionally in literate haskell for definitions
251+ -- that are to be processed by the compiler but not printed.
252+ , "ignore"
253+ , "hyperdef"
254+ , "noindent"
255+ , "markboth", "markright", "markleft"
241256 ]
242257
243258addTitle :: Inlines -> LP ()
@@ -288,7 +303,7 @@ isBlockCommand :: String -> Bool
288303isBlockCommand s = maybe False (const True) $ M.lookup s blockCommands
289304
290305inlineCommands :: M.Map String (LP Inlines)
291−inlineCommands = M.fromList
306+inlineCommands = M.fromList $
292307 [ ("emph", emph <$> tok)
293308 , ("textit", emph <$> tok)
294309 , ("textsc", smallcaps <$> tok)
@@ -307,6 +322,8 @@ inlineCommands = M.fromList
307322 , ("(", mathInline $ manyTill anyChar (try $ string "\\)"))
308323 , ("[", mathDisplay $ manyTill anyChar (try $ string "\\]"))
309324 , ("ensuremath", mathInline $ braced)
325+ , ("P", lit "¶")
326+ , ("S", lit "§")
310327 , ("$", lit "$")
311328 , ("%", lit "%")
312329 , ("&", lit "&")
@@ -339,7 +356,6 @@ inlineCommands = M.fromList
339356 , ("pounds", lit "£")
340357 , ("euro", lit "€")
341358 , ("copyright", lit "©")
342− , ("sect", lit "§")
343359 , ("`", option (str "`") $ try $ tok >>= accent grave)
344360 , ("'", option (str "'") $ try $ tok >>= accent acute)
345361 , ("^", option (str "^") $ try $ tok >>= accent hat)
@@ -352,6 +368,7 @@ inlineCommands = M.fromList
352368 , (",", pure mempty)
353369 , ("@", pure mempty)
354370 , (" ", lit "\160")
371+ , ("ps", pure $ str "PS." <> space)
355372 , ("bar", lit "|")
356373 , ("textless", lit "<")
357374 , ("textgreater", lit ">")
@@ -417,7 +434,10 @@ inlineCommands = M.fromList
417434 , ("citeauthor", (try (tok *> optional sp *> controlSeq "citetext") *>
418435 complexNatbibCitation AuthorInText)
419436 <|> citation AuthorInText False)
420− ]
437+ ] ++ map ignoreInlines
438+ -- these commands will be ignored unless --parse-raw is specified,
439+ -- in which case they will appear as raw latex blocks:
440+ [ "index" ]
421441
422442unescapeURL :: String -> String
423443unescapeURL ('\\':x:xs) | isEscapable x = x:unescapeURL xs
@@ -573,7 +593,8 @@ handleIncludes ('\\':xs) =
573593 yss <- mapM getfile fs
574594 (intercalate "\n" yss ++) `fmap`
575595 handleIncludes rest
576− _ -> case runParser verbatimEnv defaultParserState "input" ('\\':xs) of
596+ _ -> case runParser (verbCmd <|> verbatimEnv) defaultParserState
597+ "input" ('\\':xs) of
577598 Right (r, rest) -> (r ++) `fmap` handleIncludes rest
578599 _ -> ('\\':) `fmap` handleIncludes xs
579600handleIncludes (x:xs) = (x:) `fmap` handleIncludes xs
@@ -589,6 +610,15 @@ include = do
589610 else map (flip replaceExtension ".sty") fs
590611 return (fs', rest)
591612
613+verbCmd :: LP (String, String)
614+verbCmd = do
615+ (_,r) <- withRaw $ do
616+ controlSeq "verb"
617+ c <- anyChar
618+ manyTill anyChar (char c)
619+ rest <- getInput
620+ return (r, rest)
621+
592622verbatimEnv :: LP (String, String)
593623verbatimEnv = do
594624 (_,r) <- withRaw $ do
@@ -659,12 +689,19 @@ letter_contents = do
659689 -- add signature (author) and address (title)
660690 let addr = case stateTitle st of
661691 [] -> mempty
662− x -> para $ fromList x
692+ x -> para $ trimInlines $ fromList x
693+ updateState $ \s -> s{ stateAuthors = [], stateTitle = [] }
694+ return $ addr <> bs -- sig added by \closing
695+
696+closing :: LP Blocks
697+closing = do
698+ contents <- tok
699+ st <- getState
663700 let sigs = case stateAuthors st of
664701 [] -> mempty
665− xs -> para $ fromList $ intercalate [LineBreak] xs
666− updateState $ \s -> s{ stateAuthors = [], stateTitle = [] }
667− return $ addr <> bs <> sigs
702+ xs -> para $ trimInlines $ fromList
703+ $ intercalate [LineBreak] xs
704+ return $ para (trimInlines contents) <> sigs
668705
669706item :: LP Blocks
670707item = blocks *> controlSeq "item" *> optional opt *> blocks