@@ -35,7 +35,7 @@ module Text.Pandoc.Readers.Man where
3535import Control.Monad.Except (throwError)
3636import Data.Default (Default)
3737import Data.Map (insert)
38−import Data.Maybe (isJust)
38+import Data.Maybe (isJust, maybeToList)
3939import Data.List (intersperse, intercalate)
4040import qualified Data.Text as T
4141
@@ -109,18 +109,26 @@ parseMacro = do
109109 macroName <- many1 (letter <|> oneOf ['\\', '"'])
110110 args <- parseArgs
111111 let joinedArgs = concat $ intersperse " " args
112+ let toBold = return $ Plain [Strong [Str joinedArgs]]
113+ let toBoldItalic = return $ Plain [Strong [Emph [Str joinedArgs]]]
114+ let toItalic = return $ Plain [Emph [Str joinedArgs]]
112115 case macroName of
113116 "\\\"" -> return Null -- comment
114− "TH" -> macroTitle (if null args then "" else head args)
117+ "TH" -> macroTitle (if null args then "" else head args) -- man-title
118+ "TP" -> return Null -- tab-indented paragraph
119+ "PP" -> return Null -- end of tab-indented paragraphs
115120 "nf" -> macroCodeBlock True >> return Null
116121 "fi" -> macroCodeBlock False >> return Null
117− "B" -> return $ Plain [Strong [Str joinedArgs]]
118− "BR" -> return $ Plain [Strong [Str joinedArgs]]
119− "BI" -> return $ Plain [Strong [Emph [Str joinedArgs]]]
120− "I" -> return $ Plain [Emph [Str joinedArgs]]
122+ "B" -> toBold
123+ "BR" -> return $ linkToMan joinedArgs
124+ "BI" -> toBoldItalic
125+ "IB" -> toBoldItalic
126+ "I" -> toItalic
127+ "IR" -> toItalic
128+ "RI" -> toItalic
121129 "SH" -> return $ Header 2 nullAttr [Str joinedArgs]
122130 "sp" -> return $ Plain [LineBreak]
123− _ -> unkownMacro macroName args
131+ _ -> unkownMacro macroName
124132
125133 where
126134
@@ -131,21 +139,37 @@ parseMacro = do
131139 then return Null
132140 else return $ Header 1 nullAttr [Str mantitle]
133141 where
134− changeTitle title mst @ ManState{ pState = pst} =
142+ changeTitle title mst@ManState{ pState = pst} =
135143 let meta = stateMeta pst
136144 metaUp = Meta $ insert "title" (MetaString title) (unMeta meta)
137145 in
138146 mst { pState = pst {stateMeta = metaUp} }
139147
140−
141148 macroCodeBlock :: PandocMonad m => Bool -> ManParser m ()
142149 macroCodeBlock insideCB = modifyRoffState (\rst -> rst{inCodeBlock = insideCB}) >> return ()
150+
151+ linkToMan :: String -> Block
152+ linkToMan txt = case runParser linkParser () "" txt of
153+ Right lnk -> Plain [lnk]
154+ Left _ -> Plain [Emph [Str txt]]
155+ where
156+ linkParser :: Parsec String () Inline
157+ linkParser = do
158+ mpage <- many1 alphaNum
159+ space
160+ char '('
161+ mansect <- digit
162+ char ')'
163+ -- assuming man pages are generated from Linux-like repository
164+ let manurl pagename section = "../"++section++"/"++pagename++"."++section
165+ return $ Link nullAttr [Str txt] (manurl mpage [mansect], mpage)
166+
143167
144− unkownMacro :: PandocMonad m => String -> [String] -> ManParser m Block
145− unkownMacro mname args = do
168+ unkownMacro :: PandocMonad m => String -> ManParser m Block
169+ unkownMacro mname = do
146170 pos <- getPosition
147171 logMessage $ SkippedContent ("Unknown macro: " ++ mname) pos
148− return $ Plain $ Str <$> args
172+ return Null
149173
150174 parseArgs :: PandocMonad m => ManParser m [String]
151175 parseArgs = do
@@ -173,61 +197,70 @@ parseMacro = do
173197 quotedChar :: PandocMonad m => ManParser m Char
174198 quotedChar = noneOf "\"\n" <|> try (string "\"\"" >> return '"')
175199
176−roffInline :: RoffState -> String -> (Maybe Inline)
200+roffInline :: RoffState -> String -> [Inline]
177201roffInline rst str
178− | null str = Nothing
179− | inCodeBlock rst = Just $ Code nullAttr str
180− | otherwise = Just $ case fontKind rst of
181− Regular -> Str str
182− Italic -> Emph [Str str]
183− _ -> Strong [Str str]
202+ | null str = []
203+ | inCodeBlock rst = [Code nullAttr str, LineBreak]
204+ | otherwise = case fontKind rst of
205+ Regular -> [Str str]
206+ Italic -> [Emph [Str str]]
207+ Bold -> [Strong [Str str]]
208+ ItalicBold -> [Emph [Strong [Str str]]]
184209
185210parseLine :: PandocMonad m => ManParser m Block
186211parseLine = do
187212 parts <- parseLineParts
188213 newline
189214 return $ if null parts
190− then Plain [LineBreak]
215+ then Null
191216 else Plain parts
192217 where
193218 parseLineParts :: PandocMonad m => ManParser m [Inline]
194219 parseLineParts = do
195220 lnpart <- many $ noneOf "\n\\"
196221 ManState {rState = roffSt} <- getState
197− let inl = roffInline roffSt lnpart
222+ let inls = roffInline roffSt lnpart
198223 others <- backSlash <|> return []
199− return $ case inl of
200− Just x -> x:others
201− Nothing -> others
224+ return $ inls ++ others
202225
203226 backSlash :: PandocMonad m => ManParser m [Inline]
204227 backSlash = do
205228 char '\\'
206229 esc <- choice [ char 'f' >> fEscape
207230 , char '-' >> return (Just '-')
231+ , char '%' >> return Nothing
208232 , Just <$> noneOf "\n"
209233 ]
210234 ManState {rState = roffSt} <- getState
211235 case esc of
212− Just c -> case roffInline roffSt [c] of
213− Just inl -> do
214− oth <- parseLineParts
215− return $ inl : oth
216− Nothing -> parseLineParts
236+ Just c -> let inls = roffInline roffSt [c]
237+ in parseLineParts >>= (\oth -> return $ inls ++ oth)
217238 Nothing -> parseLineParts
218239 where
219240
220241 fEscape :: PandocMonad m => ManParser m (Maybe Char)
221242 fEscape = choice [ char 'B' >> modifyRoffState (\rst -> rst {fontKind = Bold})
222243 , char 'I' >> modifyRoffState (\rst -> rst {fontKind = Italic})
223− , char 'P' >> modifyRoffState (\rst -> rst {fontKind = Regular})
244+ , (char 'P' <|> anyChar) >> modifyRoffState (\rst -> rst {fontKind = Regular})
224245 ]
225246 >> return Nothing
226−
227−
247+
248+createParas :: [Block] -> [Block]
249+createParas bs = inner bs [] where
250+ inner :: [Block] -> [Inline] -> [Block]
251+ inner [] inls = maybeToList $ inlinesToPara inls
252+ inner (Plain einls : oth) inls = inner oth (inls ++ einls)
253+ inner (block : oth) inls = case inlinesToPara inls of
254+ Just par -> par : block : inner oth []
255+ Nothing -> block : inner oth []
256+
257+ inlinesToPara :: [Inline] -> Maybe Block
258+ inlinesToPara [] = Nothing
259+ inlinesToPara inls = Just $ Para (intersperse (Str " ") inls)
260+
228261
229262parseMan :: PandocMonad m => ManParser m Pandoc
230263parseMan = do
231− blocks <- many (parseMacro <|> parseLine)
264+ blocks <- createParas <$> many (parseMacro <|> parseLine)
232265 parserst <- pState <$> getState
233266 return $ Pandoc (stateMeta parserst) blocks