on master help sign in
Merge pull request #1112 from PhilipRasmussen/idrisdoc
70e9dc9Edwin Brady
src/Idris/IdrisDoc.hs+41−70
@@ -83,12 +83,6 @@ type NsItem = (Name, Maybe Docs, Accessibility)
83type NsInfo = [NsItem]
83type NsInfo = [NsItem]
84type NsDict = M.Map NsName NsInfo
84type NsDict = M.Map NsName NsInfo
85
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 ]
86-- --------------------------------------------------------------- [ Utility ]
93
87
94-- | Make an error message
88-- | Make an error message
@@ -291,14 +285,21 @@ extractPTermNames (PUnifyLog p) = extract p
291extractPTermNames (PNoImplicits p) = extract p
285extractPTermNames (PNoImplicits p) = extract p
292extractPTermNames _ = []
286extractPTermNames _ = []
293
287
288+-- | Shorter name for extractPTermNames
289+extract :: PTerm -- ^ Where to extract names from
290+ -> [Name] -- ^ Extracted names
294extract = extractPTermNames
291extract = extractPTermNames
295
292
293+-- | Helper function for extractPTermNames
294+extractPArg :: PArg -> [Name]
296extractPArg (PImp {pname=n, getTm=p}) = n : extract p
295extractPArg (PImp {pname=n, getTm=p}) = n : extract p
297extractPArg (PExp {getTm=p}) = extract p
296extractPArg (PExp {getTm=p}) = extract p
298extractPArg (PConstraint {getTm=p}) = extract p
297extractPArg (PConstraint {getTm=p}) = extract p
299extractPArg (PTacImplicit {pname=n, getScript=p1, getTm=p2})
298extractPArg (PTacImplicit {pname=n, getScript=p1, getTm=p2})
300 = n : (concatMap extract [p1, p2])
299 = n : (concatMap extract [p1, p2])
301
300
301+-- | Helper function for extractPTermNames
302+extractPDo :: PDo -> [Name]
302extractPDo (DoExp _ p) = extract p
303extractPDo (DoExp _ p) = extract p
303extractPDo (DoBind _ n p) = n : extract p
304extractPDo (DoBind _ n p) = n : extract p
304extractPDo (DoBindP _ p1 p2 ps) = let (ps1, ps2) = unzip ps
305extractPDo (DoBindP _ p1 p2 ps) = let (ps1, ps2) = unzip ps
@@ -307,6 +308,8 @@ extractPDo (DoBindP _ p1 p2 ps) = let (ps1, ps2) = unzip ps
307extractPDo (DoLet _ n p1 p2) = n : concatMap extract [p1, p2]
308extractPDo (DoLet _ n p1 p2) = n : concatMap extract [p1, p2]
308extractPDo (DoLetP _ p1 p2) = concatMap extract [p1, p2]
309extractPDo (DoLetP _ p1 p2) = concatMap extract [p1, p2]
309
310
311+-- | Helper function for extractPTermNames
312+extractPTactic :: PTactic -> [Name]
310extractPTactic (Intro ns) = ns
313extractPTactic (Intro ns) = ns
311extractPTactic (Focus n) = [n]
314extractPTactic (Focus n) = [n]
312extractPTactic (Refine n _) = [n]
315extractPTactic (Refine n _) = [n]
@@ -345,10 +348,9 @@ createDocs :: IState -- ^ Needed to determine the types of names
345 -- documentation will be written.
348 -- documentation will be written.
346 -> IO (Failable ())
349 -> IO (Failable ())
347createDocs ist nsd out =
350createDocs ist nsd out =
348− do docInfo <- readDocInfo out
351+ do new <- not `fmap` (doesFileExist $ out </> "IdrisDoc")
349− let (new, docInfo') = case docInfo of Nothing -> (True, DocInfo S.empty)
352+ existing_nss <- existingNamespaces out
350− Just di -> (False, di)
351− nss = S.union (M.keysSet nsd) (namespaces docInfo')
353+ let nss = S.union (M.keysSet nsd) existing_nss
352 dExists <- doesDirectoryExist out
354 dExists <- doesDirectoryExist out
353 if new && dExists then err $ "Output directory (" ++ out ++ ") is" ++
355 if new && dExists then err $ "Output directory (" ++ out ++ ") is" ++
354 " already in use for other than IdrisDoc."
356 " already in use for other than IdrisDoc."
@@ -356,7 +358,10 @@ createDocs ist nsd out =
356 createDirectoryIfMissing True out
358 createDirectoryIfMissing True out
357 foldl docGen (return ()) (M.toList nsd)
359 foldl docGen (return ()) (M.toList nsd)
358 createIndex nss out
360 createIndex nss out
359− writeDocInfo out (docInfo' { namespaces = nss })
361+ -- Create an empty IdrisDoc file to signal 'out' is used for IdrisDoc
362+ if new -- But only if it not already existed...
363+ then withFile (out </> "IdrisDoc") WriteMode ((flip hPutStr) "")
364+ else return ()
360 copyDependencies out
365 copyDependencies out
361 return $ Right ()
366 return $ Right ()
362
367
@@ -607,66 +612,32 @@ nbsp :: H.Html
607nbsp = preEscapedToHtml ("&nbsp;" :: String)
612nbsp = preEscapedToHtml ("&nbsp;" :: String)
608
613
609
614
615+-- | Returns a list of namespaces already documented in a IdrisDoc directory
616+existingNamespaces :: FilePath -- ^ The base directory containing the
617+ -- 'docs' directory with existing
618+ -- namespace pages
619+ -> IO (S.Set NsName)
620+existingNamespaces out = do
621+ let docs = out </> "docs"
622+ str2Ns s | s == rootNsStr = []
623+ str2Ns s = reverse $ T.splitOn (T.singleton '.') (txt s)
624+ toNs fp = do isFile <- doesFileExist $ docs </> fp
625+ let isHtml = ".html" == takeExtension fp
626+ name = dropExtension fp
627+ ns = str2Ns name
628+ return $ if isFile && isHtml then Just ns else Nothing
629+ docsExists <- doesDirectoryExist docs
630+ if not docsExists
631+ then return S.empty
632+ else do contents <- getDirectoryContents docs
633+ namespaces <- catMaybes `fmap` (sequence $ map toNs contents)
634+ return $ S.fromList namespaces
635+
636+
610-- | Copies IdrisDoc dependencies such as stylesheets to a directory
637-- | Copies IdrisDoc dependencies such as stylesheets to a directory
611−copyDependencies :: FilePath
638+copyDependencies :: FilePath -- ^ The base directory to which
639+ -- dependencies should be written
612 -> IO ()
640 -> IO ()
613copyDependencies dir =
641copyDependencies dir =
614 do styles <- getDataFileName $ "idrisdoc" </> "styles.css"
642 do styles <- getDataFileName $ "idrisdoc" </> "styles.css"
615− copyFile styles (dir </> "styles.css")
643+ 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 = "docs" </> (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
test/idrisdoc004/run+1−1
@@ -1,5 +1,5 @@
1#!/usr/bin/env bash
1#!/usr/bin/env bash
2−# Tests that documentation is generated for type classes
2+# Tests that documentation is generated for typeclasses
3idris --mkdoc test_typeclasses.ipkg
3idris --mkdoc test_typeclasses.ipkg
4[ -d test_typeclasses_doc ] && echo "Typeclasses are documented"
4[ -d test_typeclasses_doc ] && echo "Typeclasses are documented"
5rm -rf *.ibc *_doc
5rm -rf *.ibc *_doc
test/idrisdoc006/run+10−1
@@ -4,5 +4,14 @@ idris --mkdoc package_a.ipkg
4idris --mkdoc package_b.ipkg
4idris --mkdoc package_b.ipkg
5[ -f test_merge_doc/docs/A.html ] && echo "A: Check"
5[ -f test_merge_doc/docs/A.html ] && echo "A: Check"
6[ -f test_merge_doc/docs/B.html ] && echo "B: Check"
6[ -f test_merge_doc/docs/B.html ] && echo "B: Check"
7−cat test_merge_doc/IdrisDoc
7+if grep -q "href\\=\"docs/A\\.html\"" test_merge_doc/index.html; then
8+ echo A
9+else
10+ echo A is not in the index
11+fi
12+if grep -q "href\\=\"docs/B\\.html\"" test_merge_doc/index.html; then
13+ echo B
14+else
15+ echo B is not in the index
16+fi
8rm -rf *.ibc *_doc
17rm -rf *.ibc *_doc