emanote-1.0.2.0: src/Emanote/Pandoc/ExternalLink.hs
module Emanote.Pandoc.ExternalLink (
setExternalLinkIcon,
) where
import Relude
import Text.Pandoc.Definition qualified as B
import Text.Pandoc.Walk qualified as W
import Text.Parsec qualified as P
import Text.Parsec.Char qualified as PC
-- Add a data-linkicon=external attribute to external links that contain some
-- text in their description, provided that they do not already have a
-- data-linkicon attribute.
setExternalLinkIcon :: W.Walkable B.Inline b => b -> b
setExternalLinkIcon =
W.walk $ \case
B.Link (id', classes, attrs) inlines (url, title)
| hasURIScheme url && containsText inlines ->
let showLinkIconAttr = ("data-linkicon", "external")
newAttrs = insert attrs showLinkIconAttr
in B.Link (id', classes, newAttrs) inlines (url, title)
x -> x
where
-- Inserts an element in a key-value list if the element's key is not
-- already in the list.
insert :: Eq a => [(a, b)] -> (a, b) -> [(a, b)]
insert as a
| fst a `elem` (fst <$> as) = as
| otherwise = a : as
-- Checks whether the given text begins with an RFC 3986 compliant URI
-- scheme.
hasURIScheme :: Text -> Bool
hasURIScheme =
isRight . P.parse schemeP ""
where
schemeP = do
c <- PC.letter
cs <- P.many $ PC.alphaNum P.<|> P.oneOf ".-+"
void $ PC.char ':'
return (c : cs)
-- Checks whether a list of inlines contains a (perhaps nested) "textual
-- element", understood as a Pandoc `Str`, `Code` or `Math`.
containsText :: [B.Inline] -> Bool
containsText =
getAny
. W.query
( \case
B.Str _ -> Any True
B.Code _ _ -> Any True
B.Math _ _ -> Any True
_ -> Any False
)