@@ -35,7 +35,7 @@ import Text.Pandoc.Shared
3535import Text.Pandoc.Parsing
3636import Text.ParserCombinators.Parsec
3737import Control.Monad ( when, unless )
38−import Data.List ( findIndex, intercalate, transpose, sort )
38+import Data.List ( findIndex, intercalate, transpose, sort, deleteFirstsBy )
3939import qualified Data.Map as M
4040import Text.Printf ( printf )
4141
@@ -91,11 +91,15 @@ titleTransform blocks = (blocks, [])
9191parseRST :: GenParser Char ParserState Pandoc
9292parseRST = do
9393 startPos <- getPosition
94− -- go through once just to get list of reference keys
94+ -- go through once just to get list of reference keys and notes
9595 -- docMinusKeys is the raw document with blanks where the keys were...
96− docMinusKeys <- manyTill (referenceKey <|> lineClump) eof >>= return . concat
96+ docMinusKeys <- manyTill (referenceKey <|> noteBlock <|> lineClump) eof >>=
97+ return . concat
9798 setInput docMinusKeys
9899 setPosition startPos
100+ st' <- getState
101+ let reversedNotes = stateNotes st'
102+ updateState $ \s -> s { stateNotes = reverse reversedNotes }
99103 -- now parse it for real...
100104 blocks <- parseBlocks
101105 let blocks' = filter (/= Null) blocks
@@ -508,6 +512,32 @@ unknownDirective = try $ do
508512 many $ blanklines <|> (oneOf " \t" >> manyTill anyChar newline)
509513 return Null
510514
515+---
516+--- note block
517+---
518+
519+noteBlock :: GenParser Char ParserState [Char]
520+noteBlock = try $ do
521+ startPos <- getPosition
522+ string ".."
523+ spaceChar >> skipMany spaceChar
524+ ref <- noteMarker
525+ spaceChar >> skipMany spaceChar
526+ first <- anyLine
527+ blanks <- option "" blanklines
528+ rest <- option "" indentedBlock
529+ endPos <- getPosition
530+ let raw = first ++ "\n" ++ blanks ++ rest ++ "\n"
531+ let newnote = (ref, raw)
532+ st <- getState
533+ let oldnotes = stateNotes st
534+ updateState $ \s -> s { stateNotes = newnote : oldnotes }
535+ -- return blanks so line count isn't affected
536+ return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
537+
538+noteMarker :: GenParser Char ParserState [Char]
539+noteMarker = char '[' >> (many1 digit <|> count 1 (oneOf "#*")) >>~ char ']'
540+
511541--
512542-- reference key
513543--
@@ -692,6 +722,7 @@ inline = choice [ smartPunctuation inline
692722 , superscript
693723 , subscript
694724 , escapedChar
725+ , note
695726 , symbol ] <?> "inline"
696727
697728hyphens :: GenParser Char ParserState Inline
@@ -820,3 +851,20 @@ image = try $ do
820851 Nothing -> fail "no corresponding key"
821852 Just target -> return target
822853 return $ Image (normalizeSpaces ref) (src, tit)
854+
855+note :: GenParser Char ParserState Inline
856+note = try $ do
857+ ref <- noteMarker
858+ char '_'
859+ state <- getState
860+ let notes = stateNotes state
861+ case lookup ref notes of
862+ Nothing -> fail "note not found"
863+ Just raw -> do
864+ contents <- parseFromString parseBlocks raw
865+ when (ref == "*" || ref == "#") $ do -- auto-numbered
866+ -- delete the note so the next auto-numbered note
867+ -- doesn't get the same contents:
868+ let newnotes = deleteFirstsBy (==) notes [(ref,raw)]
869+ updateState $ \st -> st{ stateNotes = newnotes }
870+ return $ Note contents