on master help sign in
Merge pull request #1085 from david-christiansen/PhilipRasmussen-idrisdoc

Fix merge conflicts from IdrisDoc

commit7d2e18f682c61345b19c879544ff3091391c6ca8 authorEdwin Brady <edwin.brady@gmail.com> dateSun 20 Apr 2014, 16:37 (13 years ago) parentd8a6925cfbb64f
10 files changed+1080−13
idris.cabal+5−1 idrisdoc/styles.css+320 main/Main.hs+5 src/Idris/AbsSyntaxTree.hs+10−7 src/Idris/Core/TT.hs+2−2 src/Idris/Help.hs+3 src/Idris/IdrisDoc.hs+672 src/Idris/REPL.hs+22 src/Idris/REPLParser.hs+1 src/Pkg/Package.hs+40−3
idris.cabal+5−1
@@ -46,7 +46,8 @@ Cabal-Version: >= 1.8
4646
4747Build-type: Custom
4848
49−Data-files: jsrts/Runtime-browser.js
49+Data-files: idrisdoc/styles.css
50+ jsrts/Runtime-browser.js
5051 jsrts/Runtime-common.js
5152 jsrts/Runtime-node.js
5253 jsrts/jsbn/jsbn.js
@@ -486,6 +487,7 @@ Library
486487 , Idris.Help
487488 , Idris.IBC
488489 , Idris.IdeSlave
490+ , Idris.IdrisDoc
489491 , Idris.Imports
490492 , Idris.Inliner
491493 , Idris.Output
@@ -545,6 +547,8 @@ Library
545547 , ansi-terminal
546548 , ansi-wl-pprint
547549 , binary
550+ , blaze-html >= 0.6.1.3
551+ , blaze-markup >= 0.5.2.1 && < 0.6.0.0
548552 , bytestring
549553 , cheapskate
550554 , containers >= 0.5
idrisdoc/styles.cssnew file+320
@@ -0,0 +1,320 @@
1+html, body {
2+
3+ margin: 0;
4+ padding: 0;
5+ border: 0;
6+
7+ height: 100%;
8+
9+ font-family: "Trebuchet MS", Helvetica, sans-serif;
10+ font-size: 11pt;
11+
12+ background-color: #FFF;
13+}
14+
15+a, a:active, a:visited {
16+
17+ text-decoration: none;
18+ color: inherit;
19+}
20+
21+a:hover {
22+
23+ text-decoration: underline;
24+}
25+
26+header {
27+
28+ padding: 5px 11px;
29+
30+ border-bottom: 3px solid #659FDB;
31+ box-shadow: 0 -8px 22px 0px;
32+
33+ background-color: #252525;
34+ color: white;
35+
36+ font-size: 9pt;
37+}
38+
39+.wrapper {
40+
41+ min-height: 100%;
42+}
43+
44+header nav, header strong {
45+
46+ font-size: 11pt;
47+}
48+
49+header nav {
50+
51+ float: right;
52+}
53+
54+footer {
55+
56+ height: 30px;
57+ width: 100%;
58+ border-top: 1px solid #AAAAAA;
59+
60+ margin-top: -31px;
61+
62+ text-align: center;
63+ color: #666;
64+ line-height: 30px;
65+ font-size: 9pt;
66+
67+ background: none repeat scroll 0 0 #DDDDDD;
68+}
69+
70+.container {
71+
72+ padding: 10px 10px 41px 20px;
73+}
74+
75+body.index .container a:visited {
76+
77+ color: #666;
78+}
79+
80+body.index .container a:hover {
81+
82+ color: #04819E;
83+}
84+
85+h1 {
86+
87+ margin: 0;
88+ margin-bottom: 5px;
89+ font-size: 14pt;
90+
91+ font-family: "Trebuchet MS", Helvetica, sans-serif;
92+}
93+
94+body.namespace h1 {
95+
96+ border-bottom: 1px solid #BBB;
97+ padding-bottom: 2px;
98+}
99+
100+ul {
101+
102+ list-style-type: none;
103+
104+ margin: 0;
105+ padding: 0;
106+}
107+
108+hr {
109+
110+ margin: 0;
111+ padding: 0;
112+ border: 0;
113+
114+ border-bottom: 1px solid #BBB;
115+}
116+
117+p {
118+
119+ margin: 0;
120+ padding: 0;
121+}
122+
123+.code {
124+
125+ font-family: "Lucida Console", Monaco, monospace;
126+ font-size: 10pt;
127+}
128+
129+.decls {
130+
131+ margin-top: 15px;
132+}
133+
134+.decls > dt {
135+
136+ font-family: "Lucida Console", Monaco, monospace;
137+ font-size: 10pt;
138+ line-height: 20px;
139+
140+ padding: 2px 0;
141+
142+ border: 1px solid #CCC;
143+ background-color: #F0F0F0;
144+
145+ display: table;
146+ width: 100%;
147+}
148+
149+.decls > dt > :first-child {
150+
151+ padding-left: 6px;
152+}
153+
154+.decls > dt > :last-child {
155+
156+ padding-right: 6px;
157+}
158+
159+.decls > dd {
160+
161+ margin: 10px 0 10px 20px;
162+
163+ font-family: Arial, sans-serif;
164+ font-size: 10pt;
165+}
166+
167+.decls > dd > p {
168+
169+ margin-bottom: 8px;
170+}
171+
172+.decls > dd > dl:not(.decls):not(:first-child) {
173+
174+ padding-top: 5px;
175+ border-top: 1px solid #EEE;
176+}
177+
178+.decls > dd > dl:not(.decls) > dt {
179+
180+ display: block;
181+ min-width: 70px;
182+
183+ float: left;
184+
185+ font-weight: bold;
186+}
187+
188+.decls > dd > dl:not(.decls) > dd {
189+
190+ margin-bottom: 2px;
191+}
192+
193+.fixity {
194+
195+ font-style: italic;
196+ font-weight: normal !important;
197+}
198+
199+dd.fixity {
200+
201+ cursor: default;
202+}
203+
204+.word {
205+
206+ display: table-cell;
207+ white-space: nowrap;
208+ width: 0;
209+}
210+
211+.signature {
212+
213+ display: table-cell;
214+ width: 100%;
215+}
216+
217+.name {
218+
219+ display: table-cell;
220+ white-space: nowrap;
221+ width: 0;
222+}
223+
224+.documented, .name {
225+
226+ cursor: default;
227+}
228+
229+.documented {
230+
231+ font-weight: bold;
232+}
233+
234+a.function {
235+
236+ color: #00BA00;
237+}
238+
239+.function {
240+
241+ color: #007C21;
242+}
243+
244+a.constructor {
245+
246+ color: #FF0000;
247+}
248+
249+.constructor {
250+
251+ color: #BF3030;
252+}
253+
254+a.type {
255+
256+ color: #0000FF;
257+}
258+
259+.type {
260+
261+ color: #050599;
262+}
263+
264+.keyword {
265+
266+ color: inherit;
267+}
268+
269+.boundvar {
270+
271+ color: #BF30BF; /* Too much colour makes it hard to differ the rest of the colours */
272+ color: inherit;
273+}
274+
275+.boundvar.implicit {
276+
277+ text-decoration: underline;
278+}
279+
280+/******************* Old colours
281+
282+a {
283+
284+ color: #04819E;
285+}
286+
287+a:visited {
288+
289+ color: #26A3BF;
290+}
291+
292+********************/
293+
294+ul.names {
295+
296+ border: 1px solid #666;
297+}
298+
299+ul.names li:nth-child(odd) {
300+
301+ background-color: #EEEEEF;
302+}
303+
304+ul.names li:nth-child(even) {
305+
306+ background-color: white;
307+}
308+
309+ul.names li {
310+
311+ padding-left: 5px;
312+}
313+
314+ul.names li a {
315+
316+ display: inline-block;
317+ width: 100%;
318+
319+ padding: 2px 0;
320+}
main/Main.hs+5
@@ -61,6 +61,10 @@ runIdris opts = do
6161 [] -> return ()
6262 fs -> do runIO $ mapM_ cleanPkg fs
6363 runIO $ exitWith ExitSuccess
64+ case opt getPkgMkDoc opts of -- IdrisDoc
65+ [] -> return ()
66+ fs -> do runIO $ mapM_ documentPkg fs
67+ runIO $ exitWith ExitSuccess
6468 case opt getPkg opts of
6569 [] -> case opt getPkgREPL opts of
6670 [] -> idrisMain opts
@@ -95,6 +99,7 @@ usagemsg = usagemsghdr ++ "\n" ++
9599 "\t --install IPKG Install package\n" ++
96100 "\t --clean IPKG Clean package\n" ++
97101 "\t --build IPKG Build package\n" ++
102+ "\t --mkdoc IPKG Generate IdrisDoc for package\n" ++
98103 "\t --exec EXPR Execute as idris\n" ++
99104 "\t --libdir Display library directory\n" ++
100105 "\t --link Display link directory\n" ++
src/Idris/AbsSyntaxTree.hs+10−7
@@ -311,6 +311,8 @@ data Command = Quit
311311 | Apropos String
312312 | WhoCalls Name
313313 | CallsWho Name
314+ | MakeDoc String -- IdrisDoc
315+
314316
315317data Opt = Filename String
316318 | Ver
@@ -345,6 +347,7 @@ data Opt = Filename String
345347 | PkgClean String
346348 | PkgCheck String
347349 | PkgREPL String
350+ | PkgMkDoc String -- IdrisDoc
348351 | WarnOnly
349352 | Pkg String
350353 | BCAsm String
@@ -638,26 +641,26 @@ data PTerm = PQuote Raw
638641 | PInferRef FC Name -- ^ A name to be defined later
639642 | PPatvar FC Name
640643 | PLam Name PTerm PTerm
641− | PPi Plicity Name PTerm PTerm
644+ | PPi Plicity Name PTerm PTerm -- ^ (n : t1) -> t2
642645 | PLet Name PTerm PTerm PTerm
643646 | PTyped PTerm PTerm -- ^ Term with explicit type
644− | PApp FC PTerm [PArg]
647+ | PApp FC PTerm [PArg] -- ^ e.g. IO (), List Char, length x
645648 | PAppBind FC PTerm [PArg] -- ^ implicitly bound application
646649 | PMatchApp FC Name -- ^ Make an application by type matching
647650 | PCase FC PTerm [(PTerm, PTerm)]
648− | PTrue FC PunInfo
649− | PFalse FC
651+ | PTrue FC PunInfo -- ^ Unit type..?
652+ | PFalse FC -- ^ _|_
650653 | PRefl FC PTerm
651654 | PResolveTC FC
652− | PEq FC PTerm PTerm
655+ | PEq FC PTerm PTerm -- ^ Equality type: A = B
653656 | PRewrite FC PTerm PTerm (Maybe PTerm)
654657 | PPair FC PunInfo PTerm PTerm
655658 | PDPair FC PunInfo PTerm PTerm PTerm
656659 | PAlternative Bool [PTerm] -- True if only one may work
657660 | PHidden PTerm -- ^ Irrelevant or hidden pattern
658− | PType
661+ | PType -- ^ 'Type' type
659662 | PGoal FC PTerm Name PTerm
660− | PConstant Const
663+ | PConstant Const -- ^ Builtin types
661664 | Placeholder
662665 | PDoBlock [PDo]
663666 | PIdiom FC PTerm
src/Idris/Core/TT.hs+2−2
@@ -256,7 +256,7 @@ traceWhen False _ a = a
256256data Name = UN T.Text -- ^ User-provided name
257257 | NS Name [T.Text] -- ^ Root, namespaces
258258 | MN Int T.Text -- ^ Machine chosen names
259− | NErased -- ^ Name of somethng which is never used in scope
259+ | NErased -- ^ Name of something which is never used in scope
260260 | SN SpecialName -- ^ Decorated function names
261261 | SymRef Int -- ^ Reference to IBC file symbol table (used during serialisation)
262262 deriving (Eq, Ord)
@@ -433,7 +433,7 @@ updateDef n f ctxt
433433
434434toAlist :: Ctxt a -> [(Name, a)]
435435toAlist ctxt = let allns = map snd (Map.toList ctxt) in
436− concat (map (Map.toList) allns)
436+ concatMap (Map.toList) allns
437437
438438addAlist :: Show a => [(Name, a)] -> Ctxt a -> Ctxt a
439439addAlist [] ctxt = ctxt
src/Idris/Help.hs+3
@@ -4,6 +4,7 @@ data CmdArg = ExprArg -- ^ The command takes an expression
44 | NameArg -- ^ The command takes a name
55 | FileArg -- ^ The command takes a file
66 | ModuleArg -- ^ The command takes a module name
7+ | NamespaceArg -- ^ The command takes a namespace name
78 | OptionArg -- ^ The command takes an option
89 | MetaVarArg -- ^ The command takes a metavariable
910 | ColourArg -- ^ The command is the colour-setting command
@@ -16,6 +17,7 @@ instance Show CmdArg where
1617 show NameArg = "<name>"
1718 show FileArg = "<filename>"
1819 show ModuleArg = "<module>"
20+ show NamespaceArg = "<namespace>"
1921 show OptionArg = "<option>"
2022 show MetaVarArg = "<metavar>"
2123 show ColourArg = "<option>"
@@ -29,6 +31,7 @@ help =
2931 ([":t"], ExprArg, "Check the type of an expression"),
3032 ([":miss", ":missing"], NameArg, "Show missing clauses"),
3133 ([":doc"], NameArg, "Show internal documentation"),
34+ ([":mkdoc"], NamespaceArg, "Generate IdrisDoc for namespace(s) and dependencies"),
3235 ([":apropos"], NoArg, "Search names, types, and documentation"),
3336 ([":whocalls", ":wc"], NameArg, "List the callers of some name"),
3437 ([":callswho", ":cw"], NameArg, "List the callees of some name"),
src/Idris/IdrisDoc.hsnew file+672
@@ -0,0 +1,672 @@
1+{-# LANGUAGE PatternGuards #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+
4+-- | Generation of HTML documentation for Idris code
5+module Idris.IdrisDoc (generateDocs) where
6+
7+import Idris.Core.TT (Name (..), sUN, SpecialName (..), OutputAnnotation (..),
8+ TextFormatting (..), txt, str, nsroot)
9+import Idris.Core.Evaluate (ctxtAlist, Def (..), lookupDefAcc,
10+ Accessibility (..), isDConName, isFnName,
11+ isTConName)
12+import Idris.ParseHelpers (opChars)
13+import Idris.AbsSyntax
14+import Idris.Docs
15+import Idris.Docstrings (nullDocstring)
16+
17+import Paths_idris (getDataFileName)
18+
19+import Control.Monad (forM_)
20+import Control.Monad.Trans.Error
21+import Control.Monad.Trans.State.Strict
22+
23+import Data.Maybe
24+
25+import qualified Data.ByteString as BS
26+import qualified Data.ByteString.Lazy as BS2
27+import qualified Data.Text.Encoding as E
28+import qualified Data.List as L
29+import qualified Data.List.Split as LS
30+import qualified Data.Map as M hiding ((!))
31+import qualified Data.Ord (compare)
32+import qualified Data.Set as S
33+import qualified Data.Text as T
34+
35+import System.IO
36+import System.IO.Error
37+import System.FilePath
38+import System.Directory
39+
40+import Cheapskate.Html (renderDoc)
41+import Text.PrettyPrint.Annotated.Leijen (displayDecorated, renderCompact)
42+
43+import Text.Blaze (toValue, contents)
44+import Text.Blaze.Internal (MarkupM (Empty))
45+import Text.Blaze.Html5 ((!), toHtml, preEscapedToHtml)
46+import qualified Text.Blaze.Html5 as H
47+import Text.Blaze.Html5.Attributes as A
48+import Text.Blaze.Html.Renderer.Utf8 (renderHtml)
49+import qualified Text.Blaze.Html.Renderer.String as R
50+import Text.Blaze.Renderer.String (renderMarkup)
51+
52+-- ---------------------------------------------------------------- [ Public ]
53+
54+-- | Generates HTML documentation for a series of loaded namespaces
55+-- and their dependencies.
56+generateDocs :: IState -- ^ IState where all necessary information is
57+ -- extracted from.
58+ -> [Name] -- ^ List of namespaces to generate
59+ -- documentation for.
60+ -> FilePath -- ^ The directory to which documentation will
61+ -- be written.
62+ -> IO (Either String ())
63+generateDocs ist nss' out =
64+ do let nss = map toNsName nss'
65+ docs <- fetchInfo ist nss
66+ let (c, io) = foldl (checker docs) (0, return ()) nss
67+ io
68+ if c < length nss
69+ then catchIOError (createDocs ist docs out) (err . show)
70+ else err "No namespaces to generate documentation for"
71+
72+ where checker docs st ns | M.member ns docs = st
73+ checker docs (c, io) ns = (c+1, do prev <- io; warnMissing ns)
74+ warnMissing ns =
75+ putStrLn $ "Warning: Ignoring empty or non-existing namespace '" ++
76+ (nsName2Str ns) ++ "'"
77+
78+-- ----------------------------------------------------------------- [ Types ]
79+
80+type Failable = Either String
81+type NsName = [T.Text]
82+type NsItem = (Name, Maybe Docs, Accessibility)
83+type NsInfo = [NsItem]
84+type NsDict = M.Map NsName NsInfo
85+
86+-- Information stored together with IdrisDoc documentation
87+data DocInfo = DocInfo {
88+ -- Namespaces already documented
89+ namespaces :: S.Set NsName
90+ }
91+
92+-- --------------------------------------------------------------- [ Utility ]
93+
94+-- | Make an error message
95+err :: String -> IO (Failable ())
96+err s = return $ Left s
97+
98+-- | IdrisDoc version
99+version :: String
100+version = "1.0"
101+
102+-- | Converts a Name into a [Text] corresponding to the namespace
103+-- part of a NS Name.
104+toNsName :: Name -- ^ Name to convert
105+ -> NsName
106+toNsName (UN n) = [n]
107+toNsName (NS n ns) = (toNsName n) ++ ns
108+toNsName _ = []
109+
110+
111+-- | Retrieves the namespace part of a Name
112+getNs :: Name -- ^ Name to retrieve namespace for
113+ -> NsName
114+getNs (NS _ ns) = ns
115+getNs _ = []
116+
117+
118+-- | String to replace for the root namespace
119+rootNsStr :: String
120+rootNsStr = "[builtins]"
121+
122+
123+-- | Converts a NsName to string form
124+nsName2Str :: NsName -- ^ NsName to convert
125+ -> String
126+nsName2Str n = if null n then rootNsStr else name n
127+
128+ where name [] = []
129+ name [ns] = str ns
130+ name (ns:nss) = (name nss) ++ ('.' : str ns)
131+
132+-- --------------------------------------------------------- [ Info Fetching ]
133+
134+-- | Fetch info about namespaces and their contents
135+fetchInfo :: IState -- ^ IState to fetch info from
136+ -> [NsName] -- ^ List of namespaces to fetch info for
137+ -> IO NsDict -- ^ Mapping from namespace name to
138+ -- info about its contents
139+fetchInfo ist nss =
140+ do let originNss = S.fromList nss
141+ info <- nsDict ist
142+ let info' = M.map (filter (filterName . (\(n, _, _) -> n))) info
143+ info'' = M.map removeOrphans info'
144+ reachedNss = traceNss info'' originNss S.empty
145+ return $ M.filterWithKey (\k _ -> S.member k reachedNss) info''
146+
147+
148+-- | Removes loose class methods and data constructors,
149+-- leaving them documented only under their parent.
150+removeOrphans :: [NsItem] -- ^ List to remove orphans from
151+ -> [NsItem] -- ^ Orphan-free list
152+removeOrphans list =
153+ let children = S.fromList $ concatMap (names . (\(_, d, _) -> d)) list
154+ in filter ((`S.notMember` children) . (\(n, _, _) -> n)) list
155+
156+ where names (Just (DataDoc _ fds)) = map (\(FD n _ _ _ _) -> n) fds
157+ names (Just (ClassDoc _ _ fds)) = map (\(FD n _ _ _ _) -> n) fds
158+ names _ = []
159+
160+-- | Whether a Name names something which should be documented
161+filterName :: Name -- ^ Name to check
162+ -> Bool -- ^ Predicate result
163+filterName (UN n) | '@':'@':_ <- str n = False
164+filterName (UN _) = True
165+filterName (NS n _) = filterName n
166+filterName _ = False
167+
168+
169+-- | Finds all namespaces indirectly referred by a set of namespaces.
170+-- The NsItems of the namespaces are searched for references.
171+traceNss :: NsDict -- ^ Mappings of namespaces and their contents
172+ -> S.Set NsName -- ^ Set of namespaces to trace
173+ -> S.Set NsName -- ^ Set of namespaces which has been traced
174+ -> S.Set NsName -- ^ Set of namespaces to trace and all traced one
175+traceNss nsd sT sD =
176+ let nsTracer ns | Just nsis <- M.lookup ns nsd = map referredNss nsis
177+ nsTracer _ = [S.empty] -- Ignore
178+ reached = S.unions $ concatMap nsTracer (S.toList sT)
179+ processed = S.union sT sD
180+ untraced = S.difference reached processed
181+ in if S.null untraced then processed
182+ else traceNss nsd untraced processed
183+
184+
185+-- | Gets all namespaces directly referred by a NsItem
186+referredNss :: NsItem -- ^ The name to get all directly
187+ -- referred namespaces for
188+ -> S.Set NsName
189+referredNss (_, Nothing, _) = S.empty
190+referredNss (n, Just d, _) =
191+ let fds = getFunDocs d
192+ ts = concatMap types fds
193+ names = concatMap (extractPTermNames) ts
194+ in S.map getNs $ S.fromList names
195+
196+ where getFunDocs (FunDoc f) = [f]
197+ getFunDocs (DataDoc f fs) = f:fs
198+ getFunDocs (ClassDoc _ _ fs) = fs
199+ types (FD _ _ args t _) = t:(map second args)
200+ second (_, x, _, _) = x
201+
202+
203+-- | Returns an NsDict of containing all known namespaces and their contents
204+nsDict :: IState
205+ -> IO NsDict
206+nsDict ist =
207+ let nameDefList = ctxtAlist $ tt_ctxt ist
208+ adder m (n, _) = do map <- m
209+ doc <- loadDocs ist n
210+ let acc = getAccess ist n
211+ c = [(n, doc, acc)]
212+ return $ M.insertWith (++) (getNs n) c map
213+ in foldl adder (return M.empty) nameDefList
214+
215+
216+-- | Gets the Accessibility for a Name
217+getAccess :: IState -- ^ IState containing accessibility information
218+ -> Name -- ^ The Name to retrieve access for
219+ -> Accessibility
220+getAccess ist n =
221+ let res = lookupDefAcc n False (tt_ctxt ist)
222+ in case res of
223+ [(_, acc)] -> acc
224+ _ -> Public
225+
226+-- | Simple predicate for whether an NsItem has Docs
227+hasDoc :: NsItem -- ^ The NsItem to test
228+ -> Bool -- ^ The result
229+hasDoc (_, Just _, _) = True
230+hasDoc _ = False
231+
232+
233+-- | Predicate saying whether a Name possibly may have docs defined
234+-- Without this, getDocs from Idris.Docs may fail a pattern match.
235+mayHaveDocs :: Name -- ^ The Name to test
236+ -> Bool -- ^ The result
237+mayHaveDocs (UN _) = True
238+mayHaveDocs (NS n _) = mayHaveDocs n
239+mayHaveDocs _ = False
240+
241+
242+-- | Retrieves the Docs for a Name
243+loadDocs :: IState -- ^ IState to extract infomation from
244+ -> Name -- ^ Name to load Docs for
245+ -> IO (Maybe Docs)
246+loadDocs ist n
247+ | mayHaveDocs n = do docs <- runErrorT $ evalStateT (getDocs n) ist
248+ case docs of Right d -> return (Just d)
249+ Left _ -> return Nothing
250+ | otherwise = return Nothing
251+
252+
253+-- | Extracts names referred from a type.
254+-- The covering of all PTerms ensures that we avoid unanticipated cases,
255+-- though all of them are not needed. The author just did not know which!
256+-- TODO: Remove unnecessary cases
257+extractPTermNames :: PTerm -- ^ Where to extract names from
258+ -> [Name] -- ^ Extracted names
259+extractPTermNames (PRef _ n) = [n]
260+extractPTermNames (PInferRef _ n) = [n]
261+extractPTermNames (PPatvar _ n) = [n]
262+extractPTermNames (PLam n p1 p2) = n : concatMap extract [p1, p2]
263+extractPTermNames (PPi _ n p1 p2) = n : concatMap extract [p1, p2]
264+extractPTermNames (PLet n p1 p2 p3) = n : concatMap extract [p1, p2, p3]
265+extractPTermNames (PTyped p1 p2) = concatMap extract [p1, p2]
266+extractPTermNames (PApp _ p pas) = let names = concatMap extractPArg pas
267+ in (extract p) ++ names
268+extractPTermNames (PAppBind _ p pas) = let names = concatMap extractPArg pas
269+ in (extract p) ++ names
270+extractPTermNames (PMatchApp _ n) = [n]
271+extractPTermNames (PCase _ p ps) = let (ps1, ps2) = unzip ps
272+ in concatMap extract (p:(ps1 ++ ps2))
273+extractPTermNames (PRefl _ p) = extract p
274+extractPTermNames (PEq _ p1 p2) = concatMap extract [p1, p2]
275+extractPTermNames (PRewrite _ a b m) | Just c <- m =
276+ concatMap extract [a, b, c]
277+extractPTermNames (PRewrite _ a b _) = concatMap extract [a, b]
278+extractPTermNames (PPair _ _ p1 p2) = concatMap extract [p1, p2]
279+extractPTermNames (PDPair _ _ a b c) = concatMap extract [a, b, c]
280+extractPTermNames (PAlternative _ l) = concatMap extract l
281+extractPTermNames (PHidden p) = extract p
282+extractPTermNames (PGoal _ p1 n p2) = n : concatMap extract [p1, p2]
283+extractPTermNames (PDoBlock pdos) = concatMap extractPDo pdos
284+extractPTermNames (PIdiom _ p) = extract p
285+extractPTermNames (PMetavar n) = [n]
286+extractPTermNames (PProof tacts) = concatMap extractPTactic tacts
287+extractPTermNames (PTactics tacts) = concatMap extractPTactic tacts
288+extractPTermNames (PCoerced p) = extract p
289+extractPTermNames (PDisamb _ p) = extract p
290+extractPTermNames (PUnifyLog p) = extract p
291+extractPTermNames (PNoImplicits p) = extract p
292+extractPTermNames _ = []
293+
294+extract = extractPTermNames
295+
296+extractPArg (PImp {pname=n, getTm=p}) = n : extract p
297+extractPArg (PExp {getTm=p}) = extract p
298+extractPArg (PConstraint {getTm=p}) = extract p
299+extractPArg (PTacImplicit {pname=n, getScript=p1, getTm=p2})
300+ = n : (concatMap extract [p1, p2])
301+
302+extractPDo (DoExp _ p) = extract p
303+extractPDo (DoBind _ n p) = n : extract p
304+extractPDo (DoBindP _ p1 p2 ps) = let (ps1, ps2) = unzip ps
305+ ps' = ps1 ++ ps2
306+ in concatMap extract (p1 : p2 : ps')
307+extractPDo (DoLet _ n p1 p2) = n : concatMap extract [p1, p2]
308+extractPDo (DoLetP _ p1 p2) = concatMap extract [p1, p2]
309+
310+extractPTactic (Intro ns) = ns
311+extractPTactic (Focus n) = [n]
312+extractPTactic (Refine n _) = [n]
313+extractPTactic (Rewrite p) = extract p
314+extractPTactic (Induction n) = [n]
315+extractPTactic (Equiv p) = extract p
316+extractPTactic (MatchRefine n) = [n]
317+extractPTactic (LetTac n p) = n : extract p
318+extractPTactic (LetTacTy n p1 p2) = n : concatMap extract [p1, p2]
319+extractPTactic (Exact p) = extract p
320+extractPTactic (ProofSearch _ m ns) | Just n <- m = n : ns
321+extractPTactic (ProofSearch _ _ ns) = ns
322+extractPTactic (Try t1 t2) = concatMap extractPTactic [t1, t2]
323+extractPTactic (TSeq t1 t2) = concatMap extractPTactic [t1, t2]
324+extractPTactic (ApplyTactic p) = extract p
325+extractPTactic (ByReflection p) = extract p
326+extractPTactic (Reflect p) = extract p
327+extractPTactic (Fill p) = extract p
328+extractPTactic (GoalType _ t) = extractPTactic t
329+extractPTactic (TCheck p) = extract p
330+extractPTactic (TEval p) = extract p
331+extractPTactic _ = []
332+
333+-- ------------------------------------------------------- [ HTML Generation ]
334+
335+-- | Generates the actual HTML output based on info from a NsDict
336+-- A merge of the new docs and any existing docs located in the output dir
337+-- is attempted.
338+-- TODO: Ensure the merge always succeeds.
339+-- Currently the content of 'docs/<builtins>.html' may change between
340+-- runs, thus not always containing all items referred from other
341+-- namespace .html files.
342+createDocs :: IState -- ^ Needed to determine the types of names
343+ -> NsDict -- ^ All info from which to generate docs
344+ -> FilePath -- ^ The base directory to which
345+ -- documentation will be written.
346+ -> IO (Failable ())
347+createDocs ist nsd out =
348+ do docInfo <- readDocInfo out
349+ let (new, docInfo') = case docInfo of Nothing -> (True, DocInfo S.empty)
350+ Just di -> (False, di)
351+ nss = S.union (M.keysSet nsd) (namespaces docInfo')
352+ dExists <- doesDirectoryExist out
353+ if new && dExists then err $ "Output directory (" ++ out ++ ") is" ++
354+ " already in use for other than IdrisDoc."
355+ else do
356+ createDirectoryIfMissing True out
357+ foldl docGen (return ()) (M.toList nsd)
358+ createIndex nss out
359+ writeDocInfo out (docInfo' { namespaces = nss })
360+ copyDependencies out
361+ return $ Right ()
362+
363+ where docGen io (n, c) = do io; createNsDoc ist n c out
364+
365+
366+-- | (Over)writes the 'index.html' file in the given directory with
367+-- an (updated) index of namespaces in the documentation
368+createIndex :: S.Set NsName -- ^ Set of namespace names to
369+ -- include in the index
370+ -> FilePath -- ^ The base directory to which
371+ -- documentation will be written.
372+ -> IO ()
373+createIndex nss out =
374+ do (path, h) <- openTempFile out "index.html"
375+ BS2.hPut h $ renderHtml $ wrapper Nothing $ do
376+ H.h1 $ "Namespaces"
377+ H.ul ! class_ "names" $ do
378+ let path ns = "docs" </> genRelNsPath ns "html"
379+ item ns = do let n = toHtml $ nsName2Str ns
380+ link = toValue $ path ns
381+ H.li $ H.a ! href link ! class_ "code" $ n
382+ sort = L.sortBy (\n1 n2 -> reverse n1 `compare` reverse n2)
383+ forM_ (sort $ S.toList nss) item
384+ hClose h
385+ renameFile path (out </> "index.html")
386+
387+
388+-- | Generates a HTML file for a namespace and its contents.
389+-- The location for e.g. Prelude.Algebra is <base>/Prelude/Algebra.html
390+createNsDoc :: IState -- ^ Needed to determine the types of names
391+ -> NsName -- ^ The name of the namespace to
392+ -- create documentation for
393+ -> NsInfo -- ^ The contents of the namespace
394+ -> FilePath -- ^ The base directory to which
395+ -- documentation will be written.
396+ -> IO ()
397+createNsDoc ist ns content out =
398+ do let tpath = out </> "docs" </> (genRelNsPath ns "html")
399+ dir = takeDirectory tpath
400+ file = takeFileName tpath
401+ visible (_, _, Hidden) = False
402+ visible _ = True
403+ haveDocs (_, Just d, _) = [d]
404+ haveDocs _ = []
405+ -- Do not document private members
406+ content' = filter visible content
407+ -- We cannot do anything without a Doc
408+ content'' = concatMap haveDocs content'
409+ createDirectoryIfMissing True dir
410+ (path, h) <- openTempFile dir file
411+ BS2.hPut h $ renderHtml $ wrapper (Just ns) $ do
412+ H.h1 $ toHtml (nsName2Str ns)
413+ H.dl ! class_ "decls" $ forM_ content'' (createOtherDoc ist)
414+ hClose h
415+ renameFile path tpath
416+
417+
418+-- | Generates a relative filepath for a namespace, appending an extension
419+genRelNsPath :: NsName -- ^ Namespace to generate a path for
420+ -> String -- ^ Extension suffix
421+ -> FilePath
422+genRelNsPath ns suffix = nsName2Str ns <.> suffix
423+
424+
425+-- | Generates a HTML type signature with proper tags
426+-- TODO: Turn docstrings into title attributes more robustly
427+genTypeHeader :: IState -- ^ Needed to determine the types of names
428+ -> FunDoc -- ^ Type to generate type declaration for
429+ -> H.Html -- ^ Resulting HTML
430+genTypeHeader ist (FD n _ args ftype _) = do
431+ H.span ! class_ (toValue $ "name " ++ getType n)
432+ ! title (toValue $ show n)
433+ $ toHtml $ name $ nsroot n
434+ H.span ! class_ "word" $ do nbsp; ":"; nbsp
435+ H.span ! class_ "signature" $ preEscapedToHtml htmlSignature
436+
437+ where
438+ htmlSignature = displayDecorated decorator $ renderCompact signature
439+ signature = pprintPTerm False [] names ftype
440+ names = [ n | (n@(UN n'), _, _, _) <- args,
441+ not (T.isPrefixOf (txt "__") n') ]
442+
443+ decorator AnnConstData str = htmlSpan str "data" str
444+ decorator AnnConstType str = htmlSpan str "type" str
445+ decorator AnnKeyword str = htmlSpan "" "keyword" str
446+ decorator (AnnBoundName n i) str | Just t <- M.lookup n docs =
447+ let cs = (if i then "implicit " else "") ++ "documented boundvar"
448+ in htmlSpan t cs str
449+ decorator (AnnBoundName _ i) str =
450+ let cs = (if i then "implicit " else "") ++ "boundvar"
451+ in htmlSpan "" cs str
452+ decorator (AnnName n _ _ _) str
453+ | filterName n = htmlLink (show n) (getType n) (link n) str
454+ | otherwise = htmlSpan "" (getType n) str
455+ decorator (AnnTextFmt BoldText) str = "<b>" ++ str ++ "</b>"
456+ decorator (AnnTextFmt UnderlineText) str = "<u>" ++ str ++ "</u>"
457+ decorator (AnnTextFmt ItalicText) str = "<i>" ++ str ++ "</i>"
458+ decorator _ str = str
459+
460+ htmlSpan :: String -> String -> String -> String
461+ htmlSpan t cs str = do
462+ R.renderHtml $ H.span ! class_ (toValue cs)
463+ ! title (toValue t)
464+ $ toHtml str
465+ htmlLink :: String -> String -> String -> String -> String
466+ htmlLink t cs a str = do
467+ R.renderHtml $ H.a ! class_ (toValue cs)
468+ ! title (toValue t) ! href (toValue a)
469+ $ toHtml str
470+
471+ docs = M.fromList $ mapMaybe docExtractor args
472+ docExtractor (_, _, _, Nothing) = Nothing
473+ docExtractor (n, _, _, Just d) = Just (n, doc2Str d)
474+ -- TODO: Remove <p> tags more robustly
475+ doc2Str d = let dirty = renderMarkup $ contents $ renderDoc $ d
476+ in take (length dirty - 8) $ drop 3 dirty
477+
478+ name (NS n ns) = show (NS (sUN $ name n) ns)
479+ name n = let n' = show n
480+ in if (head n') `elem` opChars
481+ then '(':(n' ++ ")")
482+ else n'
483+
484+ link n = let path = genRelNsPath (getNs n) "html"
485+ in path ++ "#" ++ (show n)
486+
487+ getType :: Name -> String
488+ getType n = let ctxt = tt_ctxt ist
489+ in case () of
490+ _ | isDConName n ctxt -> "constructor"
491+ _ | isFnName n ctxt -> "function"
492+ _ | isTConName n ctxt -> "type"
493+ _ | otherwise -> ""
494+
495+-- | Generates HTML documentation for a function.
496+createFunDoc :: IState -- ^ Needed to determine the types of names
497+ -> FunDoc -- ^ Function to generate block for
498+ -> H.Html -- ^ Resulting HTML
499+createFunDoc ist fd@(FD name docstring args ftype fixity) = do
500+ H.dt ! (A.id $ toValue $ show name) $ genTypeHeader ist fd
501+ H.dd $ do
502+ (if nullDocstring docstring then Empty else renderDoc docstring)
503+ let args' = filter (\(_, _, _, d) -> isJust d) args
504+ if (not $ null args') || (isJust fixity)
505+ then H.dl $ do
506+ if (isJust fixity) then do
507+ H.dt ! class_ "fixity" $ "Fixity"
508+ let f = fromJust fixity
509+ H.dd ! class_ "fixity" ! title (toValue $ show f) $ genFix f
510+ else Empty
511+ forM_ args' genArg
512+ else Empty
513+
514+ where genFix (Infixl {prec=p}) =
515+ toHtml $ "Left associative, precedence " ++ show p
516+ genFix (Infixr {prec=p}) =
517+ toHtml $ "Left associative, precedence " ++ show p
518+ genFix (InfixN {prec=p}) =
519+ toHtml $ "Non-associative, precedence " ++ show p
520+ genFix (PrefixN {prec=p}) =
521+ toHtml $ "Prefix, precedence " ++ show p
522+ genArg (_, _, _, Nothing) = Empty
523+ genArg (name, _, _, Just docstring) = do
524+ H.dt $ toHtml $ show name
525+ H.dd $ renderDoc docstring
526+
527+
528+-- | Generates HTML documentation for any Docs type
529+-- TODO: Generate actual signatures for typeclasses
530+createOtherDoc :: IState -- ^ Needed to determine the types of names
531+ -> Docs -- ^ Namespace item to generate HTML block for
532+ -> H.Html -- ^ Resulting HTML
533+createOtherDoc ist (FunDoc fd) = createFunDoc ist fd
534+
535+createOtherDoc ist (ClassDoc n docstring fds) = do
536+ H.dt ! (A.id $ toValue $ show n) $ do
537+ H.span ! class_ "word" $ do "class"; nbsp
538+ H.span ! class_ "name type"
539+ ! title (toValue $ show n)
540+ $ toHtml $ name $ nsroot n
541+ H.span ! class_ "signature" $ nbsp
542+ H.dd $ do
543+ (if nullDocstring docstring then Empty else renderDoc docstring)
544+ H.dl ! class_ "decls" $ forM_ fds (createFunDoc ist)
545+
546+ where name (NS n ns) = show (NS (sUN $ name n) ns)
547+ name n = let n' = show n
548+ in if (head n') `elem` opChars
549+ then '(':(n' ++ ")")
550+ else n'
551+
552+createOtherDoc ist (DataDoc fd@(FD n docstring args _ _) fds) = do
553+ H.dt ! (A.id $ toValue $ show n) $ do
554+ H.span ! class_ "word" $ do "data"; nbsp
555+ genTypeHeader ist fd
556+ H.dd $ do
557+ (if nullDocstring docstring then Empty else renderDoc docstring)
558+ let args' = filter (\(_, _, _, d) -> isJust d) args
559+ if not $ null args'
560+ then H.dl $ forM_ args' genArg
561+ else Empty
562+ H.dl ! class_ "decls" $ forM_ fds (createFunDoc ist)
563+
564+ where genArg (_, _, _, Nothing) = Empty
565+ genArg (name, _, _, Just docstring) = do
566+ H.dt $ toHtml $ show name
567+ H.dd $ renderDoc docstring
568+
569+
570+-- | Generates everything but the actual content of the page
571+wrapper :: Maybe NsName -- ^ Namespace name, unless it is the index
572+ -> H.Html -- ^ Inner HTML
573+ -> H.Html
574+wrapper ns inner =
575+ let (index, str) = extract ns
576+ base = if index then "" else "../"
577+ styles = base ++ "styles.css" :: String
578+ indexPage = base ++ "index.html" :: String
579+ in H.docTypeHtml $ do
580+ H.head $ do
581+ H.title $ do
582+ "IdrisDoc"
583+ if index then " Index" else do
584+ ": "
585+ toHtml str
586+ H.link ! type_ "text/css" ! rel "stylesheet"
587+ ! href (toValue styles)
588+ H.body ! class_ (if index then "index" else "namespace") $ do
589+ H.div ! class_ "wrapper" $ do
590+ H.header $ do
591+ H.strong "IdrisDoc"
592+ if index then Empty else do
593+ ": "
594+ toHtml str
595+ H.nav $ H.a ! href (toValue indexPage) $ "Index"
596+ H.div ! class_ "container" $ inner
597+ H.footer $ do
598+ "Produced by IdrisDoc version "
599+ toHtml version
600+
601+ where extract (Just ns) = (False, nsName2Str ns)
602+ extract _ = (True, "")
603+
604+
605+-- | Non-break space character
606+nbsp :: H.Html
607+nbsp = preEscapedToHtml ("&nbsp;" :: String)
608+
609+
610+-- | Copies IdrisDoc dependencies such as stylesheets to a directory
611+copyDependencies :: FilePath
612+ -> IO ()
613+copyDependencies dir =
614+ do styles <- getDataFileName $ "idrisdoc" </> "styles.css"
615+ copyFile styles (dir </> "styles.css")
616+
617+-- ---------------------------------------------------- [ DocInfo Read/Write ]
618+
619+-- | Name of the DocInfo file
620+docInfoFile :: String
621+docInfoFile = "IdrisDoc"
622+
623+
624+-- | Reads the 'IdrisDoc' file from the given directory, if it is there
625+-- The info within is converted to a DocInfo
626+readDocInfo :: FilePath -- ^ The IdrisDoc directory also containing the info
627+ -> IO (Maybe DocInfo)
628+readDocInfo dir =
629+ do exists <- doesFileExist (dir </> docInfoFile)
630+ if not exists
631+ then return Nothing
632+ -- Filter out namespaces for which documentation no longer exists
633+ else do di <- (withFile (dir </> docInfoFile) ReadMode reader)
634+ s <- S.fold (onlyValid dir) (return S.empty) (namespaces di)
635+ return . Just . DocInfo $ s
636+
637+ where reader h = let converter = text2DocInfo . E.decodeUtf8
638+ in converter `fmap` BS.hGetContents h
639+ onlyValid out ns s = do s' <- s
640+ let end = (genRelNsPath ns "html")
641+ exists <- doesFileExist $ out </> end
642+ if exists then return $ S.insert ns s'
643+ else s
644+
645+-- | Writes a DocInfo to the 'IdrisDoc' file in the given directory
646+writeDocInfo :: FilePath -- ^ The directory to write to
647+ -> DocInfo -- ^ The DocInfo to write
648+ -> IO ()
649+writeDocInfo dir info = withFile (dir </> docInfoFile) WriteMode writer
650+
651+ where writer h = BS.hPut h $ E.encodeUtf8 $ docInfo2Text info
652+
653+
654+-- | Converts a DocInfo to Text for easy writing
655+docInfo2Text :: DocInfo
656+ -> T.Text
657+docInfo2Text (DocInfo {namespaces=nss}) = S.fold folder T.empty nss
658+
659+ where folder [] res = T.append (txt rootNsStr) (T.cons '\n' res)
660+ folder ns res = let base = (T.append (head ns) $ T.cons '\n' res)
661+ in foldr joiner base (tail ns)
662+ joiner n r = T.append n (T.cons '.' r)
663+
664+
665+-- | Converts an unmodified Text created by 'docInfo2Text' to DocInfo
666+text2DocInfo :: T.Text
667+ -> DocInfo
668+text2DocInfo text = DocInfo $ foldl nsAdder S.empty (T.lines text)
669+
670+ where nsAdder set text = S.insert (txt2Ns text) set
671+ txt2Ns t | t == (txt rootNsStr) = []
672+ txt2Ns t = reverse $ T.splitOn (T.singleton '.') t
src/Idris/REPL.hs+22
@@ -13,6 +13,7 @@ import Idris.Error
1313import Idris.ErrReverse
1414import Idris.Delaborate
1515import Idris.Docstrings (Docstring, overview, renderDocstring)
16+import Idris.IdrisDoc
1617import Idris.Prover
1718import Idris.Parser hiding (indent)
1819import Idris.Primitives
@@ -78,6 +79,7 @@ import Data.List
7879import Data.Char
7980import Data.Version
8081import Data.Word (Word)
82+import Data.Either (partitionEithers)
8183import Control.DeepSeq
8284
8385import Debug.Trace
@@ -1085,6 +1087,20 @@ process h fn (CallsWho n) =
10851087 prettyName True [] n <+> text "calls:" <$>
10861088 indent 1 (vsep (map ((text "*" <+>) . align . prettyName True []) ns)))
10871089 calls
1090+-- IdrisDoc
1091+process h fn (MakeDoc s) =
1092+ do istate <- getIState
1093+ let names = words s
1094+ parse n | Success x <- runparser name istate fn n = Right x
1095+ parse n = Left n
1096+ (bad, nss) = partitionEithers $ map parse names
1097+ cd <- runIO $ getCurrentDirectory
1098+ let outputDir = cd </> "doc"
1099+ result <- if null bad then runIO $ generateDocs istate nss outputDir
1100+ else return . Left $ "Illegal name: " ++ head bad
1101+ case result of Right _ -> iputStrLn "IdrisDoc generated"
1102+ Left err -> iPrintError err
1103+
10881104
10891105classInfo :: ClassInfo -> Idris (Doc OutputAnnotation)
10901106classInfo ci = do ist <- getIState
@@ -1174,6 +1190,7 @@ parseArgs ("--build":n:ns) = PkgBuild n : (parseArgs ns)
11741190parseArgs ("--install":n:ns) = PkgInstall n : (parseArgs ns)
11751191parseArgs ("--repl":n:ns) = PkgREPL n : (parseArgs ns)
11761192parseArgs ("--clean":n:ns) = PkgClean n : (parseArgs ns)
1193+parseArgs ("--mkdoc":n:ns) = PkgMkDoc n : (parseArgs ns) -- IdrisDoc
11771194parseArgs ("--checkpkg":n:ns) = PkgCheck n : (parseArgs ns)
11781195-- Misc Options
11791196parseArgs ("--bytecode":n:ns) = NoREPL : BCAsm n : (parseArgs ns)
@@ -1528,6 +1545,11 @@ getPkgCheck :: Opt -> Maybe String
15281545getPkgCheck (PkgCheck str) = Just str
15291546getPkgCheck _ = Nothing
15301547
1548+-- IdrisDoc
1549+getPkgMkDoc :: Opt -> Maybe String
1550+getPkgMkDoc (PkgMkDoc str) = Just str
1551+getPkgMkDoc _ = Nothing
1552+
15311553getCodegen :: Opt -> Maybe Codegen
15321554getCodegen (UseCodegen x) = Just x
15331555getCodegen _ = Nothing
src/Idris/REPLParser.hs+1
@@ -106,6 +106,7 @@ pCmd = do P.whiteSpace; try (do cmd ["q", "quit"]; eof; return Quit)
106106 <|> try (do cmd ["apropos"]; str <- many anyChar ; return (Apropos str))
107107 <|> try (do cmd ["wc", "whocalls"]; P.whiteSpace; n <- P.fnName ; return (WhoCalls n))
108108 <|> try (do cmd ["cw", "callswho"]; P.whiteSpace; n <- P.fnName ; return (CallsWho n))
109+ <|> try (do cmd ["mkdoc"]; str <- many anyChar; return (MakeDoc str))
109110 <|> do P.whiteSpace; do eof; return NOP
110111 <|> do t <- P.fullExpr defaultSyntax; return (Eval t)
111112
src/Pkg/Package.hs+40−3
@@ -5,18 +5,24 @@ import System.Process
55import System.Directory
66import System.Exit
77import System.IO
8−import System.FilePath ((</>), addTrailingPathSeparator, takeFileName)
8+import System.FilePath ((</>), addTrailingPathSeparator, takeFileName, takeDirectory)
99import System.Directory (createDirectoryIfMissing, copyFile)
1010
1111import Util.System
1212
1313import Control.Monad
14+import Control.Monad.Trans.State.Strict (execStateT)
15+import Control.Monad.Error (runErrorT)
16+
1417import Data.List
1518import Data.List.Split(splitOn)
1619
1720import Idris.Core.TT
1821import Idris.REPL
22+import Idris.Parser (loadModule)
23+import Idris.Output (pshow)
1924import Idris.AbsSyntax
25+import Idris.IdrisDoc
2026import Idris.Output
2127
2228import IRTS.System
@@ -74,7 +80,7 @@ checkPkg :: Bool -- ^ Show Warnings
7480 -> FilePath -- ^ Path to ipkg file.
7581 -> IO ()
7682checkPkg warnonly quit fpath
77− = do pkgdesc <-parseDesc fpath
83+ = do pkgdesc <- parseDesc fpath
7884 ok <- mapM (testLib warnonly (pkgname pkgdesc)) (libdeps pkgdesc)
7985 when (and ok) $
8086 do dir <- getCurrentDirectory
@@ -122,6 +128,38 @@ cleanPkg fp
122128 Nothing -> return ()
123129 Just s -> rmFile $ dir </> s
124130
131+-- | Generate IdrisDoc for package
132+-- TODO: Handle case where module does not contain a matching namespace
133+-- E.g. from prelude.ipkg: IO, Prelude.Chars, Builtins
134+documentPkg :: FilePath -- ^ Path to .ipkg file.
135+ -> IO ()
136+documentPkg fp =
137+ do pkgdesc <- parseDesc fp
138+ cd <- getCurrentDirectory
139+ let pkgDir = cd </> takeDirectory fp
140+ outputDir = cd </> (pkgname pkgdesc) ++ "_doc"
141+ opts = NoREPL : Verbose : idris_opts pkgdesc
142+ mods = modules pkgdesc
143+ fs = map (foldl1' (</>) . splitOn "." . showCG) mods
144+ setCurrentDirectory $ pkgDir </> sourcedir pkgdesc
145+ make (makefile pkgdesc)
146+ setCurrentDirectory $ pkgDir
147+ let run l = runErrorT . (execStateT l)
148+ load [] = return ()
149+ load (f:fs) = do loadModule stdout f; load fs
150+ loader = do idrisMain opts; load fs
151+ idrisInstance <- run loader idrisInit
152+ setCurrentDirectory cd
153+ case idrisInstance of
154+ Left err -> do putStrLn $ pshow idrisInit err; exitWith (ExitFailure 1)
155+ Right ist ->
156+ do docRes <- generateDocs ist mods outputDir
157+ case docRes of
158+ Right _ -> return ()
159+ Left msg -> do putStrLn msg
160+ exitWith (ExitFailure 1)
161+
162+
125163-- | Install package
126164installPkg :: PkgDesc -> IO ()
127165installPkg pkgdesc
@@ -132,7 +170,6 @@ installPkg pkgdesc
132170 Just o -> return () -- do nothing, keep executable locally, for noe
133171 mapM_ (installObj (pkgname pkgdesc)) (objs pkgdesc)
134172
135−
136173-- ---------------------------------------------------------- [ Helper Methods ]
137174-- Methods for building, testing, installing, and removal of idris
138175-- packages.