git.iko.soy/typeable/pandoc
on master help sign in
Merge pull request #1163 from merijn/master
56320f4John MacFarlane
src/Text/Pandoc/Parsing.hs+6
@@ -853,6 +853,11 @@ data ParserState = ParserState
853 stateHasChapters :: Bool, -- ^ True if \chapter encountered
853 stateHasChapters :: Bool, -- ^ True if \chapter encountered
854 stateMacros :: [Macro], -- ^ List of macros defined so far
854 stateMacros :: [Macro], -- ^ List of macros defined so far
855 stateRstDefaultRole :: String, -- ^ Current rST default interpreted text role
855 stateRstDefaultRole :: String, -- ^ Current rST default interpreted text role
856+ stateRstCustomRoles :: M.Map String (String, Maybe String, Attr -> (String, Attr)), -- ^ Current rST custom text roles
857+ -- Triple represents: 1) Base role, 2) Optional format (only for :raw:
858+ -- roles), 3) Source language annotation for code (could be used to
859+ -- annotate role classes too).
860+
856 stateWarnings :: [String] -- ^ Warnings generated by the parser
861 stateWarnings :: [String] -- ^ Warnings generated by the parser
857 }
862 }
858
863
@@ -915,6 +920,7 @@ defaultParserState =
915 stateHasChapters = False,
920 stateHasChapters = False,
916 stateMacros = [],
921 stateMacros = [],
917 stateRstDefaultRole = "title-reference",
922 stateRstDefaultRole = "title-reference",
923+ stateRstCustomRoles = M.empty,
918 stateWarnings = []}
924 stateWarnings = []}
919
925
920getOption :: (ReaderOptions -> a) -> Parser s ParserState a
926getOption :: (ReaderOptions -> a) -> Parser s ParserState a
src/Text/Pandoc/Readers/RST.hs+81−10
@@ -36,12 +36,13 @@ import Text.Pandoc.Builder (setMeta, fromList)
36import Text.Pandoc.Shared
36import Text.Pandoc.Shared
37import Text.Pandoc.Parsing
37import Text.Pandoc.Parsing
38import Text.Pandoc.Options
38import Text.Pandoc.Options
39−import Control.Monad ( when, liftM, guard, mzero )
39+import Control.Monad ( when, liftM, guard, mzero, mplus )
40import Data.List ( findIndex, intersperse, intercalate,
40import Data.List ( findIndex, intersperse, intercalate,
41 transpose, sort, deleteFirstsBy, isSuffixOf )
41 transpose, sort, deleteFirstsBy, isSuffixOf )
42+import Data.Maybe (fromMaybe)
42import qualified Data.Map as M
43import qualified Data.Map as M
43import Text.Printf ( printf )
44import Text.Printf ( printf )
44−import Control.Applicative ((<$>), (<$), (<*), (*>))
45+import Control.Applicative ((<$>), (<$), (<*), (*>), (<*>))
45import Text.Pandoc.Builder (Inlines, Blocks, trimInlines, (<>))
46import Text.Pandoc.Builder (Inlines, Blocks, trimInlines, (<>))
46import qualified Text.Pandoc.Builder as B
47import qualified Text.Pandoc.Builder as B
47import Data.Monoid (mconcat, mempty)
48import Data.Monoid (mconcat, mempty)
@@ -530,7 +531,7 @@ directive' = do
530 let body' = body ++ "\n\n"
531 let body' = body ++ "\n\n"
531 case label of
532 case label of
532 "raw" -> return $ B.rawBlock (trim top) (stripTrailingNewlines body)
533 "raw" -> return $ B.rawBlock (trim top) (stripTrailingNewlines body)
533− "role" -> return mempty
534+ "role" -> addNewRole top $ map (\(k,v) -> (k, trim v)) fields
534 "container" -> parseFromString parseBlocks body'
535 "container" -> parseFromString parseBlocks body'
535 "replace" -> B.para <$> -- consumed by substKey
536 "replace" -> B.para <$> -- consumed by substKey
536 parseFromString (trimInlines . mconcat <$> many inline)
537 parseFromString (trimInlines . mconcat <$> many inline)
@@ -591,7 +592,38 @@ directive' = do
591 Nothing -> B.image src "" alt
592 Nothing -> B.image src "" alt
592 _ -> return mempty
593 _ -> return mempty
593
594
595+-- TODO:
596+-- - Silently ignores illegal fields
597+-- - Silently drops classes
598+-- - Only supports :format: fields with a single format for :raw: roles,
599+-- change Text.Pandoc.Definition.Format to fix
600+addNewRole :: String -> [(String, String)] -> RSTParser Blocks
601+addNewRole roleString fields = do
602+ (role, parentRole) <- parseFromString inheritedRole roleString
603+ customRoles <- stateRstCustomRoles <$> getState
604+ baseRole <- case M.lookup parentRole customRoles of
605+ Just (base, _, _) -> return base
606+ Nothing -> return parentRole
607+
608+ let fmt = if baseRole == "raw" then lookup "format" fields else Nothing
609+ annotate = maybe id addLanguage $
610+ if baseRole == "code"
611+ then lookup "language" fields
612+ else Nothing
613+
614+ updateState $ \s -> s {
615+ stateRstCustomRoles =
616+ M.insert role (baseRole, fmt, (,) parentRole . annotate) customRoles
617+ }
618+
619+ return $ B.singleton Null
620+ where
621+ addLanguage lang (ident, classes, keyValues) =
622+ (ident, "sourceCode" : lang : classes, keyValues)
623+ inheritedRole =
624+ (,) <$> roleNameEndingIn (char '(') <*> roleNameEndingIn (char ')')
625+
594−-- Can contain haracter codes as decimal numbers or
626+-- Can contain character codes as decimal numbers or
595-- hexadecimal numbers, prefixed by 0x, x, \x, U+, u, or \u
627-- hexadecimal numbers, prefixed by 0x, x, \x, U+, u, or \u
596-- or as XML-style hexadecimal character entities, e.g. &#x1a2b;
628-- or as XML-style hexadecimal character entities, e.g. &#x1a2b;
597-- or text, which is used as-is. Comments start with ..
629-- or text, which is used as-is. Comments start with ..
@@ -930,17 +962,56 @@ strong = B.strong . trimInlines . mconcat <$>
930-- Note, this doesn't precisely implement the complex rule in
962-- Note, this doesn't precisely implement the complex rule in
931-- http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules
963-- http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules
932-- but it should be good enough for most purposes
964-- but it should be good enough for most purposes
965+--
966+-- TODO:
967+-- - Classes are silently discarded in addNewRole
968+-- - Lacks sensible implementation for title-reference (which is the default)
969+-- - Allows direct use of the :raw: role, rST only allows inherited use.
933interpretedRole :: RSTParser Inlines
970interpretedRole :: RSTParser Inlines
934interpretedRole = try $ do
971interpretedRole = try $ do
935 (role, contents) <- roleBefore <|> roleAfter
972 (role, contents) <- roleBefore <|> roleAfter
973+ renderRole contents Nothing role nullAttr
974+
975+renderRole :: String -> Maybe String -> String -> Attr -> RSTParser Inlines
936− case role of
976+renderRole contents fmt role attr = case role of
937− "sup" -> return $ B.superscript $ B.str contents
977+ "sup" -> return $ B.superscript $ B.str contents
978+ "superscript" -> return $ B.superscript $ B.str contents
938− "sub" -> return $ B.subscript $ B.str contents
979+ "sub" -> return $ B.subscript $ B.str contents
980+ "subscript" -> return $ B.subscript $ B.str contents
981+ "emphasis" -> return $ B.emph $ B.str contents
982+ "strong" -> return $ B.strong $ B.str contents
983+ "rfc-reference" -> return $ rfcLink contents
984+ "RFC" -> return $ rfcLink contents
985+ "pep-reference" -> return $ pepLink contents
986+ "PEP" -> return $ pepLink contents
987+ "literal" -> return $ B.str contents
939− "math" -> return $ B.math contents
988+ "math" -> return $ B.math contents
989+ "title-reference" -> titleRef contents
990+ "title" -> titleRef contents
991+ "t" -> titleRef contents
992+ "code" -> return $ B.codeWith attr contents
993+ "raw" -> return $ B.rawInline (fromMaybe "" fmt) contents
994+ custom -> do
995+ customRole <- stateRstCustomRoles <$> getState
996+ case M.lookup custom customRole of
997+ Just (_, newFmt, inherit) -> let
998+ fmtStr = fmt `mplus` newFmt
999+ (newRole, newAttr) = inherit attr
1000+ in renderRole contents fmtStr newRole newAttr
940− _ -> return $ B.str contents --unknown
1001+ Nothing -> return $ B.str contents -- Undefined role
1002+ where
1003+ titleRef ref = return $ B.str ref -- FIXME: Not a sensible behaviour
1004+ rfcLink rfcNo = B.link rfcUrl ("RFC " ++ rfcNo) $ B.str ("RFC " ++ rfcNo)
1005+ where rfcUrl = "http://www.faqs.org/rfcs/rfc" ++ rfcNo ++ ".html"
1006+ pepLink pepNo = B.link pepUrl ("PEP " ++ pepNo) $ B.str ("PEP " ++ pepNo)
1007+ where padNo = replicate (4 - length pepNo) '0' ++ pepNo
1008+ pepUrl = "http://http://www.python.org/dev/peps/pep-" ++ padNo ++ "/"
1009+
1010+roleNameEndingIn :: RSTParser Char -> RSTParser String
1011+roleNameEndingIn end = many1Till (letter <|> char '-') end
941
1012
942roleMarker :: RSTParser String
1013roleMarker :: RSTParser String
943−roleMarker = char ':' *> many1Till (letter <|> char '-') (char ':')
1014+roleMarker = char ':' *> roleNameEndingIn (char ':')
944
1015
945roleBefore :: RSTParser (String,String)
1016roleBefore :: RSTParser (String,String)
946roleBefore = try $ do
1017roleBefore = try $ do
tests/rst-reader.native+10
@@ -319,5 +319,15 @@ Pandoc (Meta {unMeta = fromList [("authors",MetaList [MetaInlines [Str "John",Sp
319,Para [Str "Some",Space,Superscript [Str "of"],Space,Str "these",Space,Superscript [Str "words"],Space,Str "are",Space,Str "in",Space,Superscript [Str "superscript"],Str "."]
319,Para [Str "Some",Space,Superscript [Str "of"],Space,Str "these",Space,Superscript [Str "words"],Space,Str "are",Space,Str "in",Space,Superscript [Str "superscript"],Str "."]
320,Para [Str "Reset",Space,Str "default-role",Space,Str "to",Space,Str "the",Space,Str "default",Space,Str "default."]
320,Para [Str "Reset",Space,Str "default-role",Space,Str "to",Space,Str "the",Space,Str "default",Space,Str "default."]
321,Para [Str "And",Space,Str "now",Space,Str "some-invalid-string-3231231",Space,Str "is",Space,Str "nonsense."]
321,Para [Str "And",Space,Str "now",Space,Str "some-invalid-string-3231231",Space,Str "is",Space,Str "nonsense."]
322+,Null
323+,Para [Str "And",Space,Str "now",Space,Str "with",Space,RawInline (Format "html") "<b>inline</b> <span id=\"test\">HTML</span>",Str "."]
324+,Null
325+,Para [Str "And",Space,Str "some",Space,Str "inline",Space,Str "haskell",Space,Code ("",["sourceCode","haskell"],[]) "fmap id [1,2..10]",Str "."]
326+,Null
327+,Null
328+,Para [Str "Indirect",Space,Str "python",Space,Str "role",Space,Code ("",["sourceCode","python"],[]) "[x*x for x in [1,2,3,4,5]]",Str "."]
329+,Null
330+,Null
331+,Para [Str "Different",Space,Str "indirect",Space,Str "C",Space,Code ("",["sourceCode","c"],[]) "int x = 15;",Str "."]
322,Header 2 ("literal-symbols",[],[]) [Str "Literal",Space,Str "symbols"]
332,Header 2 ("literal-symbols",[],[]) [Str "Literal",Space,Str "symbols"]
323,Para [Str "2*2",Space,Str "=",Space,Str "4*1"]]
333,Para [Str "2*2",Space,Str "=",Space,Str "4*1"]]
tests/rst-reader.rst+24
@@ -599,6 +599,30 @@ Reset default-role to the default default.
599
599
600And now `some-invalid-string-3231231` is nonsense.
600And now `some-invalid-string-3231231` is nonsense.
601
601
602+.. role:: html(raw)
603+ :format: html
604+
605+And now with :html:`<b>inline</b> <span id="test">HTML</span>`.
606+
607+.. role:: haskell(code)
608+ :language: haskell
609+
610+And some inline haskell :haskell:`fmap id [1,2..10]`.
611+
612+.. role:: indirect(code)
613+
614+.. role:: python(indirect)
615+ :language: python
616+
617+Indirect python role :python:`[x*x for x in [1,2,3,4,5]]`.
618+
619+.. role:: different-indirect(code)
620+ :language: c
621+
622+.. role:: c(different-indirect)
623+
624+Different indirect C :c:`int x = 15;`.
625+
602Literal symbols
626Literal symbols
603---------------
627---------------
604
628