@@ -500,29 +500,66 @@ directive = try $ do
500 string ".."
500 string ".."
501 directive'
501 directive'
503+-- TODO: line-block, parsed-literal, table, csv-table, list-table
503directive' :: RSTParser Blocks
510directive' :: RSTParser Blocks
504directive' = do
511directive' = do
505 skipMany1 spaceChar
512 skipMany1 spaceChar
506 label <- directiveLabel
513 label <- directiveLabel
507 skipMany spaceChar
514 skipMany spaceChar
508 top <- many $ satisfy (/='\n')
515 top <- many $ satisfy (/='\n')
516+ <|> try (char '\n' <*
517+ notFollowedBy' (rawFieldListItem " ") <*
518+ count 3 (char ' ') <*
509− <|> try (char '\n' <* notFollowedBy blankline <*
519+ notFollowedBy blankline)
510− notFollowedBy' (lookAhead (many spaceChar)
511− >>= rawFieldListItem))
513− indent <- lookAhead $ many spaceChar
514− fields <- many $ rawFieldListItem indent
521+ fields <- many $ rawFieldListItem " "
516− body <- option "" indentedBlock
522+ body <- option "" $ try $ blanklines >> indentedBlock
517 let body' = body ++ "\n\n"
524 let body' = body ++ "\n\n"
518 case label of
525 case label of
519 "container" -> parseFromString parseBlocks body'
526 "container" -> parseFromString parseBlocks body'
527+ "replace" -> B.para <$> -- consumed by substKey
528+ parseFromString (trimInlines . mconcat <$> many inline)
530+ "unicode" -> B.para <$> -- consumed by substKey
531+ parseFromString (trimInlines . mconcat <$> many inline)
532+ (trim $ unicodeTransform top)
520 "compound" -> parseFromString parseBlocks body'
533 "compound" -> parseFromString parseBlocks body'
521 "pull-quote" -> B.blockQuote <$> parseFromString parseBlocks body'
534 "pull-quote" -> B.blockQuote <$> parseFromString parseBlocks body'
522 "epigraph" -> B.blockQuote <$> parseFromString parseBlocks body'
535 "epigraph" -> B.blockQuote <$> parseFromString parseBlocks body'
523 "highlights" -> B.blockQuote <$> parseFromString parseBlocks body'
536 "highlights" -> B.blockQuote <$> parseFromString parseBlocks body'
524 "rubric" -> B.para . B.strong <$> parseFromString
537 "rubric" -> B.para . B.strong <$> parseFromString
525 (trimInlines . mconcat <$> many inline) top
538 (trimInlines . mconcat <$> many inline) top
539+ _ | label `elem` ["attention","caution","danger","error","hint",
540+ "important","note","tip","warning"] ->
541+ do let tit = B.para $ B.strong $ B.str label
542+ bod <- parseFromString parseBlocks $ top ++ "\n\n" ++ body'
543+ return $ B.blockQuote $ tit <> bod
545+ do tit <- B.para . B.strong <$> parseFromString
546+ (trimInlines . mconcat <$> many inline) top
547+ bod <- parseFromString parseBlocks body'
548+ return $ B.blockQuote $ tit <> bod
550+ do let subtit = maybe "" trim $ lookup "subtitle" fields
551+ tit <- B.para . B.strong <$> parseFromString
552+ (trimInlines . mconcat <$> many inline)
553+ (trim top ++ if null subtit
555+ else (": " ++ subtit))
556+ bod <- parseFromString parseBlocks body'
557+ return $ B.blockQuote $ tit <> bod
559+ do tit <- B.para . B.strong <$> parseFromString
560+ (trimInlines . mconcat <$> many inline) top
561+ bod <- parseFromString parseBlocks body'
526 "default-role" -> mempty <$ updateState (\s ->
563 "default-role" -> mempty <$ updateState (\s ->
527 s { stateRstDefaultRole =
564 s { stateRstDefaultRole =
528 case trim top of
565 case trim top of
@@ -546,6 +583,38 @@ directive' = do
546 Nothing -> B.image src "" alt
583 Nothing -> B.image src "" alt
547 _ -> return mempty
584 _ -> return mempty
586+-- Can contain haracter codes as decimal numbers or
587+-- hexadecimal numbers, prefixed by 0x, x, \x, U+, u, or \u
588+-- or as XML-style hexadecimal character entities, e.g. ᨫ
589+-- or text, which is used as-is. Comments start with ..
590+unicodeTransform :: String -> String
593+ ('.':'.':xs) -> unicodeTransform $ dropWhile (/='\n') xs -- comment
594+ ('0':'x':xs) -> go "0x" xs
595+ ('x':xs) -> go "x" xs
596+ ('\\':'x':xs) -> go "\\x" xs
597+ ('U':'+':xs) -> go "U+" xs
598+ ('u':xs) -> go "u" xs
599+ ('\\':'u':xs) -> go "\\u" xs
600+ ('&':'#':'x':xs) -> maybe ("&#x" ++ unicodeTransform xs)
602+ (\(c,s) -> c : unicodeTransform (drop 1 s))
603+ $ extractUnicodeChar xs
604+ (x:xs) -> x : unicodeTransform xs
606+ where go pref zs = maybe (pref ++ unicodeTransform zs)
607+ (\(c,s) -> c : unicodeTransform s)
608+ $ extractUnicodeChar zs
610+extractUnicodeChar :: String -> Maybe (Char, String)
611+extractUnicodeChar s = maybe Nothing (\c -> Just (c,rest)) mbc
612+ where (ds,rest) = span isHexDigit s
613+ mbc = safeRead ('\'':'\\':'x':ds ++ "'")
615+isHexDigit :: Char -> Bool
616+isHexDigit c = c `elem` "0123456789ABCDEFabcdef"
549extractCaption :: RSTParser (Inlines, Blocks)
618extractCaption :: RSTParser (Inlines, Blocks)
550extractCaption = do
619extractCaption = do
551 capt <- trimInlines . mconcat <$> many inline
620 capt <- trimInlines . mconcat <$> many inline
@@ -662,7 +731,7 @@ substKey = try $ do
662 skipMany1 spaceChar
731 skipMany1 spaceChar
663 (alt,ref) <- withRaw $ trimInlines . mconcat
732 (alt,ref) <- withRaw $ trimInlines . mconcat
664 <$> enclosed (char '|') (char '|') inline
733 <$> enclosed (char '|') (char '|') inline
665− res <- B.toList <$> (directive' <|> para)
734+ res <- B.toList <$> directive'
666 il <- case res of
735 il <- case res of
667 -- use alt unless :alt: attribute on image:
736 -- use alt unless :alt: attribute on image:
668 [Para [Image [Str "image"] (src,tit)]] ->
737 [Para [Image [Str "image"] (src,tit)]] ->