git.iko.soy/typeable/pandoc
on master help sign in
Roff reader: introduce normal/copy mode distinction.
7a30eaeJohn MacFarlane
src/Text/Pandoc/Readers/Roff.hs+33−4
@@ -117,10 +117,15 @@ newtype RoffTokens = RoffTokens { unRoffTokens :: Seq.Seq RoffToken }
117singleTok :: RoffToken -> RoffTokens
117singleTok :: RoffToken -> RoffTokens
118singleTok t = RoffTokens (Seq.singleton t)
118singleTok t = RoffTokens (Seq.singleton t)
119
119
120+data RoffMode = NormalMode
121+ | CopyMode
122+ deriving Show
123+
120data RoffState = RoffState { customMacros :: M.Map String RoffTokens
124data RoffState = RoffState { customMacros :: M.Map String RoffTokens
121 , prevFont :: FontSpec
125 , prevFont :: FontSpec
122 , currentFont :: FontSpec
126 , currentFont :: FontSpec
123 , tableTabChar :: Char
127 , tableTabChar :: Char
128+ , roffMode :: RoffMode
124 } deriving Show
129 } deriving Show
125
130
126instance Default RoffState where
131instance Default RoffState where
@@ -135,6 +140,7 @@ instance Default RoffState where
135 , prevFont = defaultFontSpec
140 , prevFont = defaultFontSpec
136 , currentFont = defaultFontSpec
141 , currentFont = defaultFontSpec
137 , tableTabChar = '\t'
142 , tableTabChar = '\t'
143+ , roffMode = NormalMode
138 }
144 }
139
145
140type RoffLexer m = ParserT [Char] RoffState m
146type RoffLexer m = ParserT [Char] RoffState m
@@ -159,7 +165,7 @@ combiningAccentsMap =
159
165
160escape :: PandocMonad m => RoffLexer m [LinePart]
166escape :: PandocMonad m => RoffLexer m [LinePart]
161escape = do
167escape = do
162− char '\\'
168+ backslash
163 escapeGlyph <|> escapeNormal
169 escapeGlyph <|> escapeNormal
164
170
165escapeGlyph :: PandocMonad m => RoffLexer m [LinePart]
171escapeGlyph :: PandocMonad m => RoffLexer m [LinePart]
@@ -226,7 +232,12 @@ escapeNormal = do
226 '-' -> return [RoffStr "-"]
232 '-' -> return [RoffStr "-"]
227 '_' -> return [RoffStr "_"]
233 '_' -> return [RoffStr "_"]
228 ' ' -> return [RoffStr " "]
234 ' ' -> return [RoffStr " "]
235+ '\\' -> do
236+ mode <- roffMode <$> getState
237+ case mode of
238+ CopyMode -> char '\\'
239+ NormalMode -> return '\\'
229− '\\' -> return [RoffStr "\\"]
240+ return [RoffStr "\\"]
230 't' -> return [RoffStr "\t"]
241 't' -> return [RoffStr "\t"]
231 'e' -> return [RoffStr "\\"]
242 'e' -> return [RoffStr "\\"]
232 '`' -> return [RoffStr "`"]
243 '`' -> return [RoffStr "`"]
@@ -514,6 +525,7 @@ lexStringDef args = do -- string definition
514
525
515lexMacroDef :: PandocMonad m => [Arg] -> RoffLexer m RoffTokens
526lexMacroDef :: PandocMonad m => [Arg] -> RoffLexer m RoffTokens
516lexMacroDef args = do -- macro definition
527lexMacroDef args = do -- macro definition
528+ modifyState $ \st -> st{ roffMode = CopyMode }
517 (macroName, stopMacro) <-
529 (macroName, stopMacro) <-
518 case args of
530 case args of
519 (x : y : _) -> return (linePartsToString x, linePartsToString y)
531 (x : y : _) -> return (linePartsToString x, linePartsToString y)
@@ -528,7 +540,8 @@ lexMacroDef args = do -- macro definition
528 return ()
540 return ()
529 ts <- mconcat <$> manyTill manToken stop
541 ts <- mconcat <$> manyTill manToken stop
530 modifyState $ \st ->
542 modifyState $ \st ->
531− st{ customMacros = M.insert macroName ts (customMacros st) }
543+ st{ customMacros = M.insert macroName ts (customMacros st)
544+ , roffMode = NormalMode }
532 return mempty
545 return mempty
533
546
534lexArgs :: PandocMonad m => RoffLexer m [Arg]
547lexArgs :: PandocMonad m => RoffLexer m [Arg]
@@ -587,6 +600,10 @@ escString = try $ do
587
600
588lexLine :: PandocMonad m => RoffLexer m RoffTokens
601lexLine :: PandocMonad m => RoffLexer m RoffTokens
589lexLine = do
602lexLine = do
603+ mode <- roffMode <$> getState
604+ case mode of
605+ CopyMode -> optional $ try $ string "\\&"
606+ NormalMode -> return ()
590 lnparts <- mconcat <$> many1 linePart
607 lnparts <- mconcat <$> many1 linePart
591 eofline
608 eofline
592 go lnparts
609 go lnparts
@@ -600,10 +617,22 @@ linePart :: PandocMonad m => RoffLexer m [LinePart]
600linePart = macroArg <|> escape <|>
617linePart = macroArg <|> escape <|>
601 regularText <|> quoteChar <|> spaceTabChar
618 regularText <|> quoteChar <|> spaceTabChar
602
619
620+backslash :: PandocMonad m => RoffLexer m ()
621+backslash = do
622+ char '\\'
623+ mode <- roffMode <$> getState
624+ case mode of
625+ -- experimentally, it seems you don't always need to double
626+ -- the backslash in macro defs. It's essential with \\$1,
627+ -- but not with \\f[I]. So we make the second one optional.
628+ CopyMode -> optional $ char '\\'
629+ NormalMode -> return ()
630+
603macroArg :: PandocMonad m => RoffLexer m [LinePart]
631macroArg :: PandocMonad m => RoffLexer m [LinePart]
604macroArg = try $ do
632macroArg = try $ do
605 pos <- getPosition
633 pos <- getPosition
606− string "\\\\$"
634+ backslash
635+ char '$'
607 x <- escapeArg <|> count 1 digit
636 x <- escapeArg <|> count 1 digit
608 case safeRead x of
637 case safeRead x of
609 Just i -> return [MacroArg i]
638 Just i -> return [MacroArg i]