git.iko.soy/typeable/pandoc
on master help sign in
Markdown reader: warn for notes defined but not used.

Closes #1718. Parsing.ParserState: Make stateNotes' a Map, add stateNoteRefs.

commit8f2c803f973d53da340c876edbbcb2b1223f35cd authorJohn MacFarlane <jgm@berkeley.edu> dateThu 25 May 2017, 11:15 (9 years ago) parent41db9e8
3 files changed+29−8
src/Text/Pandoc/Logging.hs+10 src/Text/Pandoc/Parsing.hs+5−2 src/Text/Pandoc/Readers/Markdown.hs+14−6
src/Text/Pandoc/Logging.hs+10
@@ -72,6 +72,7 @@ data LogMessage =
7272 | CouldNotParseYamlMetadata String SourcePos
7373 | DuplicateLinkReference String SourcePos
7474 | DuplicateNoteReference String SourcePos
75+ | NoteDefinedButNotUsed String SourcePos
7576 | DuplicateIdentifier String SourcePos
7677 | ReferenceNotFound String SourcePos
7778 | CircularReference String SourcePos
@@ -113,6 +114,11 @@ instance ToJSON LogMessage where
113114 "source" .= Text.pack (sourceName pos),
114115 "line" .= toJSON (sourceLine pos),
115116 "column" .= toJSON (sourceColumn pos)]
117+ NoteDefinedButNotUsed s pos ->
118+ ["key" .= Text.pack s,
119+ "source" .= Text.pack (sourceName pos),
120+ "line" .= toJSON (sourceLine pos),
121+ "column" .= toJSON (sourceColumn pos)]
116122 DuplicateNoteReference s pos ->
117123 ["contents" .= Text.pack s,
118124 "source" .= Text.pack (sourceName pos),
@@ -203,6 +209,9 @@ showLogMessage msg =
203209 "Duplicate link reference '" ++ s ++ "' at " ++ showPos pos
204210 DuplicateNoteReference s pos ->
205211 "Duplicate note reference '" ++ s ++ "' at " ++ showPos pos
212+ NoteDefinedButNotUsed s pos ->
213+ "Note with key '" ++ s ++ "' defined at " ++ showPos pos ++
214+ " but not used."
206215 DuplicateIdentifier s pos ->
207216 "Duplicate identifier '" ++ s ++ "' at " ++ showPos pos
208217 ReferenceNotFound s pos ->
@@ -256,6 +265,7 @@ messageVerbosity msg =
256265 CouldNotParseYamlMetadata{} -> WARNING
257266 DuplicateLinkReference{} -> WARNING
258267 DuplicateNoteReference{} -> WARNING
268+ NoteDefinedButNotUsed{} -> WARNING
259269 DuplicateIdentifier{} -> WARNING
260270 ReferenceNotFound{} -> WARNING
261271 CircularReference{} -> WARNING
src/Text/Pandoc/Parsing.hs+5−2
@@ -983,6 +983,7 @@ data ParserState = ParserState
983983 stateSubstitutions :: SubstTable, -- ^ List of substitution references
984984 stateNotes :: NoteTable, -- ^ List of notes (raw bodies)
985985 stateNotes' :: NoteTable', -- ^ List of notes (parsed bodies)
986+ stateNoteRefs :: Set.Set String, -- ^ List of note references used
986987 stateMeta :: Meta, -- ^ Document metadata
987988 stateMeta' :: F Meta, -- ^ Document metadata
988989 stateCitations :: M.Map String String, -- ^ RST-style citations
@@ -1099,7 +1100,8 @@ defaultParserState =
10991100 stateHeaderKeys = M.empty,
11001101 stateSubstitutions = M.empty,
11011102 stateNotes = [],
1102− stateNotes' = [],
1103+ stateNotes' = M.empty,
1104+ stateNoteRefs = Set.empty,
11031105 stateMeta = nullMeta,
11041106 stateMeta' = return nullMeta,
11051107 stateCitations = M.empty,
@@ -1166,7 +1168,8 @@ data QuoteContext
11661168
11671169type NoteTable = [(String, String)]
11681170
1169−type NoteTable' = [(String, F Blocks)] -- used in markdown reader
1171+type NoteTable' = M.Map String (SourcePos, F Blocks)
1172+-- used in markdown reader
11701173
11711174newtype Key = Key String deriving (Show, Read, Eq, Ord)
11721175
src/Text/Pandoc/Readers/Markdown.hs+14−6
@@ -362,6 +362,14 @@ parseMarkdown = do
362362 optional titleBlock
363363 blocks <- parseBlocks
364364 st <- getState
365+ -- check for notes with no corresponding note references
366+ let notesUsed = stateNoteRefs st
367+ let notesDefined = M.keys (stateNotes' st)
368+ mapM_ (\n -> unless (n `Set.member` notesUsed) $ do
369+ -- lookup to get sourcepos
370+ case M.lookup n (stateNotes' st) of
371+ Just (pos, _) -> report (NoteDefinedButNotUsed n pos)
372+ Nothing -> error "The impossible happened.") notesDefined
365373 let doc = runF (do Pandoc _ bs <- B.doc <$> blocks
366374 meta <- stateMeta' st
367375 return $ Pandoc meta bs) st
@@ -469,12 +477,11 @@ noteBlock = try $ do
469477 let raw = unlines (first:rest) ++ "\n"
470478 optional blanklines
471479 parsed <- parseFromString' parseBlocks raw
472− let newnote = (ref, parsed)
473480 oldnotes <- stateNotes' <$> getState
474− case lookup ref oldnotes of
481+ case M.lookup ref oldnotes of
475482 Just _ -> logMessage $ DuplicateNoteReference ref pos
476483 Nothing -> return ()
477− updateState $ \s -> s { stateNotes' = newnote : oldnotes }
484+ updateState $ \s -> s { stateNotes' = M.insert ref (pos, parsed) oldnotes }
478485 return mempty
479486
480487--
@@ -1816,16 +1823,17 @@ note :: PandocMonad m => MarkdownParser m (F Inlines)
18161823note = try $ do
18171824 guardEnabled Ext_footnotes
18181825 ref <- noteMarker
1826+ updateState $ \st -> st{ stateNoteRefs = Set.insert ref (stateNoteRefs st) }
18191827 return $ do
18201828 notes <- asksF stateNotes'
1821− case lookup ref notes of
1829+ case M.lookup ref notes of
18221830 Nothing -> return $ B.str $ "[^" ++ ref ++ "]"
1823− Just contents -> do
1831+ Just (_pos, contents) -> do
18241832 st <- askF
18251833 -- process the note in a context that doesn't resolve
18261834 -- notes, to avoid infinite looping with notes inside
18271835 -- notes:
1828− let contents' = runF contents st{ stateNotes' = [] }
1836+ let contents' = runF contents st{ stateNotes' = M.empty }
18291837 return $ B.note contents'
18301838
18311839inlineNote :: PandocMonad m => MarkdownParser m (F Inlines)