1{-# LANGUAGE PatternGuards #-}
2{-# LANGUAGE OverloadedStrings #-}
4-- | Generation of HTML documentation for Idris code
5module Idris.IdrisDoc (generateDocs) where
7import Idris.Core.TT (Name (..), sUN, SpecialName (..), OutputAnnotation (..),
8 TextFormatting (..), txt, str, nsroot, constIsType, toAlist)
9import Idris.Core.Evaluate (ctxtAlist, Def (..), lookupDefAcc,
10 Accessibility (..), isDConName, isFnName,
12import Idris.ParseHelpers (opChars)
15import Idris.Docstrings (nullDocstring)
16import qualified Idris.Docstrings as Docstrings
18import IRTS.System (getDataFileName)
20import Control.Applicative ((<|>))
21import Control.Monad (forM_)
22import Control.Monad.Trans.Except
23import Control.Monad.Trans.State.Strict
27import qualified Data.ByteString as BS
28import qualified Data.ByteString.Lazy as BS2
29import qualified Data.Text.Encoding as E
30import qualified Data.List as L
31import qualified Data.List.Split as LS
32import qualified Data.Map as M hiding ((!))
33import Data.Monoid (mempty)
34import qualified Data.Ord (compare)
35import qualified Data.Set as S
36import qualified Data.Text as T
41import System.Directory
43import Text.PrettyPrint.Annotated.Leijen (displayDecorated, renderCompact)
45import Text.Blaze (toValue, contents)
46import Text.Blaze.Internal (MarkupM (Empty))
47import Text.Blaze.Html5 ((!), toHtml, preEscapedToHtml)
48import qualified Text.Blaze.Html5 as H
49import Text.Blaze.Html5.Attributes as A
50import Text.Blaze.Html.Renderer.Utf8 (renderHtml)
51import qualified Text.Blaze.Html.Renderer.String as R
52import Text.Blaze.Renderer.String (renderMarkup)
54-- ---------------------------------------------------------------- [ Public ]
56-- | Generates HTML documentation for a series of loaded namespaces
57-- and their dependencies.
58generateDocs :: IState -- ^ IState where all necessary information is
60 -> [Name] -- ^ List of namespaces to generate
62 -> FilePath -- ^ The directory to which documentation will
64 -> IO (Either String ())
65generateDocs ist nss' out =
66 do let nss = map toNsName nss'
67 docs <- fetchInfo ist nss
68 let (c, io) = foldl (checker docs) (0, return ()) nss
71 then catchIOError (createDocs ist docs out) (err . show)
72 else err "No namespaces to generate documentation for"
74 where checker docs st ns | M.member ns docs = st
75 checker docs (c, io) ns = (c+1, do prev <- io; warnMissing ns)
77 putStrLn $ "Warning: Ignoring empty or non-existing namespace '" ++
78 (nsName2Str ns) ++ "'"
80-- ----------------------------------------------------------------- [ Types ]
82-- | Either an error message or a result
83type Failable = Either String
85-- | Internal representation of a fully qualified namespace name
88-- | All information to be documented about a single namespace member
89type NsItem = (Name, Maybe Docs, Accessibility)
91-- | Docstrings containing fully elaborated term annotations
92type FullDocstring = Docstrings.Docstring Docstrings.DocTerm
94-- | All information to be documented about a namespace
95data NsInfo = NsInfo { nsDocstring :: Maybe FullDocstring,
96 nsContents :: [NsItem]
99-- | A map from namespace names to information about them
100type NsDict = M.Map NsName NsInfo
102-- --------------------------------------------------------------- [ Utility ]
104-- | Make an error message
105err :: String -> IO (Failable ())
106err s = return $ Left s
112-- | Converts a Name into a [Text] corresponding to the namespace
114toNsName :: Name -- ^ Name to convert
117toNsName (NS n ns) = (toNsName n) ++ ns
121-- | Retrieves the namespace part of a Name
122getNs :: Name -- ^ Name to retrieve namespace for
128-- | String to replace for the root namespace
130rootNsStr = "[builtins]"
133-- | Converts a NsName to string form
134nsName2Str :: NsName -- ^ NsName to convert
136nsName2Str n = if null n then rootNsStr else name n
140 name (ns:nss) = (name nss) ++ ('.' : str ns)
142-- --------------------------------------------------------- [ Info Fetching ]
144-- | Fetch info about namespaces and their contents
145fetchInfo :: IState -- ^ IState to fetch info from
146 -> [NsName] -- ^ List of namespaces to fetch info for
147 -> IO NsDict -- ^ Mapping from namespace name to
148 -- info about its contents
150 do let originNss = S.fromList nss
152 let accessible = M.map (filterContents filterInclude) info
153 nonOrphan = M.map (updateContents removeOrphans) accessible
154 nonEmpty = M.filter (not . null . nsContents) nonOrphan
155 reachedNss = traceNss nonEmpty originNss S.empty
156 return $ M.filterWithKey (\k _ -> S.member k reachedNss) nonEmpty
159 filterContents p (NsInfo md ns) = NsInfo md (filter p ns)
160 updateContents f x = x { nsContents = f (nsContents x) }
162-- | Removes loose class methods and data constructors,
163-- leaving them documented only under their parent.
164removeOrphans :: [NsItem] -- ^ List to remove orphans from
165 -> [NsItem] -- ^ Orphan-free list
167 let children = S.fromList $ concatMap (names . (\(_, d, _) -> d)) list
168 in filter ((`S.notMember` children) . (\(n, _, _) -> n)) list
170 where names (Just (DataDoc _ fds)) = map (\(FD n _ _ _ _) -> n) fds
171 names (Just (ClassDoc _ _ fds _ _ _ _)) = map (\(FD n _ _ _ _) -> n) fds
174-- | Whether a Name names something which should be documented
175filterName :: Name -- ^ Name to check
176 -> Bool -- ^ Predicate result
177filterName (UN n) | '@':'@':_ <- str n = False
178filterName (UN _) = True
179filterName (NS n _) = filterName n
183-- | Whether a NsItem should be included in the documentation.
184-- It must not be Hidden and filterName must return True for the name.
185-- Also it must have Docs -- without Docs, nothing can be done.
186filterInclude :: NsItem -- ^ Accessibility to check
187 -> Bool -- ^ Predicate result
188filterInclude (name, Just _, Public) | filterName name = True
189filterInclude (name, Just _, Frozen) | filterName name = True
190filterInclude _ = False
193-- | Finds all namespaces indirectly referred by a set of namespaces.
194-- The NsItems of the namespaces are searched for references.
195traceNss :: NsDict -- ^ Mappings of namespaces and their contents
196 -> S.Set NsName -- ^ Set of namespaces to trace
197 -> S.Set NsName -- ^ Set of namespaces which has been traced
198 -> S.Set NsName -- ^ Set of namespaces to trace and all traced one
200 let nsTracer ns | Just nsis <- M.lookup ns nsd = map referredNss (nsContents nsis)
201 nsTracer _ = [S.empty] -- Ignore
202 reached = S.unions $ concatMap nsTracer (S.toList sT)
203 processed = S.union sT sD
204 untraced = S.difference reached processed
205 in if S.null untraced then processed
206 else traceNss nsd untraced processed
209-- | Gets all namespaces directly referred by a NsItem
210referredNss :: NsItem -- ^ The name to get all directly
211 -- referred namespaces for
213referredNss (_, Nothing, _) = S.empty
214referredNss (n, Just d, _) =
215 let fds = getFunDocs d
216 ts = concatMap types fds
217 names = concatMap (extractPTermNames) ts
218 in S.map getNs $ S.fromList names
220 where getFunDocs (FunDoc f) = [f]
221 getFunDocs (DataDoc f fs) = f:fs
222 getFunDocs (ClassDoc _ _ fs _ _ _ _) = fs
223 types (FD _ _ args t _) = t:(map second args)
224 second (_, x, _, _) = x
227-- | Returns an NsDict of containing all known namespaces and their contents
230nsDict ist = flip (foldl addModDoc) modDocs $ foldl adder (return M.empty) nameDefList
231 where nameDefList = ctxtAlist $ tt_ctxt ist
232 adder m (n, _) = do map <- m
233 doc <- loadDocs ist n
234 let access = getAccess ist n
235 nInfo = NsInfo Nothing [(n, doc, access)]
236 return $ M.insertWith addNameInfo (getNs n) nInfo map
237 addNameInfo (NsInfo m ns) (NsInfo m' ns') = NsInfo (m <|> m') (ns ++ ns')
238 modDocs = map (\(mn, d) -> (mn, NsInfo (Just d) [])) $ toAlist (idris_moduledocs ist)
239 addModDoc :: IO NsDict -> (Name, NsInfo) -> IO NsDict
240 addModDoc dict (mn, d) = fmap (M.insertWith addNameInfo (getNs mn) d) dict
245-- | Gets the Accessibility for a Name
246getAccess :: IState -- ^ IState containing accessibility information
247 -> Name -- ^ The Name to retrieve access for
250 let res = lookupDefAcc n False (tt_ctxt ist)
255-- | Simple predicate for whether an NsItem has Docs
256hasDoc :: NsItem -- ^ The NsItem to test
257 -> Bool -- ^ The result
258hasDoc (_, Just _, _) = True
262-- | Predicate saying whether a Name possibly may have docs defined
263-- Without this, getDocs from Idris.Docs may fail a pattern match.
264mayHaveDocs :: Name -- ^ The Name to test
265 -> Bool -- ^ The result
266mayHaveDocs (UN _) = True
267mayHaveDocs (NS n _) = mayHaveDocs n
271-- | Retrieves the Docs for a Name
272loadDocs :: IState -- ^ IState to extract infomation from
273 -> Name -- ^ Name to load Docs for
276 | mayHaveDocs n = do docs <- runExceptT $ evalStateT (getDocs n FullDocs) ist
277 case docs of Right d -> return (Just d)
278 Left _ -> return Nothing
279 | otherwise = return Nothing
282-- | Extracts names referred from a type.
283-- The covering of all PTerms ensures that we avoid unanticipated cases,
284-- though all of them are not needed. The author just did not know which!
285-- TODO: Remove unnecessary cases
286extractPTermNames :: PTerm -- ^ Where to extract names from
287 -> [Name] -- ^ Extracted names
288extractPTermNames (PRef _ n) = [n]
289extractPTermNames (PInferRef _ n) = [n]
290extractPTermNames (PPatvar _ n) = [n]
291extractPTermNames (PLam _ n p1 p2) = n : concatMap extract [p1, p2]
292extractPTermNames (PPi _ n p1 p2) = n : concatMap extract [p1, p2]
293extractPTermNames (PLet _ n p1 p2 p3) = n : concatMap extract [p1, p2, p3]
294extractPTermNames (PTyped p1 p2) = concatMap extract [p1, p2]
295extractPTermNames (PApp _ p pas) = let names = concatMap extractPArg pas
296 in (extract p) ++ names
297extractPTermNames (PAppBind _ p pas) = let names = concatMap extractPArg pas
298 in (extract p) ++ names
299extractPTermNames (PMatchApp _ n) = [n]
300extractPTermNames (PCase _ p ps) = let (ps1, ps2) = unzip ps
301 in concatMap extract (p:(ps1 ++ ps2))
302extractPTermNames (PRefl _ p) = extract p
303extractPTermNames (PEq _ _ _ p1 p2) = concatMap extract [p1, p2]
304extractPTermNames (PRewrite _ a b m) | Just c <- m =
305 concatMap extract [a, b, c]
306extractPTermNames (PRewrite _ a b _) = concatMap extract [a, b]
307extractPTermNames (PPair _ _ p1 p2) = concatMap extract [p1, p2]
308extractPTermNames (PDPair _ _ a b c) = concatMap extract [a, b, c]
309extractPTermNames (PAlternative _ l) = concatMap extract l
310extractPTermNames (PHidden p) = extract p
311extractPTermNames (PGoal _ p1 n p2) = n : concatMap extract [p1, p2]
312extractPTermNames (PDoBlock pdos) = concatMap extractPDo pdos
313extractPTermNames (PIdiom _ p) = extract p
314extractPTermNames (PMetavar n) = [n]
315extractPTermNames (PProof tacts) = concatMap extractPTactic tacts
316extractPTermNames (PTactics tacts) = concatMap extractPTactic tacts
317extractPTermNames (PCoerced p) = extract p
318extractPTermNames (PDisamb _ p) = extract p
319extractPTermNames (PUnifyLog p) = extract p
320extractPTermNames (PNoImplicits p) = extract p
321extractPTermNames (PRunTactics _ p) = extract p
322extractPTermNames _ = []
324-- | Shorter name for extractPTermNames
325extract :: PTerm -- ^ Where to extract names from
326 -> [Name] -- ^ Extracted names
327extract = extractPTermNames
329-- | Helper function for extractPTermNames
330extractPArg :: PArg -> [Name]
331extractPArg (PImp {pname=n, getTm=p}) = n : extract p
332extractPArg (PExp {getTm=p}) = extract p
333extractPArg (PConstraint {getTm=p}) = extract p
334extractPArg (PTacImplicit {pname=n, getScript=p1, getTm=p2})
335 = n : (concatMap extract [p1, p2])
337-- | Helper function for extractPTermNames
338extractPDo :: PDo -> [Name]
339extractPDo (DoExp _ p) = extract p
340extractPDo (DoBind _ n p) = n : extract p
341extractPDo (DoBindP _ p1 p2 ps) = let (ps1, ps2) = unzip ps
343 in concatMap extract (p1 : p2 : ps')
344extractPDo (DoLet _ n p1 p2) = n : concatMap extract [p1, p2]
345extractPDo (DoLetP _ p1 p2) = concatMap extract [p1, p2]
347-- | Helper function for extractPTermNames
348extractPTactic :: PTactic -> [Name]
349extractPTactic (Intro ns) = ns
350extractPTactic (Focus n) = [n]
351extractPTactic (Refine n _) = [n]
352extractPTactic (Rewrite p) = extract p
353extractPTactic (Induction p) = extract p
354extractPTactic (CaseTac p) = extract p
355extractPTactic (Equiv p) = extract p
356extractPTactic (MatchRefine n) = [n]
357extractPTactic (LetTac n p) = n : extract p
358extractPTactic (LetTacTy n p1 p2) = n : concatMap extract [p1, p2]
359extractPTactic (Exact p) = extract p
360extractPTactic (ProofSearch _ _ _ m ns) | Just n <- m = n : ns
361extractPTactic (ProofSearch _ _ _ _ ns) = ns
362extractPTactic (Try t1 t2) = concatMap extractPTactic [t1, t2]
363extractPTactic (TSeq t1 t2) = concatMap extractPTactic [t1, t2]
364extractPTactic (ApplyTactic p) = extract p
365extractPTactic (ByReflection p) = extract p
366extractPTactic (Reflect p) = extract p
367extractPTactic (Fill p) = extract p
368extractPTactic (GoalType _ t) = extractPTactic t
369extractPTactic (TCheck p) = extract p
370extractPTactic (TEval p) = extract p
373-- ------------------------------------------------------- [ HTML Generation ]
375-- | Generates the actual HTML output based on info from a NsDict
376-- A merge of the new docs and any existing docs located in the output dir
378-- TODO: Ensure the merge always succeeds.
379-- Currently the content of 'docs/<builtins>.html' may change between
380-- runs, thus not always containing all items referred from other
381-- namespace .html files.
382createDocs :: IState -- ^ Needed to determine the types of names
383 -> NsDict -- ^ All info from which to generate docs
384 -> FilePath -- ^ The base directory to which
385 -- documentation will be written.
387createDocs ist nsd out =
388 do new <- not `fmap` (doesFileExist $ out </> "IdrisDoc")
389 existing_nss <- existingNamespaces out
390 let nss = S.union (M.keysSet nsd) existing_nss
391 dExists <- doesDirectoryExist out
392 if new && dExists then err $ "Output directory (" ++ out ++ ") is" ++
393 " already in use for other than IdrisDoc."
395 createDirectoryIfMissing True out
396 foldl docGen (return ()) (M.toList nsd)
398 -- Create an empty IdrisDoc file to signal 'out' is used for IdrisDoc
399 if new -- But only if it not already existed...
400 then withFile (out </> "IdrisDoc") WriteMode ((flip hPutStr) "")
405 where docGen io (n, c) = do io; createNsDoc ist n c out
408-- | (Over)writes the 'index.html' file in the given directory with
409-- an (updated) index of namespaces in the documentation
410createIndex :: S.Set NsName -- ^ Set of namespace names to
411 -- include in the index
412 -> FilePath -- ^ The base directory to which
413 -- documentation will be written.
416 do (path, h) <- openTempFile out "index.html"
417 BS2.hPut h $ renderHtml $ wrapper Nothing $ do
419 H.ul ! class_ "names" $ do
420 let path ns = "docs" </> genRelNsPath ns "html"
421 item ns = do let n = toHtml $ nsName2Str ns
422 link = toValue $ path ns
423 H.li $ H.a ! href link ! class_ "code" $ n
424 sort = L.sortBy (\n1 n2 -> reverse n1 `compare` reverse n2)
425 forM_ (sort $ S.toList nss) item
427 renameFile path (out </> "index.html")
430-- | Generates a HTML file for a namespace and its contents.
431-- The location for e.g. Prelude.Algebra is <base>/Prelude/Algebra.html
432createNsDoc :: IState -- ^ Needed to determine the types of names
433 -> NsName -- ^ The name of the namespace to
434 -- create documentation for
435 -> NsInfo -- ^ The contents of the namespace
436 -> FilePath -- ^ The base directory to which
437 -- documentation will be written.
439createNsDoc ist ns content out =
440 do let tpath = out </> "docs" </> (genRelNsPath ns "html")
441 dir = takeDirectory tpath
442 file = takeFileName tpath
443 haveDocs (_, Just d, _) = [d]
445 -- We cannot do anything without a Doc
446 content' = concatMap haveDocs (nsContents content)
447 createDirectoryIfMissing True dir
448 (path, h) <- openTempFile dir file
449 BS2.hPut h $ renderHtml $ wrapper (Just ns) $ do
450 H.h1 $ toHtml (nsName2Str ns)
451 case nsDocstring content of
453 Just docstring -> Docstrings.renderHtml docstring
454 H.dl ! class_ "decls" $ forM_ content' (createOtherDoc ist)
456 renameFile path tpath
459-- | Generates a relative filepath for a namespace, appending an extension
460genRelNsPath :: NsName -- ^ Namespace to generate a path for
461 -> String -- ^ Extension suffix
463genRelNsPath ns suffix = nsName2Str ns <.> suffix
466-- | Generates a HTML type signature with proper tags
467-- TODO: Turn docstrings into title attributes more robustly
468genTypeHeader :: IState -- ^ Needed to determine the types of names
469 -> FunDoc -- ^ Type to generate type declaration for
470 -> H.Html -- ^ Resulting HTML
471genTypeHeader ist (FD n _ args ftype _) = do
472 H.span ! class_ (toValue $ "name " ++ getType n)
473 ! title (toValue $ show n)
474 $ toHtml $ name $ nsroot n
475 H.span ! class_ "word" $ do nbsp; ":"; nbsp
476 H.span ! class_ "signature" $ preEscapedToHtml htmlSignature
479 htmlSignature = displayDecorated decorator $ renderCompact signature
480 signature = pprintPTerm defaultPPOption [] names (idris_infixes ist) ftype
481 names = [ n | (n@(UN n'), _, _, _) <- args,
482 not (T.isPrefixOf (txt "__") n') ]
484 decorator (AnnConst c) str | constIsType c = htmlSpan str "type" str
485 | otherwise = htmlSpan str "data" str
486 decorator (AnnData _ _) str = htmlSpan str "data" str
487 decorator (AnnType _ _) str = htmlSpan str "type" str
488 decorator AnnKeyword str = htmlSpan "" "keyword" str
489 decorator (AnnBoundName n i) str | Just t <- M.lookup n docs =
490 let cs = (if i then "implicit " else "") ++ "documented boundvar"
492 decorator (AnnBoundName _ i) str =
493 let cs = (if i then "implicit " else "") ++ "boundvar"
494 in htmlSpan "" cs str
495 decorator (AnnName n _ _ _) str
496 | filterName n = htmlLink (show n) (getType n) (link n) str
497 | otherwise = htmlSpan "" (getType n) str
498 decorator (AnnTextFmt BoldText) str = "<b>" ++ str ++ "</b>"
499 decorator (AnnTextFmt UnderlineText) str = "<u>" ++ str ++ "</u>"
500 decorator (AnnTextFmt ItalicText) str = "<i>" ++ str ++ "</i>"
501 decorator _ str = str
503 htmlSpan :: String -> String -> String -> String
504 htmlSpan t cs str = do
505 R.renderHtml $ H.span ! class_ (toValue cs)
508 htmlLink :: String -> String -> String -> String -> String
509 htmlLink t cs a str = do
510 R.renderHtml $ H.a ! class_ (toValue cs)
511 ! title (toValue t) ! href (toValue a)
514 docs = M.fromList $ mapMaybe docExtractor args
515 docExtractor (_, _, _, Nothing) = Nothing
516 docExtractor (n, _, _, Just d) = Just (n, doc2Str d)
517 -- TODO: Remove <p> tags more robustly
518 doc2Str d = let dirty = renderMarkup $ contents $ Docstrings.renderHtml $ d
519 in take (length dirty - 8) $ drop 3 dirty
521 name (NS n ns) = show (NS (sUN $ name n) ns)
522 name n = let n' = show n
523 in if (head n') `elem` opChars
527 link n = let path = genRelNsPath (getNs n) "html"
528 in path ++ "#" ++ (show n)
530 getType :: Name -> String
531 getType n = let ctxt = tt_ctxt ist
533 _ | isDConName n ctxt -> "constructor"
534 _ | isFnName n ctxt -> "function"
535 _ | isTConName n ctxt -> "type"
538-- | Generates HTML documentation for a function.
539createFunDoc :: IState -- ^ Needed to determine the types of names
540 -> FunDoc -- ^ Function to generate block for
541 -> H.Html -- ^ Resulting HTML
542createFunDoc ist fd@(FD name docstring args ftype fixity) = do
543 H.dt ! (A.id $ toValue $ show name) $ genTypeHeader ist fd
545 (if nullDocstring docstring then Empty else Docstrings.renderHtml docstring)
546 let args' = filter (\(_, _, _, d) -> isJust d) args
547 if (not $ null args') || (isJust fixity)
549 if (isJust fixity) then do
550 H.dt ! class_ "fixity" $ "Fixity"
551 let f = fromJust fixity
552 H.dd ! class_ "fixity" ! title (toValue $ show f) $ genFix f
557 where genFix (Infixl {prec=p}) =
558 toHtml $ "Left associative, precedence " ++ show p
559 genFix (Infixr {prec=p}) =
560 toHtml $ "Left associative, precedence " ++ show p
561 genFix (InfixN {prec=p}) =
562 toHtml $ "Non-associative, precedence " ++ show p
563 genFix (PrefixN {prec=p}) =
564 toHtml $ "Prefix, precedence " ++ show p
565 genArg (_, _, _, Nothing) = Empty
566 genArg (name, _, _, Just docstring) = do
567 H.dt $ toHtml $ show name
568 H.dd $ Docstrings.renderHtml docstring
571-- | Generates HTML documentation for any Docs type
572-- TODO: Generate actual signatures for typeclasses
573createOtherDoc :: IState -- ^ Needed to determine the types of names
574 -> Docs -- ^ Namespace item to generate HTML block for
575 -> H.Html -- ^ Resulting HTML
576createOtherDoc ist (FunDoc fd) = createFunDoc ist fd
578createOtherDoc ist (ClassDoc n docstring fds _ _ _ _) = do
579 H.dt ! (A.id $ toValue $ show n) $ do
580 H.span ! class_ "word" $ do "class"; nbsp
581 H.span ! class_ "name type"
582 ! title (toValue $ show n)
583 $ toHtml $ name $ nsroot n
584 H.span ! class_ "signature" $ nbsp
586 (if nullDocstring docstring then Empty else Docstrings.renderHtml docstring)
587 H.dl ! class_ "decls" $ forM_ fds (createFunDoc ist)
589 where name (NS n ns) = show (NS (sUN $ name n) ns)
590 name n = let n' = show n
591 in if (head n') `elem` opChars
595createOtherDoc ist (DataDoc fd@(FD n docstring args _ _) fds) = do
596 H.dt ! (A.id $ toValue $ show n) $ do
597 H.span ! class_ "word" $ do "data"; nbsp
600 (if nullDocstring docstring then Empty else Docstrings.renderHtml docstring)
601 let args' = filter (\(_, _, _, d) -> isJust d) args
603 then H.dl $ forM_ args' genArg
605 H.dl ! class_ "decls" $ forM_ fds (createFunDoc ist)
607 where genArg (_, _, _, Nothing) = Empty
608 genArg (name, _, _, Just docstring) = do
609 H.dt $ toHtml $ show name
610 H.dd $ Docstrings.renderHtml docstring
612createOtherDoc ist (ModDoc _ docstring) = do
613 Docstrings.renderHtml docstring
615-- | Generates everything but the actual content of the page
616wrapper :: Maybe NsName -- ^ Namespace name, unless it is the index
617 -> H.Html -- ^ Inner HTML
620 let (index, str) = extract ns
621 base = if index then "" else "../"
622 styles = base ++ "styles.css" :: String
623 indexPage = base ++ "index.html" :: String
624 in H.docTypeHtml $ do
628 if index then " Index" else do
631 H.link ! type_ "text/css" ! rel "stylesheet"
632 ! href (toValue styles)
633 H.body ! class_ (if index then "index" else "namespace") $ do
634 H.div ! class_ "wrapper" $ do
637 if index then Empty else do
640 H.nav $ H.a ! href (toValue indexPage) $ "Index"
641 H.div ! class_ "container" $ inner
643 "Produced by IdrisDoc version "
646 where extract (Just ns) = (False, nsName2Str ns)
647 extract _ = (True, "")
650-- | Non-break space character
652nbsp = preEscapedToHtml (" " :: String)
655-- | Returns a list of namespaces already documented in a IdrisDoc directory
656existingNamespaces :: FilePath -- ^ The base directory containing the
657 -- 'docs' directory with existing
660existingNamespaces out = do
661 let docs = out </> "docs"
662 str2Ns s | s == rootNsStr = []
663 str2Ns s = reverse $ T.splitOn (T.singleton '.') (txt s)
664 toNs fp = do isFile <- doesFileExist $ docs </> fp
665 let isHtml = ".html" == takeExtension fp
666 name = dropExtension fp
668 return $ if isFile && isHtml then Just ns else Nothing
669 docsExists <- doesDirectoryExist docs
672 else do contents <- getDirectoryContents docs
673 namespaces <- catMaybes `fmap` (sequence $ map toNs contents)
674 return $ S.fromList namespaces
677-- | Copies IdrisDoc dependencies such as stylesheets to a directory
678copyDependencies :: FilePath -- ^ The base directory to which
679 -- dependencies should be written
681copyDependencies dir =
682 do styles <- getDataFileName $ "idrisdoc" </> "styles.css"
683 copyFile styles (dir </> "styles.css")
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