@@ -116,8 +116,7 @@ import Control.Monad (MonadPlus (..), msum, unless)
116116import qualified Control.Monad.State.Strict as S
117117import qualified Data.ByteString.Lazy as BL
118118import qualified Data.Bifunctor as Bifunctor
119−import Data.Char (isAlpha, isDigit, isLetter, isLower, isSpace, isUpper,
120− toLower)
119+import Data.Char (isAlpha, isLower, isSpace, isUpper, toLower, isAlphaNum)
121120import Data.Data (Data, Typeable)
122121import Data.List (find, intercalate, intersperse, stripPrefix)
123122import qualified Data.Map as M
@@ -137,7 +136,9 @@ import Text.HTML.TagSoup (RenderOptions (..), Tag (..), renderOptions,
137136import Text.Pandoc.Builder (Blocks, Inlines, ToMetaValue (..))
138137import qualified Text.Pandoc.Builder as B
139138import Data.Time
139+import Text.Pandoc.Asciify (toAsciiChar)
140140import Text.Pandoc.Definition
141+import Text.Pandoc.Extensions (Extensions, Extension(..), extensionEnabled)
141142import Text.Pandoc.Generic (bottomUp)
142143import Text.Pandoc.Pretty (charWidth)
143144import Text.Pandoc.Walk
@@ -483,18 +484,29 @@ instance Walkable Block Element where
483484 query f (Blk x) = query f x
484485 query f (Sec _ _ _ ils elts) = query f ils `mappend` query f elts
485486
486−
487487-- | Convert Pandoc inline list to plain text identifier. HTML
488488-- identifiers must start with a letter, and may contain only
489489-- letters, digits, and the characters _-.
490−inlineListToIdentifier :: [Inline] -> String
491−inlineListToIdentifier =
492− dropWhile (not . isAlpha) . intercalate "-" . words .
493− map (nbspToSp . toLower) .
494− filter (\c -> isLetter c || isDigit c || c `elem` "_-. ") .
495− stringify
496− where nbspToSp '\160' = ' '
497− nbspToSp x = x
490+inlineListToIdentifier :: Extensions -> [Inline] -> String
491+inlineListToIdentifier exts =
492+ dropNonLetter . filterAscii . toIdent . stringify
493+ where
494+ dropNonLetter
495+ | extensionEnabled Ext_gfm_auto_identifiers exts = id
496+ | otherwise = dropWhile (not . isAlpha)
497+ filterAscii
498+ | extensionEnabled Ext_ascii_identifiers exts
499+ = mapMaybe toAsciiChar
500+ | otherwise = id
501+ toIdent
502+ | extensionEnabled Ext_gfm_auto_identifiers exts =
503+ filterPunct . spaceToDash . map toLower
504+ | otherwise = intercalate "-" . words . filterPunct . map toLower
505+ filterPunct = filter (\c -> isSpace c || isAlphaNum c || isAllowedPunct c)
506+ isAllowedPunct c
507+ | extensionEnabled Ext_gfm_auto_identifiers exts = c == '_' || c == '-'
508+ | otherwise = c == '_' || c == '-' || c == '.'
509+ spaceToDash = map (\c -> if isSpace c then '-' else c)
498510
499511-- | Convert list of Pandoc blocks into (hierarchical) list of Elements
500512hierarchicalize :: [Block] -> [Element]
@@ -530,17 +542,20 @@ headerLtEq _ _ = False
530542
531543-- | Generate a unique identifier from a list of inlines.
532544-- Second argument is a list of already used identifiers.
533−uniqueIdent :: [Inline] -> Set.Set String -> String
534−uniqueIdent title' usedIdents
535− = let baseIdent = case inlineListToIdentifier title' of
536− "" -> "section"
537− x -> x
538− numIdent n = baseIdent ++ "-" ++ show n
539− in if baseIdent `Set.member` usedIdents
540− then case find (\x -> not $ numIdent x `Set.member` usedIdents) ([1..60000] :: [Int]) of
541− Just x -> numIdent x
542− Nothing -> baseIdent -- if we have more than 60,000, allow repeats
543− else baseIdent
545+uniqueIdent :: Extensions -> [Inline] -> Set.Set String -> String
546+uniqueIdent exts title' usedIdents =
547+ if baseIdent `Set.member` usedIdents
548+ then case find (\x -> not $ numIdent x `Set.member` usedIdents)
549+ ([1..60000] :: [Int]) of
550+ Just x -> numIdent x
551+ Nothing -> baseIdent
552+ -- if we have more than 60,000, allow repeats
553+ else baseIdent
554+ where
555+ baseIdent = case inlineListToIdentifier exts title' of
556+ "" -> "section"
557+ x -> x
558+ numIdent n = baseIdent ++ "-" ++ show n
544559
545560-- | True if block is a Header block.
546561isHeaderBlock :: Block -> Bool