@@ -1,10 +1,10 @@
11{-# LANGUAGE DeriveFunctor, ScopedTypeVariables #-}
2−{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
2+{-# OPTIONS_GHC -fwarn-incomplete-patterns -Werror #-}
33
44-- | Wrapper around Markdown library
55module Idris.Docstrings (
66 Docstring(..), Block(..), Inline(..), parseDocstring, renderDocstring, emptyDocstring, nullDocstring, noDocs,
7− overview, containsText, renderHtml, annotCode
7+ overview, containsText, renderHtml, annotCode, DocTerm(..), renderDocTerm, checkDocstring
88 ) where
99
1010import qualified Cheapskate as C
@@ -13,7 +13,7 @@ import Cheapskate.Html (renderDoc)
1313
1414import Util.Pretty
1515
16−import Idris.Core.TT (OutputAnnotation(..), TextFormatting(..), Name, Term)
16+import Idris.Core.TT (OutputAnnotation(..), TextFormatting(..), Name, Term, Err)
1717
1818import qualified Data.Text as T
1919import qualified Data.Foldable as F
@@ -25,6 +25,22 @@ import Control.DeepSeq (NFData(..))
2525
2626import Text.Blaze.Html (Html)
2727
28+-- | The various kinds of code samples that can be embedded in docs
29+data DocTerm = Unchecked
30+ | Checked Term
31+ | Example Term
32+ | Failing Err
33+ deriving Show
34+
35+-- | Render a term in the documentation
36+renderDocTerm :: (Term -> Doc OutputAnnotation) -> (Term -> Term) -> DocTerm -> String -> Doc OutputAnnotation
37+renderDocTerm pp norm Unchecked src = text src
38+renderDocTerm pp norm (Checked tm) src = pp tm
39+renderDocTerm pp norm (Example tm) src = align $
40+ text ">" <+> align (pp tm) <$>
41+ pp (norm tm)
42+renderDocTerm pp norm (Failing err) src = annotate (AnnErr err) $ text src
43+
2844-- | Representation of Idris's inline documentation. The type paramter
2945-- represents the type of terms that are associated with code blocks.
3046data Docstring a = DocString CT.Options (Blocks a)
@@ -58,6 +74,37 @@ data Inline a = Str T.Text
5874type Inlines a = S.Seq (Inline a)
5975
6076
77+-- | Run some kind of processing step over code in a Docstring. The code
78+-- processor gets the language and annotations as parameters, along with the
79+-- source and the original annotation.
80+checkDocstring :: forall a b. (String -> [String] -> String -> a -> b) -> Docstring a -> Docstring b
81+checkDocstring f (DocString opts blocks) = DocString opts (fmap (checkBlock f) blocks)
82+ where checkBlock :: (String -> [String] -> String -> a -> b) -> Block a -> Block b
83+ checkBlock f (Para inlines) = Para (fmap (checkInline f) inlines)
84+ checkBlock f (Header i inlines) = Header i (fmap (checkInline f) inlines)
85+ checkBlock f (Blockquote bs) = Blockquote (fmap (checkBlock f) bs)
86+ checkBlock f (List b t blocks) = List b t (fmap (fmap (checkBlock f)) blocks)
87+ checkBlock f (CodeBlock attrs src tm) = CodeBlock attrs src
88+ (f (T.unpack $ CT.codeLang attrs)
89+ (words . T.unpack $ CT.codeInfo attrs)
90+ (T.unpack src)
91+ tm)
92+ checkBlock f (HtmlBlock src) = HtmlBlock src
93+ checkBlock f HRule = HRule
94+
95+ checkInline :: (String -> [String] -> String -> a -> b) -> Inline a -> Inline b
96+ checkInline f (Str txt) = Str txt
97+ checkInline f Space = Space
98+ checkInline f SoftBreak = SoftBreak
99+ checkInline f LineBreak = LineBreak
100+ checkInline f (Emph is) = Emph (fmap (checkInline f) is)
101+ checkInline f (Strong is) = Strong (fmap (checkInline f) is)
102+ checkInline f (Code src x) = Code src (f "" [] (T.unpack src) x)
103+ checkInline f (Link is url title) = Link (fmap (checkInline f) is) url title
104+ checkInline f (Image is url title) = Image (fmap (checkInline f) is) url title
105+ checkInline f (Entity txt) = Entity txt
106+ checkInline f (RawHtml src) = RawHtml src
107+
61108-- | Construct a docstring from a Text that contains Markdown-formatted docs
62109parseDocstring :: T.Text -> Docstring ()
63110parseDocstring = toDocstring . C.markdown options
@@ -94,60 +141,53 @@ options = CT.Options { CT.sanitize = True
94141 }
95142
96143-- | Convert a docstring to be shown by the pretty-printer
97−renderDocstring :: (a -> Doc OutputAnnotation) -> (a -> a) -> Docstring (Maybe a) -> Doc OutputAnnotation
98−renderDocstring pp norm (DocString _ blocks) = renderBlocks pp norm blocks
144+renderDocstring :: (a -> String -> Doc OutputAnnotation) -> Docstring a -> Doc OutputAnnotation
145+renderDocstring pp (DocString _ blocks) = renderBlocks pp blocks
99146
100147-- | Construct a docstring consisting of the first block-level element of the
101148-- argument docstring, for use in summaries.
102149overview :: Docstring a -> Docstring a
103150overview (DocString opts blocks) = DocString opts (S.take 1 blocks)
104151
105−renderBlocks :: (a -> Doc OutputAnnotation) -> (a -> a)
106− -> Blocks (Maybe a) -> Doc OutputAnnotation
107−renderBlocks pp norm blocks | S.length blocks > 1 = F.foldr1 (\b1 b2 -> b1 <> line <> line <> b2) $
108− fmap (renderBlock pp norm) blocks
109− | S.length blocks == 1 = renderBlock pp norm (S.index blocks 0)
152+renderBlocks :: (a -> String -> Doc OutputAnnotation)
153+ -> Blocks a -> Doc OutputAnnotation
154+renderBlocks pp blocks | S.length blocks > 1 = F.foldr1 (\b1 b2 -> b1 <> line <> line <> b2) $
155+ fmap (renderBlock pp) blocks
156+ | S.length blocks == 1 = renderBlock pp (S.index blocks 0)
110157 | otherwise = empty
111158
112−renderBlock :: (a -> Doc OutputAnnotation) -> (a -> a)
113− -> Block (Maybe a) -> Doc OutputAnnotation
114−renderBlock pp norm (Para inlines) = renderInlines pp inlines
115−renderBlock pp norm (Header lvl inlines) = renderInlines pp inlines <+> parens (text (show lvl))
116−renderBlock pp norm (Blockquote blocks) = indent 8 $ renderBlocks pp norm blocks
117−renderBlock pp norm (List b ty blockss) = renderList pp norm b ty blockss
118−renderBlock pp norm (CodeBlock attr src Nothing) = indent 8 $ text (T.unpack src)
119−renderBlock pp norm (CodeBlock attr src (Just tm))
120− | isExample attr = indent 4 $
121− text ">" <+> align (group (pp tm)) <$>
122− align (group (pp (norm tm)))
123− | otherwise = indent 4 $ pp tm
124− where isExample (CT.CodeAttr lang info) = T.pack "example" `elem` lang : T.words info
125−renderBlock pp norm (HtmlBlock txt) = text "<html block>" -- TODO
126−renderBlock pp norm HRule = text "----------------------"
127−
128−renderList :: (a -> Doc OutputAnnotation) -> (a -> a)
129− -> Bool -> CT.ListType -> [Blocks (Maybe a)] -> Doc OutputAnnotation
130−renderList pp norm b (CT.Bullet c) blockss = vsep $ map (hang 4 . (char c <+>) . renderBlocks pp norm) blockss
131−renderList pp norm b (CT.Numbered nw i) blockss =
159+renderBlock :: (a -> String -> Doc OutputAnnotation)
160+ -> Block a -> Doc OutputAnnotation
161+renderBlock pp (Para inlines) = renderInlines pp inlines
162+renderBlock pp (Header lvl inlines) = renderInlines pp inlines <+> parens (text (show lvl))
163+renderBlock pp (Blockquote blocks) = indent 8 $ renderBlocks pp blocks
164+renderBlock pp (List b ty blockss) = renderList pp b ty blockss
165+renderBlock pp (CodeBlock attr src tm) = indent 4 $ pp tm (T.unpack src)
166+renderBlock pp (HtmlBlock txt) = text "<html block>" -- TODO
167+renderBlock pp HRule = text "----------------------"
168+
169+renderList :: (a -> String -> Doc OutputAnnotation)
170+ -> Bool -> CT.ListType -> [Blocks a] -> Doc OutputAnnotation
171+renderList pp b (CT.Bullet c) blockss = vsep $ map (hang 4 . (char c <+>) . renderBlocks pp) blockss
172+renderList pp b (CT.Numbered nw i) blockss =
132173 vsep $
133174 zipWith3 (\n p txt -> hang 4 $ text (show n) <> p <+> txt)
134− [i..] (repeat punc) (map (renderBlocks pp norm) blockss)
175+ [i..] (repeat punc) (map (renderBlocks pp) blockss)
135176 where punc = case nw of
136177 CT.PeriodFollowing -> char '.'
137178 CT.ParenFollowing -> char '('
138179
139−renderInlines :: (a -> Doc OutputAnnotation) -> Inlines (Maybe a) -> Doc OutputAnnotation
180+renderInlines :: (a -> String -> Doc OutputAnnotation) -> Inlines a -> Doc OutputAnnotation
140181renderInlines pp = F.foldr (<>) empty . fmap (renderInline pp)
141182
142−renderInline :: (a -> Doc OutputAnnotation) -> Inline (Maybe a) -> Doc OutputAnnotation
183+renderInline :: (a -> String -> Doc OutputAnnotation) -> Inline a -> Doc OutputAnnotation
143184renderInline pp (Str s) = text $ T.unpack s
144185renderInline pp Space = softline
145186renderInline pp SoftBreak = softline
146187renderInline pp LineBreak = line
147188renderInline pp (Emph txt) = annotate (AnnTextFmt ItalicText) $ renderInlines pp txt
148189renderInline pp (Strong txt) = annotate (AnnTextFmt BoldText) $ renderInlines pp txt
149−renderInline pp (Code txt Nothing) = text $ T.unpack txt
150−renderInline pp (Code txt (Just tm)) = pp tm
190+renderInline pp (Code txt tm) = pp tm $ T.unpack txt
151191renderInline pp (Link body url title) = annotate (AnnTextFmt UnderlineText) (renderInlines pp body) <+>
152192 parens (text $ T.unpack url)
153193renderInline pp (Image body url title) = text "<image>" -- TODO
@@ -193,13 +233,13 @@ containsText str (DocString _ blocks) = F.any (blockContains (T.toLower str)) bl
193233 inlineContains str (RawHtml txt) = T.isInfixOf str (T.toLower txt)
194234
195235
196−renderHtml :: Docstring (Maybe Term) -> Html
236+renderHtml :: Docstring DocTerm -> Html
197237renderHtml = renderDoc . fromDocstring
198238 where
199− fromDocstring :: Docstring (Maybe Term) -> CT.Doc
239+ fromDocstring :: Docstring DocTerm -> CT.Doc
200240 fromDocstring (DocString opts blocks) = CT.Doc opts (fmap fromBlock blocks)
201241
202− fromBlock :: Block (Maybe Term) -> CT.Block
242+ fromBlock :: Block DocTerm -> CT.Block
203243 fromBlock (Para inlines) = CT.Para (fmap fromInline inlines)
204244 fromBlock (Header i inlines) = CT.Header i (fmap fromInline inlines)
205245 fromBlock (Blockquote blocks) = CT.Blockquote (fmap fromBlock blocks)
@@ -208,7 +248,7 @@ renderHtml = renderDoc . fromDocstring
208248 fromBlock (HtmlBlock src) = CT.HtmlBlock src
209249 fromBlock HRule = CT.HRule
210250
211− fromInline :: Inline (Maybe Term) -> CT.Inline
251+ fromInline :: Inline DocTerm -> CT.Inline
212252 fromInline (Str t) = CT.Str t
213253 fromInline Space = CT.Space
214254 fromInline SoftBreak = CT.SoftBreak