1+ {-# LANGUAGE ConstraintKinds #-}
12{-# LANGUAGE MultiParamTypeClasses #-}
23{-# LANGUAGE OverloadedStrings #-}
34{-# LANGUAGE FlexibleInstances #-}
45{-# LANGUAGE FlexibleContexts #-}
56{-# LANGUAGE GeneralizedNewtypeDeriving #-}
67{-# LANGUAGE UndecidableInstances #-}
7- module Distribution.Server.Util.Markdown where
8+
9+ module Distribution.Server.Util.Markdown
10+ ( renderMarkdown
11+ , renderMarkdownRel
12+ , supposedToBeMarkdown
13+ ) where
814
915import Commonmark
1016import Commonmark.Extensions
@@ -14,6 +20,7 @@ import qualified Data.Text as T
1420import qualified Data.Text.Encoding as T
1521import qualified Data.Text.Encoding.Error as T (lenientDecode )
1622import qualified Data.Text.Lazy as TL
23+ import Data.Typeable (Typeable )
1724import Network.URI (isRelativeReference )
1825import Control.Monad.Identity
1926import Text.HTML.SanitizeXSS as XSS
@@ -83,38 +90,61 @@ instance HasMath (HHtml a) where
8390 inlineMath t = HHtml $ inlineMath t
8491 displayMath t = HHtml $ displayMath t
8592
86-
8793instance Rangeable (Html a ) => HasFootnote (HHtml a ) (HHtml a ) where
8894 footnote x y (HHtml t) = HHtml (footnote x y t)
8995 footnoteList xs = HHtml $ footnoteList (map unHHtml xs)
9096 footnoteRef x y (HHtml t) = HHtml (footnoteRef x y t)
9197
98+ -- | Prefix relative links with @src/@.
9299adjustRelativeLink :: T. Text -> T. Text
93100adjustRelativeLink url
94101 | isRelativeReference (T. unpack url) &&
95102 not (" /" `T.isPrefixOf` url)
96103 = " src/" <> url
97104 | otherwise = url
98105
99-
100- renderHHtml :: HHtml () -> TL. Text
101- renderHHtml (HHtml x) = renderHtml x
102-
103- renderMarkdown :: String -> BS. ByteString -> XHtml. Html
104- renderMarkdown name md =
105- either (const $ XHtml. pre XHtml. << T. unpack txt) (XHtml. primHtml . T. unpack . sanitizeBalance . TL. toStrict . (renderHtml :: Html () -> TL. Text )) $
106- runIdentity (commonmarkWith (mathSpec <> footnoteSpec <> defaultSyntaxSpec <> gfmExtensions)
107- name
108- txt)
109- where txt = T. decodeUtf8With T. lenientDecode . BS. toStrict $ md
110-
111- renderMarkdownRel :: String -> BS. ByteString -> XHtml. Html
112- renderMarkdownRel name md =
113- either (const $ XHtml. pre XHtml. << T. unpack txt) (XHtml. primHtml . T. unpack . sanitizeBalance . TL. toStrict . renderHHtml) $
114- runIdentity (commonmarkWith (mathSpec <> footnoteSpec <> defaultSyntaxSpec <> gfmExtensions)
106+ -- | Render markdown to HTML.
107+ renderMarkdown
108+ :: String -- ^ Name or path of input.
109+ -> BS. ByteString -- ^ Commonmark text input.
110+ -> XHtml. Html -- ^ Rendered HTML.
111+ renderMarkdown = renderMarkdown' (renderHtml :: Html () -> TL. Text )
112+
113+ -- | Render markdown to HTML, prefixing relative links with @src/@.
114+ renderMarkdownRel
115+ :: String -- ^ Name or path of input.
116+ -> BS. ByteString -- ^ Commonmark text input.
117+ -> XHtml. Html -- ^ Rendered HTML.
118+ renderMarkdownRel = renderMarkdown' (renderHtml . unHHtml :: HHtml () -> TL. Text )
119+
120+ -- | Prerequisites for 'commonmarkWith' with 'gfmExtensions' and 'mathSpec'.
121+ type MarkdownRenderable a =
122+ ( Typeable a
123+ , HasEmoji a
124+ , HasFootnote a a
125+ , HasMath a
126+ , HasPipeTable a a
127+ , HasStrikethrough a
128+ , HasTaskList a a
129+ , IsBlock a a
130+ , IsInline a
131+ , ToPlainText a
132+ )
133+
134+ -- | Generic gfm markdown rendering.
135+ renderMarkdown'
136+ :: MarkdownRenderable a
137+ => (a -> TL. Text ) -- ^ HTML rendering function.
138+ -> String -- ^ Name or path of input.
139+ -> BS. ByteString -- ^ Commonmark text input.
140+ -> XHtml. Html -- ^ Rendered HTML.
141+ renderMarkdown' render name md =
142+ either (const $ XHtml. pre XHtml. << T. unpack txt) (XHtml. primHtml . T. unpack . sanitizeBalance . TL. toStrict . render) $
143+ runIdentity (commonmarkWith (mathSpec <> gfmExtensions <> defaultSyntaxSpec)
115144 name
116145 txt)
117146 where txt = T. decodeUtf8With T. lenientDecode . BS. toStrict $ md
118147
148+ -- | Does the file extension suggest that the file is in markdown syntax?
119149supposedToBeMarkdown :: FilePath -> Bool
120150supposedToBeMarkdown fname = takeExtension fname `elem` [" .md" , " .markdown" ]
0 commit comments