links, paragraphs, codeblocks
This commit is contained in:
parent
c1617565fc
commit
83902ffdb2
1 changed files with 66 additions and 33 deletions
|
@ -35,7 +35,7 @@ module Text.Pandoc.Readers.Man where
|
||||||
import Control.Monad.Except (throwError)
|
import Control.Monad.Except (throwError)
|
||||||
import Data.Default (Default)
|
import Data.Default (Default)
|
||||||
import Data.Map (insert)
|
import Data.Map (insert)
|
||||||
import Data.Maybe (isJust)
|
import Data.Maybe (isJust, maybeToList)
|
||||||
import Data.List (intersperse, intercalate)
|
import Data.List (intersperse, intercalate)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
|
|
||||||
|
@ -109,18 +109,26 @@ parseMacro = do
|
||||||
macroName <- many1 (letter <|> oneOf ['\\', '"'])
|
macroName <- many1 (letter <|> oneOf ['\\', '"'])
|
||||||
args <- parseArgs
|
args <- parseArgs
|
||||||
let joinedArgs = concat $ intersperse " " args
|
let joinedArgs = concat $ intersperse " " args
|
||||||
|
let toBold = return $ Plain [Strong [Str joinedArgs]]
|
||||||
|
let toBoldItalic = return $ Plain [Strong [Emph [Str joinedArgs]]]
|
||||||
|
let toItalic = return $ Plain [Emph [Str joinedArgs]]
|
||||||
case macroName of
|
case macroName of
|
||||||
"\\\"" -> return Null -- comment
|
"\\\"" -> return Null -- comment
|
||||||
"TH" -> macroTitle (if null args then "" else head args)
|
"TH" -> macroTitle (if null args then "" else head args) -- man-title
|
||||||
|
"TP" -> return Null -- tab-indented paragraph
|
||||||
|
"PP" -> return Null -- end of tab-indented paragraphs
|
||||||
"nf" -> macroCodeBlock True >> return Null
|
"nf" -> macroCodeBlock True >> return Null
|
||||||
"fi" -> macroCodeBlock False >> return Null
|
"fi" -> macroCodeBlock False >> return Null
|
||||||
"B" -> return $ Plain [Strong [Str joinedArgs]]
|
"B" -> toBold
|
||||||
"BR" -> return $ Plain [Strong [Str joinedArgs]]
|
"BR" -> return $ linkToMan joinedArgs
|
||||||
"BI" -> return $ Plain [Strong [Emph [Str joinedArgs]]]
|
"BI" -> toBoldItalic
|
||||||
"I" -> return $ Plain [Emph [Str joinedArgs]]
|
"IB" -> toBoldItalic
|
||||||
|
"I" -> toItalic
|
||||||
|
"IR" -> toItalic
|
||||||
|
"RI" -> toItalic
|
||||||
"SH" -> return $ Header 2 nullAttr [Str joinedArgs]
|
"SH" -> return $ Header 2 nullAttr [Str joinedArgs]
|
||||||
"sp" -> return $ Plain [LineBreak]
|
"sp" -> return $ Plain [LineBreak]
|
||||||
_ -> unkownMacro macroName args
|
_ -> unkownMacro macroName
|
||||||
|
|
||||||
where
|
where
|
||||||
|
|
||||||
|
@ -131,21 +139,37 @@ parseMacro = do
|
||||||
then return Null
|
then return Null
|
||||||
else return $ Header 1 nullAttr [Str mantitle]
|
else return $ Header 1 nullAttr [Str mantitle]
|
||||||
where
|
where
|
||||||
changeTitle title mst @ ManState{ pState = pst} =
|
changeTitle title mst@ManState{ pState = pst} =
|
||||||
let meta = stateMeta pst
|
let meta = stateMeta pst
|
||||||
metaUp = Meta $ insert "title" (MetaString title) (unMeta meta)
|
metaUp = Meta $ insert "title" (MetaString title) (unMeta meta)
|
||||||
in
|
in
|
||||||
mst { pState = pst {stateMeta = metaUp} }
|
mst { pState = pst {stateMeta = metaUp} }
|
||||||
|
|
||||||
|
|
||||||
macroCodeBlock :: PandocMonad m => Bool -> ManParser m ()
|
macroCodeBlock :: PandocMonad m => Bool -> ManParser m ()
|
||||||
macroCodeBlock insideCB = modifyRoffState (\rst -> rst{inCodeBlock = insideCB}) >> return ()
|
macroCodeBlock insideCB = modifyRoffState (\rst -> rst{inCodeBlock = insideCB}) >> return ()
|
||||||
|
|
||||||
unkownMacro :: PandocMonad m => String -> [String] -> ManParser m Block
|
linkToMan :: String -> Block
|
||||||
unkownMacro mname args = do
|
linkToMan txt = case runParser linkParser () "" txt of
|
||||||
|
Right lnk -> Plain [lnk]
|
||||||
|
Left _ -> Plain [Emph [Str txt]]
|
||||||
|
where
|
||||||
|
linkParser :: Parsec String () Inline
|
||||||
|
linkParser = do
|
||||||
|
mpage <- many1 alphaNum
|
||||||
|
space
|
||||||
|
char '('
|
||||||
|
mansect <- digit
|
||||||
|
char ')'
|
||||||
|
-- assuming man pages are generated from Linux-like repository
|
||||||
|
let manurl pagename section = "../"++section++"/"++pagename++"."++section
|
||||||
|
return $ Link nullAttr [Str txt] (manurl mpage [mansect], mpage)
|
||||||
|
|
||||||
|
|
||||||
|
unkownMacro :: PandocMonad m => String -> ManParser m Block
|
||||||
|
unkownMacro mname = do
|
||||||
pos <- getPosition
|
pos <- getPosition
|
||||||
logMessage $ SkippedContent ("Unknown macro: " ++ mname) pos
|
logMessage $ SkippedContent ("Unknown macro: " ++ mname) pos
|
||||||
return $ Plain $ Str <$> args
|
return Null
|
||||||
|
|
||||||
parseArgs :: PandocMonad m => ManParser m [String]
|
parseArgs :: PandocMonad m => ManParser m [String]
|
||||||
parseArgs = do
|
parseArgs = do
|
||||||
|
@ -173,61 +197,70 @@ parseMacro = do
|
||||||
quotedChar :: PandocMonad m => ManParser m Char
|
quotedChar :: PandocMonad m => ManParser m Char
|
||||||
quotedChar = noneOf "\"\n" <|> try (string "\"\"" >> return '"')
|
quotedChar = noneOf "\"\n" <|> try (string "\"\"" >> return '"')
|
||||||
|
|
||||||
roffInline :: RoffState -> String -> (Maybe Inline)
|
roffInline :: RoffState -> String -> [Inline]
|
||||||
roffInline rst str
|
roffInline rst str
|
||||||
| null str = Nothing
|
| null str = []
|
||||||
| inCodeBlock rst = Just $ Code nullAttr str
|
| inCodeBlock rst = [Code nullAttr str, LineBreak]
|
||||||
| otherwise = Just $ case fontKind rst of
|
| otherwise = case fontKind rst of
|
||||||
Regular -> Str str
|
Regular -> [Str str]
|
||||||
Italic -> Emph [Str str]
|
Italic -> [Emph [Str str]]
|
||||||
_ -> Strong [Str str]
|
Bold -> [Strong [Str str]]
|
||||||
|
ItalicBold -> [Emph [Strong [Str str]]]
|
||||||
|
|
||||||
parseLine :: PandocMonad m => ManParser m Block
|
parseLine :: PandocMonad m => ManParser m Block
|
||||||
parseLine = do
|
parseLine = do
|
||||||
parts <- parseLineParts
|
parts <- parseLineParts
|
||||||
newline
|
newline
|
||||||
return $ if null parts
|
return $ if null parts
|
||||||
then Plain [LineBreak]
|
then Null
|
||||||
else Plain parts
|
else Plain parts
|
||||||
where
|
where
|
||||||
parseLineParts :: PandocMonad m => ManParser m [Inline]
|
parseLineParts :: PandocMonad m => ManParser m [Inline]
|
||||||
parseLineParts = do
|
parseLineParts = do
|
||||||
lnpart <- many $ noneOf "\n\\"
|
lnpart <- many $ noneOf "\n\\"
|
||||||
ManState {rState = roffSt} <- getState
|
ManState {rState = roffSt} <- getState
|
||||||
let inl = roffInline roffSt lnpart
|
let inls = roffInline roffSt lnpart
|
||||||
others <- backSlash <|> return []
|
others <- backSlash <|> return []
|
||||||
return $ case inl of
|
return $ inls ++ others
|
||||||
Just x -> x:others
|
|
||||||
Nothing -> others
|
|
||||||
|
|
||||||
backSlash :: PandocMonad m => ManParser m [Inline]
|
backSlash :: PandocMonad m => ManParser m [Inline]
|
||||||
backSlash = do
|
backSlash = do
|
||||||
char '\\'
|
char '\\'
|
||||||
esc <- choice [ char 'f' >> fEscape
|
esc <- choice [ char 'f' >> fEscape
|
||||||
, char '-' >> return (Just '-')
|
, char '-' >> return (Just '-')
|
||||||
|
, char '%' >> return Nothing
|
||||||
, Just <$> noneOf "\n"
|
, Just <$> noneOf "\n"
|
||||||
]
|
]
|
||||||
ManState {rState = roffSt} <- getState
|
ManState {rState = roffSt} <- getState
|
||||||
case esc of
|
case esc of
|
||||||
Just c -> case roffInline roffSt [c] of
|
Just c -> let inls = roffInline roffSt [c]
|
||||||
Just inl -> do
|
in parseLineParts >>= (\oth -> return $ inls ++ oth)
|
||||||
oth <- parseLineParts
|
|
||||||
return $ inl : oth
|
|
||||||
Nothing -> parseLineParts
|
|
||||||
Nothing -> parseLineParts
|
Nothing -> parseLineParts
|
||||||
where
|
where
|
||||||
|
|
||||||
fEscape :: PandocMonad m => ManParser m (Maybe Char)
|
fEscape :: PandocMonad m => ManParser m (Maybe Char)
|
||||||
fEscape = choice [ char 'B' >> modifyRoffState (\rst -> rst {fontKind = Bold})
|
fEscape = choice [ char 'B' >> modifyRoffState (\rst -> rst {fontKind = Bold})
|
||||||
, char 'I' >> modifyRoffState (\rst -> rst {fontKind = Italic})
|
, char 'I' >> modifyRoffState (\rst -> rst {fontKind = Italic})
|
||||||
, char 'P' >> modifyRoffState (\rst -> rst {fontKind = Regular})
|
, (char 'P' <|> anyChar) >> modifyRoffState (\rst -> rst {fontKind = Regular})
|
||||||
]
|
]
|
||||||
>> return Nothing
|
>> return Nothing
|
||||||
|
|
||||||
|
createParas :: [Block] -> [Block]
|
||||||
|
createParas bs = inner bs [] where
|
||||||
|
inner :: [Block] -> [Inline] -> [Block]
|
||||||
|
inner [] inls = maybeToList $ inlinesToPara inls
|
||||||
|
inner (Plain einls : oth) inls = inner oth (inls ++ einls)
|
||||||
|
inner (block : oth) inls = case inlinesToPara inls of
|
||||||
|
Just par -> par : block : inner oth []
|
||||||
|
Nothing -> block : inner oth []
|
||||||
|
|
||||||
|
inlinesToPara :: [Inline] -> Maybe Block
|
||||||
|
inlinesToPara [] = Nothing
|
||||||
|
inlinesToPara inls = Just $ Para (intersperse (Str " ") inls)
|
||||||
|
|
||||||
|
|
||||||
parseMan :: PandocMonad m => ManParser m Pandoc
|
parseMan :: PandocMonad m => ManParser m Pandoc
|
||||||
parseMan = do
|
parseMan = do
|
||||||
blocks <- many (parseMacro <|> parseLine)
|
blocks <- createParas <$> many (parseMacro <|> parseLine)
|
||||||
parserst <- pState <$> getState
|
parserst <- pState <$> getState
|
||||||
return $ Pandoc (stateMeta parserst) blocks
|
return $ Pandoc (stateMeta parserst) blocks
|
||||||
|
|
Loading…
Add table
Reference in a new issue