git.iko.soy/typeable/pandoc
on master help sign in
Made KeyTable a map instead of an association list.

* This affects the RST and Markdown readers. * The type for stateKeys in ParserState has also changed. * Pandoc, Meta, Inline, and Block have been given Ord instances. * Reference keys now have a type of their own (Key), with its own Ord instance for case-insensitive comparison.

commitb5bda7569e700ff45582fe2d11993776451fd6fc authorJohn MacFarlane <jgm@berkeley.edu> dateSat 8 May 2010, 10:03 (16 years ago) parent91f52e2
6 files changed+67−50
src/Text/Pandoc/Definition.hs+9−9 src/Text/Pandoc/Readers/Markdown.hs+5−4 src/Text/Pandoc/Readers/RST.hs+23−19 src/Text/Pandoc/Shared.hs+16−6 src/Text/Pandoc/Writers/Markdown.hs+4−4 src/Text/Pandoc/Writers/RST.hs+10−8
src/Text/Pandoc/Definition.hs+9−9
@@ -33,19 +33,19 @@ module Text.Pandoc.Definition where
3333
3434import Data.Generics
3535
36−data Pandoc = Pandoc Meta [Block] deriving (Eq, Read, Show, Typeable, Data)
36+data Pandoc = Pandoc Meta [Block] deriving (Eq, Ord, Read, Show, Typeable, Data)
3737
3838-- | Bibliographic information for the document: title, authors, date.
3939data Meta = Meta { docTitle :: [Inline]
4040 , docAuthors :: [[Inline]]
4141 , docDate :: [Inline] }
42− deriving (Eq, Show, Read, Typeable, Data)
42+ deriving (Eq, Ord, Show, Read, Typeable, Data)
4343
4444-- | Alignment of a table column.
4545data Alignment = AlignLeft
4646 | AlignRight
4747 | AlignCenter
48− | AlignDefault deriving (Eq, Show, Read, Typeable, Data)
48+ | AlignDefault deriving (Eq, Ord, Show, Read, Typeable, Data)
4949
5050-- | List attributes.
5151type ListAttributes = (Int, ListNumberStyle, ListNumberDelim)
@@ -56,13 +56,13 @@ data ListNumberStyle = DefaultStyle
5656 | LowerRoman
5757 | UpperRoman
5858 | LowerAlpha
59− | UpperAlpha deriving (Eq, Show, Read, Typeable, Data)
59+ | UpperAlpha deriving (Eq, Ord, Show, Read, Typeable, Data)
6060
6161-- | Delimiter of list numbers.
6262data ListNumberDelim = DefaultDelim
6363 | Period
6464 | OneParen
65− | TwoParens deriving (Eq, Show, Read, Typeable, Data)
65+ | TwoParens deriving (Eq, Ord, Show, Read, Typeable, Data)
6666
6767-- | Attributes: identifier, classes, key-value pairs
6868type Attr = (String, [String], [(String, String)])
@@ -90,16 +90,16 @@ data Block
9090 -- column headers (each a list of blocks), and
9191 -- rows (each a list of lists of blocks)
9292 | Null -- ^ Nothing
93− deriving (Eq, Read, Show, Typeable, Data)
93+ deriving (Eq, Ord, Read, Show, Typeable, Data)
9494
9595-- | Type of quotation marks to use in Quoted inline.
96−data QuoteType = SingleQuote | DoubleQuote deriving (Show, Eq, Read, Typeable, Data)
96+data QuoteType = SingleQuote | DoubleQuote deriving (Show, Eq, Ord, Read, Typeable, Data)
9797
9898-- | Link target (URL, title).
9999type Target = (String, String)
100100
101101-- | Type of math element (display or inline).
102−data MathType = DisplayMath | InlineMath deriving (Show, Eq, Read, Typeable, Data)
102+data MathType = DisplayMath | InlineMath deriving (Show, Eq, Ord, Read, Typeable, Data)
103103
104104-- | Inline elements.
105105data Inline
@@ -126,7 +126,7 @@ data Inline
126126 | Image [Inline] Target -- ^ Image: alt text (list of inlines), target
127127 -- and target
128128 | Note [Block] -- ^ Footnote or endnote
129− deriving (Show, Eq, Read, Typeable, Data)
129+ deriving (Show, Eq, Ord, Read, Typeable, Data)
130130
131131-- | Applies a transformation on @a@s to matching elements in a @b@.
132132processWith :: (Data a, Data b) => (a -> a) -> b -> b
src/Text/Pandoc/Readers/Markdown.hs+5−4
@@ -32,6 +32,7 @@ module Text.Pandoc.Readers.Markdown (
3232 ) where
3333
3434import Data.List ( transpose, isSuffixOf, sortBy, findIndex, intercalate )
35+import qualified Data.Map as M
3536import Data.Ord ( comparing )
3637import Data.Char ( isAlphaNum )
3738import Data.Maybe
@@ -202,10 +203,10 @@ referenceKey = try $ do
202203 tit <- option "" referenceTitle
203204 blanklines
204205 endPos <- getPosition
205− let newkey = (lab, (escapeURI $ removeTrailingSpace src, tit))
206+ let target = (escapeURI $ removeTrailingSpace src, tit)
206207 st <- getState
207208 let oldkeys = stateKeys st
208− updateState $ \s -> s { stateKeys = newkey : oldkeys }
209+ updateState $ \s -> s { stateKeys = M.insert (Key lab) target oldkeys }
209210 -- return blanks so line count isn't affected
210211 return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
211212
@@ -1216,7 +1217,7 @@ referenceLink lab = do
12161217 optional (newline >> skipSpaces) >> reference))
12171218 let ref' = if null ref then lab else ref
12181219 state <- getState
1219− case lookupKeySrc (stateKeys state) ref' of
1220+ case lookupKeySrc (stateKeys state) (Key ref') of
12201221 Nothing -> fail "no corresponding key"
12211222 Just target -> return target
12221223
@@ -1301,7 +1302,7 @@ inlineCitation = try $ do
13011302chkCit :: Target -> GenParser Char ParserState (Maybe Target)
13021303chkCit t = do
13031304 st <- getState
1304− case lookupKeySrc (stateKeys st) [Str $ fst t] of
1305+ case lookupKeySrc (stateKeys st) (Key [Str $ fst t]) of
13051306 Just _ -> fail "This is a link"
13061307 Nothing -> if elem (fst t) $ stateCitations st
13071308 then return $ Just t
src/Text/Pandoc/Readers/RST.hs+23−19
@@ -34,7 +34,9 @@ import Text.Pandoc.Definition
3434import Text.Pandoc.Shared
3535import Text.ParserCombinators.Parsec
3636import Control.Monad ( when, unless, liftM )
37−import Data.List ( findIndex, delete, intercalate, transpose )
37+import Data.List ( findIndex, intercalate, transpose, sort )
38+import qualified Data.Map as M
39+import Text.Printf ( printf )
3840
3941-- | Parse reStructuredText string and return Pandoc document.
4042readRST :: ParserState -- ^ Parser state, including options for parser
@@ -93,9 +95,6 @@ parseRST = do
9395 docMinusKeys <- manyTill (referenceKey <|> lineClump) eof >>= return . concat
9496 setInput docMinusKeys
9597 setPosition startPos
96− st <- getState
97− let reversedKeys = stateKeys st
98− updateState $ \s -> s { stateKeys = reverse reversedKeys }
9998 -- now parse it for real...
10099 blocks <- parseBlocks
101100 let blocks' = filter (/= Null) blocks
@@ -540,10 +539,10 @@ referenceName = quotedReferenceName <|>
540539referenceKey :: GenParser Char ParserState [Char]
541540referenceKey = do
542541 startPos <- getPosition
543− key <- choice [imageKey, anonymousKey, regularKey]
542+ (key, target) <- choice [imageKey, anonymousKey, regularKey]
544543 st <- getState
545544 let oldkeys = stateKeys st
546− updateState $ \s -> s { stateKeys = key : oldkeys }
545+ updateState $ \s -> s { stateKeys = M.insert key target oldkeys }
547546 optional blanklines
548547 endPos <- getPosition
549548 -- return enough blanks to replace key
@@ -558,28 +557,29 @@ targetURI = do
558557 blanklines
559558 return $ escapeURI $ removeLeadingTrailingSpace $ contents
560559
561−imageKey :: GenParser Char ParserState ([Inline], (String, [Char]))
560+imageKey :: GenParser Char ParserState (Key, Target)
562561imageKey = try $ do
563562 string ".. |"
564563 ref <- manyTill inline (char '|')
565564 skipSpaces
566565 string "image::"
567566 src <- targetURI
568− return (normalizeSpaces ref, (src, ""))
567+ return (Key (normalizeSpaces ref), (src, ""))
569568
570−anonymousKey :: GenParser Char st ([Inline], (String, [Char]))
569+anonymousKey :: GenParser Char st (Key, Target)
571570anonymousKey = try $ do
572571 oneOfStrings [".. __:", "__"]
573572 src <- targetURI
574− return ([Str "_"], (src, ""))
573+ pos <- getPosition
574+ return (Key [Str $ "_" ++ printf "%09d" (sourceLine pos)], (src, ""))
575575
576−regularKey :: GenParser Char ParserState ([Inline], (String, [Char]))
576+regularKey :: GenParser Char ParserState (Key, Target)
577577regularKey = try $ do
578578 string ".. _"
579579 ref <- referenceName
580580 char ':'
581581 src <- targetURI
582− return (normalizeSpaces ref, (src, ""))
582+ return (Key (normalizeSpaces ref), (src, ""))
583583
584584--
585585-- tables
@@ -889,17 +889,21 @@ explicitLink = try $ do
889889referenceLink :: GenParser Char ParserState Inline
890890referenceLink = try $ do
891891 label' <- (quotedReferenceName <|> simpleReferenceName) >>~ char '_'
892− key <- option label' (do{char '_'; return [Str "_"]}) -- anonymous link
893892 state <- getState
894893 let keyTable = stateKeys state
894+ let isAnonKey (Key [Str ('_':_)]) = True
895+ isAnonKey _ = False
896+ key <- option (Key label') $
897+ do char '_'
898+ let anonKeys = sort $ filter isAnonKey $ M.keys keyTable
899+ if null anonKeys
900+ then pzero
901+ else return (head anonKeys)
895902 (src,tit) <- case lookupKeySrc keyTable key of
896903 Nothing -> fail "no corresponding key"
897904 Just target -> return target
898− -- if anonymous link, remove first anon key so it won't be used again
899− let keyTable' = if (key == [Str "_"]) -- anonymous link?
900− then delete ([Str "_"], (src,tit)) keyTable -- remove first anon key
901− else keyTable
902− setState $ state { stateKeys = keyTable' }
905+ -- if anonymous link, remove key so it won't be used again
906+ when (isAnonKey key) $ updateState $ \s -> s{ stateKeys = M.delete key keyTable }
903907 return $ Link (normalizeSpaces label') (src, tit)
904908
905909autoURI :: GenParser Char ParserState Inline
@@ -922,7 +926,7 @@ image = try $ do
922926 ref <- manyTill inline (char '|')
923927 state <- getState
924928 let keyTable = stateKeys state
925− (src,tit) <- case lookupKeySrc keyTable ref of
929+ (src,tit) <- case lookupKeySrc keyTable (Key ref) of
926930 Nothing -> fail "no corresponding key"
927931 Just target -> return target
928932 return $ Image (normalizeSpaces ref) (src, tit)
src/Text/Pandoc/Shared.hs+16−6
@@ -88,6 +88,7 @@ module Text.Pandoc.Shared (
8888 QuoteContext (..),
8989 NoteTable,
9090 KeyTable,
91+ Key (..),
9192 lookupKeySrc,
9293 refsMatch,
9394 -- * Prettyprinting
@@ -127,6 +128,7 @@ import System.FilePath ( (</>) )
127128import Data.Generics (Typeable, Data)
128129import qualified Control.Monad.State as S
129130import Control.Monad (join)
131+import qualified Data.Map as M
130132import Paths_pandoc (getDataFileName)
131133
132134--
@@ -704,7 +706,7 @@ defaultParserState =
704706 stateParserContext = NullState,
705707 stateQuoteContext = NoQuote,
706708 stateSanitizeHTML = False,
707− stateKeys = [],
709+ stateKeys = M.empty,
708710#ifdef _CITEPROC
709711 stateCitations = [],
710712#endif
@@ -739,15 +741,23 @@ data QuoteContext
739741
740742type NoteTable = [(String, String)]
741743
742−type KeyTable = [([Inline], Target)]
744+newtype Key = Key [Inline] deriving (Show, Read)
745+
746+instance Eq Key where
747+ Key a == Key b = refsMatch a b
748+
749+instance Ord Key where
750+ compare (Key a) (Key b) = if a == b then EQ else compare a b
751+
752+type KeyTable = M.Map Key Target
743753
744754-- | Look up key in key table and return target object.
745755lookupKeySrc :: KeyTable -- ^ Key table
746− -> [Inline] -- ^ Key
756+ -> Key -- ^ Key
747757 -> Maybe Target
748−lookupKeySrc table key = case find (refsMatch key . fst) table of
749− Nothing -> Nothing
750− Just (_, src) -> Just src
758+lookupKeySrc table key = case M.lookup key table of
759+ Nothing -> Nothing
760+ Just src -> Just src
751761
752762-- | Returns @True@ if keys match (case insensitive).
753763refsMatch :: [Inline] -> [Inline] -> Bool
src/Text/Pandoc/Writers/Markdown.hs+4−4
@@ -40,7 +40,7 @@ import Text.PrettyPrint.HughesPJ hiding ( Str )
4040import Control.Monad.State
4141
4242type Notes = [[Block]]
43−type Refs = KeyTable
43+type Refs = [([Inline], Target)]
4444data WriterState = WriterState { stNotes :: Notes
4545 , stRefs :: Refs
4646 , stPlain :: Bool }
@@ -94,7 +94,7 @@ pandocToMarkdown opts (Pandoc (Meta title authors date) blocks) = do
9494 st <- get
9595 notes' <- notesToMarkdown opts (reverse $ stNotes st)
9696 st' <- get -- note that the notes may contain refs
97− refs' <- keyTableToMarkdown opts (reverse $ stRefs st')
97+ refs' <- refsToMarkdown opts (reverse $ stRefs st')
9898 let main = render $ body $+$ text "" $+$ notes' $+$ text "" $+$ refs'
9999 let context = writerVariables opts ++
100100 [ ("toc", render toc)
@@ -109,8 +109,8 @@ pandocToMarkdown opts (Pandoc (Meta title authors date) blocks) = do
109109 else return main
110110
111111-- | Return markdown representation of reference key table.
112−keyTableToMarkdown :: WriterOptions -> KeyTable -> State WriterState Doc
113−keyTableToMarkdown opts refs = mapM (keyToMarkdown opts) refs >>= return . vcat
112+refsToMarkdown :: WriterOptions -> Refs -> State WriterState Doc
113+refsToMarkdown opts refs = mapM (keyToMarkdown opts) refs >>= return . vcat
114114
115115-- | Return markdown representation of a reference key.
116116keyToMarkdown :: WriterOptions
src/Text/Pandoc/Writers/RST.hs+10−8
@@ -39,10 +39,12 @@ import Text.PrettyPrint.HughesPJ hiding ( Str )
3939import Control.Monad.State
4040import Control.Applicative ( (<$>) )
4141
42+type Refs = [([Inline], Target)]
43+
4244data WriterState =
4345 WriterState { stNotes :: [[Block]]
44− , stLinks :: KeyTable
45− , stImages :: KeyTable
46+ , stLinks :: Refs
47+ , stImages :: Refs
4648 , stHasMath :: Bool
4749 , stOptions :: WriterOptions
4850 }
@@ -65,8 +67,8 @@ pandocToRST (Pandoc (Meta tit auth dat) blocks) = do
6567 body <- blockListToRST blocks
6668 notes <- liftM (reverse . stNotes) get >>= notesToRST
6769 -- note that the notes may contain refs, so we do them first
68− refs <- liftM (reverse . stLinks) get >>= keyTableToRST
69− pics <- liftM (reverse . stImages) get >>= pictTableToRST
70+ refs <- liftM (reverse . stLinks) get >>= refsToRST
71+ pics <- liftM (reverse . stImages) get >>= pictRefsToRST
7072 hasMath <- liftM stHasMath get
7173 let main = render $ body $+$ notes $+$ text "" $+$ refs $+$ pics
7274 let context = writerVariables opts ++
@@ -80,8 +82,8 @@ pandocToRST (Pandoc (Meta tit auth dat) blocks) = do
8082 else return main
8183
8284-- | Return RST representation of reference key table.
83−keyTableToRST :: KeyTable -> State WriterState Doc
84−keyTableToRST refs = mapM keyToRST refs >>= return . vcat
85+refsToRST :: Refs -> State WriterState Doc
86+refsToRST refs = mapM keyToRST refs >>= return . vcat
8587
8688-- | Return RST representation of a reference key.
8789keyToRST :: ([Inline], (String, String))
@@ -107,8 +109,8 @@ noteToRST num note = do
107109 return $ marker $$ nest 3 contents
108110
109111-- | Return RST representation of picture reference table.
110−pictTableToRST :: KeyTable -> State WriterState Doc
111−pictTableToRST refs = mapM pictToRST refs >>= return . vcat
112+pictRefsToRST :: Refs -> State WriterState Doc
113+pictRefsToRST refs = mapM pictToRST refs >>= return . vcat
112114
113115-- | Return RST representation of a picture substitution reference.
114116pictToRST :: ([Inline], (String, String))