From 1b19e79650d6bcc6ec45733ee349c3af5c36ab36 Mon Sep 17 00:00:00 2001
From: John MacFarlane <jgm@berkeley.edu>
Date: Sat, 20 Oct 2018 10:00:50 -0700
Subject: [PATCH] Man reader: parse TP as definition lists.

Closes #4981.
---
 src/Text/Pandoc/Readers/Man.hs | 61 ++++++++++++++++++++--------------
 test/man-reader.man            | 11 ++++++
 test/man-reader.native         |  9 ++++-
 3 files changed, 55 insertions(+), 26 deletions(-)

diff --git a/src/Text/Pandoc/Readers/Man.hs b/src/Text/Pandoc/Readers/Man.hs
index 7e5288aa1..01c44066a 100644
--- a/src/Text/Pandoc/Readers/Man.hs
+++ b/src/Text/Pandoc/Readers/Man.hs
@@ -128,6 +128,7 @@ parseMan = do
 
 parseBlock :: PandocMonad m => ManParser m Blocks
 parseBlock = choice [ parseList
+                    , parseDefinitionList
                     , parseTitle
                     , parsePara
                     , parseSkippedContent
@@ -351,7 +352,9 @@ msatisfy :: (Show t, Stream s m t) => (t -> Bool) -> ParserT s st m t
 msatisfy predic = tokenPrim show nextPos testTok
   where
     testTok t     = if predic t then Just t else Nothing
-    nextPos pos _x _xs  = updatePosString (setSourceColumn (setSourceLine pos $ sourceLine pos + 1) 1) ("")
+    nextPos pos _x _xs  = updatePosString
+                             (setSourceColumn
+                               (setSourceLine pos $ sourceLine pos + 1) 1) ("")
 
 mstr :: PandocMonad m => ManParser m ManToken
 mstr = msatisfy isMStr where
@@ -428,25 +431,23 @@ parseInlines = do
   let withspaces = intersperse B.space inls
   return $ mconcat withspaces
 
-  where
+strInl :: PandocMonad m => ManParser m Inlines
+strInl = do
+  (MStr rstr) <- mstr
+  return $ strToInlines rstr
 
-  strInl :: PandocMonad m => ManParser m Inlines
-  strInl = do
-    (MStr rstr) <- mstr
-    return $ strToInlines rstr
+lineInl :: PandocMonad m => ManParser m Inlines
+lineInl = do
+  (MLine fragments) <- mline
+  return $ mconcat $ strToInlines <$> fragments
 
-  lineInl :: PandocMonad m => ManParser m Inlines
-  lineInl = do
-    (MLine fragments) <- mline
-    return $ mconcat $ strToInlines <$> fragments
-
-  linkInl :: PandocMonad m => ManParser m Inlines
-  linkInl = do
-    (MMaybeLink txt) <- mmaybeLink
-    let inls = case runParser linkParser () "" txt of
-                  Right lnk -> lnk
-                  Left _ -> strong $ text txt
-    return inls
+linkInl :: PandocMonad m => ManParser m Inlines
+linkInl = do
+  (MMaybeLink txt) <- mmaybeLink
+  let inls = case runParser linkParser () "" txt of
+                Right lnk -> lnk
+                Left _ -> strong $ text txt
+  return inls
 
     where
 
@@ -463,8 +464,8 @@ parseInlines = do
           lnkInls = link (manurl mpage [mansect]) mpage (strong $ str mpage)
       return $ lnkInls <> strong (str (" ("++[mansect] ++ ")") <> text other)
 
-  comment :: PandocMonad m => ManParser m Inlines
-  comment = mcomment >> return mempty
+comment :: PandocMonad m => ManParser m Inlines
+comment = mcomment >> return mempty
 
 bareIP :: PandocMonad m => ManParser m ManToken
 bareIP = msatisfy isBareIP where
@@ -497,12 +498,10 @@ parseHeader = do
   MMacro name args <- mmacro "SH" <|> mmacro "SS"
   contents <- if null args
                  then do
-                   MLine ils <- mline
-                   return $ mconcat $ map strToInlines ils
+                   strInl <|> lineInl
                  else do
-                   return $ mconcat
-                          $ intersperse B.space
-                          $ map strToInlines args
+                   return $
+                     mconcat $ intersperse B.space $ map strToInlines args
   let lvl = if name == "SH" then 1 else 2
   return $ header lvl contents
 
@@ -549,6 +548,18 @@ continuation = do
   mmacro "RE"
   return bs
 
+definitionListItem :: PandocMonad m
+                   => ManParser m (Inlines, [Blocks])
+definitionListItem = try $ do
+  (MMacro _ _) <- mmacro "TP"  -- args specify indent level, can ignore
+  term <- strInl <|> lineInl
+  inls <- parseInlines
+  continuations <- mconcat <$> many continuation
+  return $ (term, [para inls <> continuations])
+
+parseDefinitionList :: PandocMonad m => ManParser m Blocks
+parseDefinitionList = definitionList <$> many1 definitionListItem
+
 -- In case of weird man file it will be parsed succesfully
 parseSkipMacro :: PandocMonad m => ManParser m Blocks
 parseSkipMacro = do
diff --git a/test/man-reader.man b/test/man-reader.man
index e514bc8ca..7a34d5dcb 100644
--- a/test/man-reader.man
+++ b/test/man-reader.man
@@ -144,7 +144,18 @@ Lower alpha with paren
 .RE
 .RE
 .RE
+.SS Ordered
+Definition lists
+.TP
+.B term1
+definition 1
+.RS
 .PP
+continued
+.RE
+.TP
+.B term2
+definition 2
    *   *   *   *   *
 .SH Special Characters
 AT&T has an ampersand in their name.
diff --git a/test/man-reader.native b/test/man-reader.native
index 811c7c5c8..996ab7cac 100644
--- a/test/man-reader.native
+++ b/test/man-reader.native
@@ -70,7 +70,14 @@ Pandoc (Meta {unMeta = fromList [("date",MetaString "Oct 17, 2018"),("section",M
      [[Para [Str "Decimal",Space,Str "start",Space,Str "with",Space,Str "6"]
       ,OrderedList (3,LowerAlpha,OneParen)
        [[Para [Str "Lower",Space,Str "alpha",Space,Str "with",Space,Str "paren"]]]]]]]]]
-,Para [Str "*",Space,Str "*",Space,Str "*",Space,Str "*",Space,Str "*"]
+,Header 2 ("",[],[]) [Str "Ordered"]
+,Para [Str "Definition",Space,Str "lists"]
+,DefinitionList
+ [([Strong [Str "term1"]],
+   [[Para [Str "definition",Space,Str "1"]
+    ,Para [Str "continued"]]])
+ ,([Strong [Str "term2"]],
+   [[Para [Str "definition",Space,Str "2",Space,Str "*",Space,Str "*",Space,Str "*",Space,Str "*",Space,Str "*"]]])]
 ,Header 1 ("",[],[]) [Str "Special",Space,Str "Characters"]
 ,Para [Str "AT&T",Space,Str "has",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "their",Space,Str "name."]
 ,Para [Str "4",Space,Str "<",Space,Str "5."]