2Module : Idris.Docstrings
3Description : Wrapper around Markdown library.
6Maintainer : The Idris Community.
9{-# LANGUAGE DeriveFunctor, DeriveGeneric, ScopedTypeVariables #-}
10{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
11module Idris.Docstrings (
12 Docstring(..), Block(..), Inline(..), parseDocstring, renderDocstring
13 , emptyDocstring, nullDocstring, noDocs, overview, containsText
14 , renderHtml, annotCode, DocTerm(..), renderDocTerm, checkDocstring
17import Idris.Core.TT (Err, Name, OutputAnnotation(..), Term, TextFormatting(..))
21import Prelude hiding ((<$>))
23import qualified Cheapskate as C
24import Cheapskate.Html (renderDoc)
25import qualified Cheapskate.Types as CT
26import Data.Foldable (Foldable)
27import qualified Data.Foldable as F
28import qualified Data.Sequence as S
29import qualified Data.Text as T
30import Data.Traversable (Traversable)
31import GHC.Generics (Generic)
32import Text.Blaze.Html (Html)
34-- | The various kinds of code samples that can be embedded in docs
35data DocTerm = Unchecked
39 deriving (Show, Generic)
41-- | Render a term in the documentation
42renderDocTerm :: (Term -> Doc OutputAnnotation) -> (Term -> Term) -> DocTerm -> String -> Doc OutputAnnotation
43renderDocTerm pp norm Unchecked src = text src
44renderDocTerm pp norm (Checked tm) src = pp tm
45renderDocTerm pp norm (Example tm) src = align $
46 text ">" <+> align (pp tm) <$>
48renderDocTerm pp norm (Failing err) src = annotate (AnnErr err) $ text src
50-- | Representation of Idris's inline documentation. The type paramter
51-- represents the type of terms that are associated with code blocks.
52data Docstring a = DocString CT.Options (Blocks a)
53 deriving (Show, Functor, Foldable, Traversable, Generic)
55type Blocks a = S.Seq (Block a)
57-- | Block-level elements.
58data Block a = Para (Inlines a)
59 | Header Int (Inlines a)
60 | Blockquote (Blocks a)
61 | List Bool CT.ListType [Blocks a]
62 | CodeBlock CT.CodeAttr T.Text a
65 deriving (Show, Functor, Foldable, Traversable, Generic)
67data Inline a = Str T.Text
74 | Link (Inlines a) T.Text T.Text
75 | Image (Inlines a) T.Text T.Text
78 deriving (Show, Functor, Foldable, Traversable, Generic)
80type Inlines a = S.Seq (Inline a)
83-- | Run some kind of processing step over code in a Docstring. The code
84-- processor gets the language and annotations as parameters, along with the
85-- source and the original annotation.
86checkDocstring :: forall a b. (String -> [String] -> String -> a -> b) -> Docstring a -> Docstring b
87checkDocstring f (DocString opts blocks) = DocString opts (fmap (checkBlock f) blocks)
88 where checkBlock :: (String -> [String] -> String -> a -> b) -> Block a -> Block b
89 checkBlock f (Para inlines) = Para (fmap (checkInline f) inlines)
90 checkBlock f (Header i inlines) = Header i (fmap (checkInline f) inlines)
91 checkBlock f (Blockquote bs) = Blockquote (fmap (checkBlock f) bs)
92 checkBlock f (List b t blocks) = List b t (fmap (fmap (checkBlock f)) blocks)
93 checkBlock f (CodeBlock attrs src tm) = CodeBlock attrs src
94 (f (T.unpack $ CT.codeLang attrs)
95 (words . T.unpack $ CT.codeInfo attrs)
98 checkBlock f (HtmlBlock src) = HtmlBlock src
99 checkBlock f HRule = HRule
101 checkInline :: (String -> [String] -> String -> a -> b) -> Inline a -> Inline b
102 checkInline f (Str txt) = Str txt
103 checkInline f Space = Space
104 checkInline f SoftBreak = SoftBreak
105 checkInline f LineBreak = LineBreak
106 checkInline f (Emph is) = Emph (fmap (checkInline f) is)
107 checkInline f (Strong is) = Strong (fmap (checkInline f) is)
108 checkInline f (Code src x) = Code src (f "" [] (T.unpack src) x)
109 checkInline f (Link is url title) = Link (fmap (checkInline f) is) url title
110 checkInline f (Image is url title) = Image (fmap (checkInline f) is) url title
111 checkInline f (Entity txt) = Entity txt
112 checkInline f (RawHtml src) = RawHtml src
114-- | Construct a docstring from a Text that contains Markdown-formatted docs
115parseDocstring :: T.Text -> Docstring ()
116parseDocstring = toDocstring . C.markdown options
117 where toDocstring :: CT.Doc -> Docstring ()
118 toDocstring (CT.Doc opts blocks) = DocString opts (fmap toBlock blocks)
120 toBlock :: CT.Block -> Block ()
121 toBlock (CT.Para inlines) = Para (fmap toInline inlines)
122 toBlock (CT.Header i inlines) = Header i (fmap toInline inlines)
123 toBlock (CT.Blockquote blocks) = Blockquote (fmap toBlock blocks)
124 toBlock (CT.List b t blocks) = List b t (fmap (fmap toBlock) blocks)
125 toBlock (CT.CodeBlock attrs text) = CodeBlock attrs text ()
126 toBlock (CT.HtmlBlock src) = HtmlBlock src
127 toBlock CT.HRule = HRule
129 toInline :: CT.Inline -> Inline ()
130 toInline (CT.Str t) = Str t
131 toInline CT.Space = Space
132 toInline CT.SoftBreak = SoftBreak
133 toInline CT.LineBreak = LineBreak
134 toInline (CT.Emph is) = Emph (fmap toInline is)
135 toInline (CT.Strong is) = Strong (fmap toInline is)
136 toInline (CT.Code src) = Code src ()
137 toInline (CT.Link is url title) = Link (fmap toInline is) url title
138 toInline (CT.Image is url title) = Image (fmap toInline is) url title
139 toInline (CT.Entity txt) = Entity txt
140 toInline (CT.RawHtml src) = RawHtml src
143options = CT.Options { CT.sanitize = True
144 , CT.allowRawHtml = False
145 , CT.preserveHardBreaks = True
149-- | Convert a docstring to be shown by the pretty-printer
150renderDocstring :: (a -> String -> Doc OutputAnnotation) -> Docstring a -> Doc OutputAnnotation
151renderDocstring pp (DocString _ blocks) = renderBlocks pp blocks
153-- | Construct a docstring consisting of the first block-level element of the
154-- argument docstring, for use in summaries.
155overview :: Docstring a -> Docstring a
156overview (DocString opts blocks) = DocString opts (S.take 1 blocks)
158renderBlocks :: (a -> String -> Doc OutputAnnotation)
159 -> Blocks a -> Doc OutputAnnotation
160renderBlocks pp blocks | S.length blocks > 1 = F.foldr1 (\b1 b2 -> b1 <> line <> line <> b2) $
161 fmap (renderBlock pp) blocks
162 | S.length blocks == 1 = renderBlock pp (S.index blocks 0)
165renderBlock :: (a -> String -> Doc OutputAnnotation)
166 -> Block a -> Doc OutputAnnotation
167renderBlock pp (Para inlines) = renderInlines pp inlines
168renderBlock pp (Header lvl inlines) = renderInlines pp inlines <+> parens (text (show lvl))
169renderBlock pp (Blockquote blocks) = indent 8 $ renderBlocks pp blocks
170renderBlock pp (List b ty blockss) = renderList pp b ty blockss
171renderBlock pp (CodeBlock attr src tm) = indent 4 $ pp tm (T.unpack src)
172renderBlock pp (HtmlBlock txt) = text "<html block>" -- TODO
173renderBlock pp HRule = text "----------------------"
175renderList :: (a -> String -> Doc OutputAnnotation)
176 -> Bool -> CT.ListType -> [Blocks a] -> Doc OutputAnnotation
177renderList pp b (CT.Bullet c) blockss = vsep $ map (hang 4 . (char c <+>) . renderBlocks pp) blockss
178renderList pp b (CT.Numbered nw i) blockss =
180 zipWith3 (\n p txt -> hang 4 $ text (show n) <> p <+> txt)
181 [i..] (repeat punc) (map (renderBlocks pp) blockss)
182 where punc = case nw of
183 CT.PeriodFollowing -> char '.'
184 CT.ParenFollowing -> char '('
186renderInlines :: (a -> String -> Doc OutputAnnotation) -> Inlines a -> Doc OutputAnnotation
187renderInlines pp = F.foldr (<>) empty . fmap (renderInline pp)
189renderInline :: (a -> String -> Doc OutputAnnotation) -> Inline a -> Doc OutputAnnotation
190renderInline pp (Str s) = text $ T.unpack s
191renderInline pp Space = softline
192renderInline pp SoftBreak = softline
193renderInline pp LineBreak = line
194renderInline pp (Emph txt) = annotate (AnnTextFmt ItalicText) $ renderInlines pp txt
195renderInline pp (Strong txt) = annotate (AnnTextFmt BoldText) $ renderInlines pp txt
196renderInline pp (Code txt tm) = pp tm $ T.unpack txt
197renderInline pp (Link body url title) = annotate (AnnLink (T.unpack url)) (renderInlines pp body)
198renderInline pp (Image body url title) = text "<image>" -- TODO
199renderInline pp (Entity a) = text $ "<entity " ++ T.unpack a ++ ">" -- TODO
200renderInline pp (RawHtml txt) = text "<html content>" --TODO
202-- | The empty docstring
203emptyDocstring :: Docstring a
204emptyDocstring = DocString options S.empty
206-- | Check whether a docstring is emtpy
207nullDocstring :: Docstring a -> Bool
208nullDocstring (DocString _ blocks) = S.null blocks
210-- | Empty documentation for a definition
211noDocs :: (Docstring a, [(Name, Docstring a)])
212noDocs = (emptyDocstring, [])
214-- | Does a string occur in the docstring?
215containsText :: T.Text -> Docstring a -> Bool
216containsText str (DocString _ blocks) = F.any (blockContains (T.toLower str)) blocks
217 -- blockContains and inlineContains should always be called with a lower-case search string
218 where blockContains :: T.Text -> Block a -> Bool
219 blockContains str (Para inlines) = F.any (inlineContains str) inlines
220 blockContains str (Header lvl inlines) = F.any (inlineContains str) inlines
221 blockContains str (Blockquote blocks) = F.any (blockContains str) blocks
222 blockContains str (List b ty blockss) = F.any (F.any (blockContains str)) blockss
223 blockContains str (CodeBlock attr src _) = T.isInfixOf str (T.toLower src)
224 blockContains str (HtmlBlock txt) = False -- TODO
225 blockContains str HRule = False
227 inlineContains :: T.Text -> Inline a -> Bool
228 inlineContains str (Str s) = T.isInfixOf str (T.toLower s)
229 inlineContains str Space = False
230 inlineContains str SoftBreak = False
231 inlineContains str LineBreak = False
232 inlineContains str (Emph txt) = F.any (inlineContains str) txt
233 inlineContains str (Strong txt) = F.any (inlineContains str) txt
234 inlineContains str (Code txt _) = T.isInfixOf str (T.toLower txt)
235 inlineContains str (Link body url title) = F.any (inlineContains str) body
236 inlineContains str (Image body url title) = False
237 inlineContains str (Entity a) = False
238 inlineContains str (RawHtml txt) = T.isInfixOf str (T.toLower txt)
241renderHtml :: Docstring DocTerm -> Html
242renderHtml = renderDoc . fromDocstring
244 fromDocstring :: Docstring DocTerm -> CT.Doc
245 fromDocstring (DocString opts blocks) = CT.Doc opts (fmap fromBlock blocks)
247 fromBlock :: Block DocTerm -> CT.Block
248 fromBlock (Para inlines) = CT.Para (fmap fromInline inlines)
249 fromBlock (Header i inlines) = CT.Header i (fmap fromInline inlines)
250 fromBlock (Blockquote blocks) = CT.Blockquote (fmap fromBlock blocks)
251 fromBlock (List b t blocks) = CT.List b t (fmap (fmap fromBlock) blocks)
252 fromBlock (CodeBlock attrs text _) = CT.CodeBlock attrs text
253 fromBlock (HtmlBlock src) = CT.HtmlBlock src
254 fromBlock HRule = CT.HRule
256 fromInline :: Inline DocTerm -> CT.Inline
257 fromInline (Str t) = CT.Str t
258 fromInline Space = CT.Space
259 fromInline SoftBreak = CT.SoftBreak
260 fromInline LineBreak = CT.LineBreak
261 fromInline (Emph is) = CT.Emph (fmap fromInline is)
262 fromInline (Strong is) = CT.Strong (fmap fromInline is)
263 fromInline (Code src _) = CT.Code src
264 fromInline (Link is url title) = CT.Link (fmap fromInline is) url title
265 fromInline (Image is url title) = CT.Image (fmap fromInline is) url title
266 fromInline (Entity txt) = CT.Entity txt
267 fromInline (RawHtml src) = CT.RawHtml src
270-- | Annotate the code samples in a docstring
271annotCode :: forall a b. (String -> b) -- ^ How to annotate code samples
274annotCode annot (DocString opts blocks)
275 = DocString opts $ fmap annotCodeBlock blocks
277 annotCodeBlock :: Block a -> Block b
278 annotCodeBlock (Para inlines) = Para (fmap annotCodeInline inlines)
279 annotCodeBlock (Header i inlines) = Header i (fmap annotCodeInline inlines)
280 annotCodeBlock (Blockquote blocks) = Blockquote (fmap annotCodeBlock blocks)
281 annotCodeBlock (List b t blocks) = List b t (fmap (fmap annotCodeBlock) blocks)
282 annotCodeBlock (CodeBlock attrs src _) = CodeBlock attrs src (annot (T.unpack src))
283 annotCodeBlock (HtmlBlock src) = HtmlBlock src
284 annotCodeBlock HRule = HRule
286 annotCodeInline :: Inline a -> Inline b
287 annotCodeInline (Str t) = Str t
288 annotCodeInline Space = Space
289 annotCodeInline SoftBreak = SoftBreak
290 annotCodeInline LineBreak = LineBreak
291 annotCodeInline (Emph is) = Emph (fmap annotCodeInline is)
292 annotCodeInline (Strong is) = Strong (fmap annotCodeInline is)
293 annotCodeInline (Code src _) = Code src (annot (T.unpack src))
294 annotCodeInline (Link is url title) = Link (fmap annotCodeInline is) url title
295 annotCodeInline (Image is url title) = Image (fmap annotCodeInline is) url title
296 annotCodeInline (Entity txt) = Entity txt
297 annotCodeInline (RawHtml src) = RawHtml src
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list