git.iko.soy/typeable/pandoc
on master help sign in
Groff tokenizer: introduce TableRow type, handle .T&.

Closes #5020.

commit52df18f476b7eb7935c2c01f566fa1adee4a8621 authorJohn MacFarlane <jgm@berkeley.edu> dateFri 26 Oct 2018, 21:22 (8 years ago) parent7f70aaa
2 files changed+41−23
src/Text/Pandoc/Readers/Groff.hs+29−12 src/Text/Pandoc/Readers/Man.hs+12−11
src/Text/Pandoc/Readers/Groff.hs+29−12
@@ -38,7 +38,8 @@ module Text.Pandoc.Readers.Groff
3838 , LinePart(..)
3939 , Arg
4040 , TableOption
41− , TableFormat(..)
41+ , CellFormat(..)
42+ , TableRow
4243 , GroffToken(..)
4344 , GroffTokens(..)
4445 , linePartsToString
@@ -47,6 +48,7 @@ module Text.Pandoc.Readers.Groff
4748where
4849
4950import Prelude
51+import Safe (lastDef)
5052import Control.Monad (void, mzero, guard, when)
5153import Control.Monad.Except (throwError)
5254import Text.Pandoc.Class
@@ -92,20 +94,21 @@ type Arg = [LinePart]
9294
9395type TableOption = (String, String)
9496
95−data TableFormat =
96− TableFormat
97+data CellFormat =
98+ CellFormat
9799 { columnType :: Char
98100 , pipePrefix :: Bool
99101 , pipeSuffix :: Bool
100102 , columnSuffixes :: [String]
101103 } deriving (Show, Eq, Ord)
102104
105+type TableRow = ([CellFormat], [GroffTokens])
103106
104107-- TODO parse tables (see man tbl)
105108data GroffToken = MLine [LinePart]
106109 | MEmptyLine
107110 | MMacro MacroKind [Arg] SourcePos
108− | MTable [TableOption] [[TableFormat]] [[GroffTokens]] SourcePos
111+ | MTable [TableOption] [TableRow] SourcePos
109112 deriving Show
110113
111114newtype GroffTokens = GroffTokens { unGroffTokens :: Seq.Seq GroffToken }
@@ -346,13 +349,27 @@ lexTable pos = do
346349 spaces
347350 skipMany lexComment
348351 spaces
352+ rows <- lexTableRows
353+ morerows <- many $ try $ do
354+ string ".T&"
355+ skipMany spacetab
356+ newline
357+ lexTableRows
358+ string ".TE"
359+ skipMany spacetab
360+ eofline
361+ return $ singleTok $ MTable opts (rows ++ concat morerows) pos
362+
363+lexTableRows :: PandocMonad m => GroffLexer m [TableRow]
364+lexTableRows = do
349365 aligns <- tableFormatSpec
350366 spaces
351367 skipMany lexComment
352368 spaces
353− rows <- manyTill tableRow (try (string ".TE" >> skipMany spacetab >> eofline))
354− return $ singleTok $ MTable opts aligns rows pos
355−
369+ rows <- many (notFollowedBy (try (string ".TE") <|> try (string ".T&")) >>
370+ tableRow)
371+ return $ zip aligns rows
372+
356373tableCell :: PandocMonad m => GroffLexer m GroffTokens
357374tableCell = (enclosedCell <|> simpleCell) >>= lexGroff . T.pack
358375 where
@@ -387,18 +404,18 @@ tableOption = do
387404 skipMany spacetab
388405 return (k,v)
389406
390−tableFormatSpec :: PandocMonad m => GroffLexer m [[TableFormat]]
407+tableFormatSpec :: PandocMonad m => GroffLexer m [[CellFormat]]
391408tableFormatSpec = do
392409 speclines <- tableFormatSpecLine `sepBy1` (newline <|> char ',')
393410 skipMany spacetab
394411 char '.'
395− return speclines
412+ return $ speclines ++ repeat (lastDef [] speclines) -- last line is default
396413
397−tableFormatSpecLine :: PandocMonad m => GroffLexer m [TableFormat]
414+tableFormatSpecLine :: PandocMonad m => GroffLexer m [CellFormat]
398415tableFormatSpecLine =
399416 many1 $ try $ skipMany spacetab >> tableColFormat
400417
401−tableColFormat :: PandocMonad m => GroffLexer m TableFormat
418+tableColFormat :: PandocMonad m => GroffLexer m CellFormat
402419tableColFormat = do
403420 pipePrefix' <- option False
404421 $ True <$ (try $ string "|" <* notFollowedBy spacetab)
@@ -416,7 +433,7 @@ tableColFormat = do
416433 else return ""
417434 return $ x : num
418435 pipeSuffix' <- option False $ True <$ string "|"
419− return $ TableFormat
436+ return $ CellFormat
420437 { columnType = c
421438 , pipePrefix = pipePrefix'
422439 , pipeSuffix = pipeSuffix'
src/Text/Pandoc/Readers/Man.hs+12−11
@@ -34,7 +34,6 @@ Conversion of man to 'Pandoc' document.
3434module Text.Pandoc.Readers.Man (readMan) where
3535
3636import Prelude
37−import Safe (lastMay)
3837import Data.Char (toLower)
3938import Data.Default (Default)
4039import Control.Monad (liftM, mzero, guard)
@@ -114,22 +113,22 @@ parseTable :: PandocMonad m => ManParser m Blocks
114113parseTable = do
115114 let isMTable (MTable{}) = True
116115 isMTable _ = False
117− MTable _opts aligns rows pos <- msatisfy isMTable
118− case lastMay aligns of
119− Just as -> try (do
116+ MTable _opts rows pos <- msatisfy isMTable
117+ case rows of
118+ ((as,_):_) -> try (do
120119 let as' = map (columnTypeToAlignment . columnType) as
121120 guard $ all isJust as'
122121 let alignments = catMaybes as'
123122 let (headerRow', bodyRows') =
124123 case rows of
125− (h:[x]:bs)
124+ (h:x:bs)
126125 | isHrule x -> (h, bs)
127− _ -> ([], rows)
128− headerRow <- mapM parseTableCell headerRow'
129− bodyRows <- mapM (mapM parseTableCell) bodyRows'
126+ _ -> (([],[]), rows)
127+ headerRow <- mapM parseTableCell $ snd headerRow'
128+ bodyRows <- mapM (mapM parseTableCell . snd) bodyRows'
130129 return $ B.table mempty (zip alignments (repeat 0.0))
131130 headerRow bodyRows) <|> fallback pos
132− Nothing -> fallback pos
131+ [] -> fallback pos
133132
134133 where
135134
@@ -146,11 +145,13 @@ parseTable = do
146145 Left e -> throwError e
147146 Right x -> return x
148147
149− isHrule :: GroffTokens -> Bool
150− isHrule (GroffTokens ss) =
148+ isHrule :: TableRow -> Bool
149+ isHrule ([cellfmt], _) = columnType cellfmt `elem` ['_','-','=']
150+ isHrule (_, [GroffTokens ss]) =
151151 case Foldable.toList ss of
152152 [MLine [RoffStr [c]]] -> c `elem` ['_','-','=']
153153 _ -> False
154+ isHrule _ = False
154155
155156 fallback pos = do
156157 report $ SkippedContent "TABLE" pos