@@ -33,15 +33,23 @@ module Text.Pandoc.Readers.CommonMark (readCommonMark)
3333where
3434
3535import CMarkGFM
36+import Control.Monad.State
37+import Data.Char (isLetter, isAlphaNum, isSpace, toLower)
3638import Data.List (groupBy)
3739import Data.Text (Text, unpack)
40+import qualified Data.Map as Map
3841import Text.Pandoc.Class (PandocMonad)
3942import Text.Pandoc.Definition
4043import Text.Pandoc.Options
44+import Text.Pandoc.Shared (stringify)
45+import Text.Pandoc.Walk (walkM)
4146
4247-- | Parse a CommonMark formatted string into a 'Pandoc' structure.
4348readCommonMark :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
4449readCommonMark opts s = return $
50+ (if enabled Ext_gfm_auto_identifiers
51+ then addHeaderIdentifiers
52+ else id) $
4553 nodeToPandoc $ commonmarkToNode opts' exts s
4654 where opts' = [ optSmart | enabled Ext_smart ]
4755 exts = [ extStrikethrough | enabled Ext_strikeout ] ++
@@ -49,6 +57,29 @@ readCommonMark opts s = return $
4957 [ extAutolink | enabled Ext_autolink_bare_uris ]
5058 enabled x = extensionEnabled x (readerExtensions opts)
5159
60+addHeaderIdentifiers :: Pandoc -> Pandoc
61+addHeaderIdentifiers doc = evalState (walkM addHeaderId doc) mempty
62+
63+addHeaderId :: Block -> State (Map.Map String Int) Block
64+addHeaderId (Header lev (_,classes,kvs) ils) = do
65+ idmap <- get
66+ let ident = toIdent ils
67+ ident' <- case Map.lookup ident idmap of
68+ Nothing -> do
69+ put (Map.insert ident 1 idmap)
70+ return ident
71+ Just i -> do
72+ put (Map.adjust (+ 1) ident idmap)
73+ return (ident ++ "-" ++ show i)
74+ return $ Header lev (ident',classes,kvs) ils
75+addHeaderId x = return x
76+
77+toIdent :: [Inline] -> String
78+toIdent = map (\c -> if isSpace c then '-' else c)
79+ . filter (\c -> isLetter c || isAlphaNum c || isSpace c ||
80+ c == '_' || c == '-')
81+ . map toLower . stringify
82+
5283nodeToPandoc :: Node -> Pandoc
5384nodeToPandoc (Node _ DOCUMENT nodes) =
5485 Pandoc nullMeta $ foldr addBlock [] nodes