git.iko.soy/typeable/pandoc
on master help sign in
Markdown reader: Made implicit header references case-insensitive.

Added `stateHeaderKeys` to `ParserState`; this is a `KeyTable` like `stateKeys`, but it only gets consulted if we don't find a match in `stateKeys`, and if `Ext_implicit_header_references` is enabled. Closes #1606.

commit24ee1ab4f739d9f89e3d2741d841a99ebaaafabf authorJohn MacFarlane <jgm@berkeley.edu> dateWed 13 May 2015, 23:02 (11 years ago) parentdc51114
6 files changed+45−16
README+10−3 changelog+6−1 src/Text/Pandoc/Parsing.hs+3−1 src/Text/Pandoc/Readers/Markdown.hs+23−11 tests/markdown-reader-more.native+1 tests/markdown-reader-more.txt+2
README+10−3
@@ -1269,10 +1269,17 @@ If there are multiple headers with identical text, the corresponding
12691269reference will link to the first one only, and you will need to use explicit
12701270links to link to the others, as described above.
12711271
1272−Unlike regular reference links, these references are case-sensitive.
1272+Like regular reference links, these references are case-insensitive.
12731273
1274−Note: if you have defined an explicit identifier for a header,
1275−then implicit references to it will not work.
1274+Explicit link reference definitions always take priority over
1275+implicit header references. So, in the following example, the
1276+link will point to `bar`, not to `#foo`:
1277+
1278+ # Foo
1279+
1280+ [foo]: bar
1281+
1282+ See [foo]
12761283
12771284Block quotations
12781285----------------
changelog+6−1
@@ -35,6 +35,8 @@ pandoc (1.14)
3535
3636 * Markdown reader:
3737
38+ + Reference links with `implicit_header_references` are no longer
39+ case-sensitive (#1606).
3840 + Definition lists: don't require indent for first line (#2087).
3941 Previously the body of the definition (after the `:` or `~` marker)
4042 needed to be in column 4. This commit relaxes that requirement,
@@ -439,7 +441,10 @@ pandoc (1.14)
439441 `extra-source-files`. This should make maintenance of these components
440442 easier going forward.
441443
442− * `Text.Pandoc.Parsing`: Added new `<+?>` combinator (Nikolay Yakimov).
444+ * `Text.Pandoc.Parsing`:
445+
446+ + Added new `<+?>` combinator (Nikolay Yakimov).
447+ + Added `stateHeaderKeys` to `ParserState`.
443448
444449 * `make_deb.sh` fixes:
445450
src/Text/Pandoc/Parsing.hs+3−1
@@ -903,7 +903,8 @@ data ParserState = ParserState
903903 stateAllowLinks :: Bool, -- ^ Allow parsing of links
904904 stateMaxNestingLevel :: Int, -- ^ Max # of nested Strong/Emph
905905 stateLastStrPos :: Maybe SourcePos, -- ^ Position after last str parsed
906− stateKeys :: KeyTable, -- ^ List of reference keys (with fallbacks)
906+ stateKeys :: KeyTable, -- ^ List of reference keys
907+ stateHeaderKeys :: KeyTable, -- ^ List of implicit header ref keys
907908 stateSubstitutions :: SubstTable, -- ^ List of substitution references
908909 stateNotes :: NoteTable, -- ^ List of notes (raw bodies)
909910 stateNotes' :: NoteTable', -- ^ List of notes (parsed bodies)
@@ -1001,6 +1002,7 @@ defaultParserState =
10011002 stateMaxNestingLevel = 6,
10021003 stateLastStrPos = Nothing,
10031004 stateKeys = M.empty,
1005+ stateHeaderKeys = M.empty,
10041006 stateSubstitutions = M.empty,
10051007 stateNotes = [],
10061008 stateNotes' = [],
src/Text/Pandoc/Readers/Markdown.hs+23−11
@@ -509,9 +509,12 @@ atxHeader = try $ do
509509 notFollowedBy $ guardEnabled Ext_fancy_lists >>
510510 (char '.' <|> char ')') -- this would be a list
511511 skipSpaces
512− text <- trimInlinesF . mconcat <$> many (notFollowedBy atxClosing >> inline)
512+ (text, raw) <- withRaw $
513+ trimInlinesF . mconcat <$> many (notFollowedBy atxClosing >> inline)
513514 attr <- atxClosing
514− attr' <- registerHeader attr (runF text defaultParserState)
515+ attr'@(ident,_,_) <- registerHeader attr (runF text defaultParserState)
516+ guardDisabled Ext_implicit_header_references
517+ <|> registerImplicitHeader raw ident
515518 return $ B.headerWith attr' level <$> text
516519
517520atxClosing :: MarkdownParser Attr
@@ -544,15 +547,24 @@ setextHeader = try $ do
544547 -- This lookahead prevents us from wasting time parsing Inlines
545548 -- unless necessary -- it gives a significant performance boost.
546549 lookAhead $ anyLine >> many1 (oneOf setextHChars) >> blankline
547− text <- trimInlinesF . mconcat <$> many1 (notFollowedBy setextHeaderEnd >> inline)
550+ (text, raw) <- withRaw $
551+ trimInlinesF . mconcat <$> many1 (notFollowedBy setextHeaderEnd >> inline)
548552 attr <- setextHeaderEnd
549553 underlineChar <- oneOf setextHChars
550554 many (char underlineChar)
551555 blanklines
552556 let level = (fromMaybe 0 $ findIndex (== underlineChar) setextHChars) + 1
553− attr' <- registerHeader attr (runF text defaultParserState)
557+ attr'@(ident,_,_) <- registerHeader attr (runF text defaultParserState)
558+ guardDisabled Ext_implicit_header_references
559+ <|> registerImplicitHeader raw ident
554560 return $ B.headerWith attr' level <$> text
555561
562+registerImplicitHeader :: String -> String -> MarkdownParser ()
563+registerImplicitHeader raw ident = do
564+ let key = toKey $ "[" ++ raw ++ "]"
565+ updateState (\s -> s { stateHeaderKeys =
566+ M.insert key ('#':ident,"") (stateHeaderKeys s) })
567+
556568--
557569-- hrule block
558570--
@@ -1700,7 +1712,7 @@ referenceLink :: (String -> String -> Inlines -> Inlines)
17001712 -> (F Inlines, String) -> MarkdownParser (F Inlines)
17011713referenceLink constructor (lab, raw) = do
17021714 sp <- (True <$ lookAhead (char ' ')) <|> return False
1703− (ref,raw') <- option (mempty, "") $
1715+ (_,raw') <- option (mempty, "") $
17041716 lookAhead (try (spnl >> normalCite >> return (mempty, "")))
17051717 <|>
17061718 try (spnl >> reference)
@@ -1720,13 +1732,13 @@ referenceLink constructor (lab, raw) = do
17201732 return $ do
17211733 keys <- asksF stateKeys
17221734 case M.lookup key keys of
1723− Nothing -> do
1724− headers <- asksF stateHeaders
1725− ref' <- if labIsRef then lab else ref
1735+ Nothing ->
17261736 if implicitHeaderRefs
1727− then case M.lookup ref' headers of
1728− Just ident -> constructor ('#':ident) "" <$> lab
1729− Nothing -> makeFallback
1737+ then do
1738+ headerKeys <- asksF stateHeaderKeys
1739+ case M.lookup key headerKeys of
1740+ Just (src, tit) -> constructor src tit <$> lab
1741+ Nothing -> makeFallback
17301742 else makeFallback
17311743 Just (src,tit) -> constructor src tit <$> lab
17321744
tests/markdown-reader-more.native+1
@@ -76,6 +76,7 @@
7676,Header 3 ("my-other-header",[],[]) [Str "My",Space,Str "other",Space,Str "header"]
7777,Para [Str "A",Space,Str "link",Space,Str "to",Space,Link [Str "My",Space,Str "header"] ("#my-header-1",""),Str "."]
7878,Para [Str "Another",Space,Str "link",Space,Str "to",Space,Link [Str "it"] ("#my-header-1",""),Str "."]
79+,Para [Str "Should",Space,Str "be",Space,Link [Str "case",Space,Str "insensitive"] ("#my-header-1",""),Str "."]
7980,Para [Str "Link",Space,Str "to",Space,Link [Str "Explicit",Space,Str "header",Space,Str "attributes"] ("#foobar",""),Str "."]
8081,Para [Str "But",Space,Str "this",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "link",Space,Str "to",Space,Link [Str "My",Space,Str "other",Space,Str "header"] ("/foo",""),Str ",",Space,Str "since",Space,Str "the",Space,Str "reference",Space,Str "is",Space,Str "defined."]
8182,Header 2 ("foobar",["baz"],[("key","val")]) [Str "Explicit",Space,Str "header",Space,Str "attributes"]
tests/markdown-reader-more.txt+2
@@ -168,6 +168,8 @@ A link to [My header].
168168
169169Another link to [it][My header].
170170
171+Should be [case insensitive][my header].
172+
171173Link to [Explicit header attributes].
172174
173175[my other header]: /foo