Skip to content
This repository was archived by the owner on Aug 3, 2024. It is now read-only.

Commit c5a83df

Browse files
authored
Render module tree per package in the content page (#1492)
* Render module tree per package in the content page When rendering content page for multiple packages it is useful to split the module tree per package. Package names in this patch are inferred from haddock's interface file names. * Write PackageInfo into interface file To keep interface file format backward compatible, instead of using `Binary` instance for `InterfaceFile` we introduce functions to serialise and deserialise, which depends on the interface file version.
1 parent f53f298 commit c5a83df

File tree

4 files changed

+199
-53
lines changed

4 files changed

+199
-53
lines changed

haddock-api/src/Haddock.hs

Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{-# LANGUAGE CPP #-}
22
{-# LANGUAGE LambdaCase #-}
3+
{-# LANGUAGE NamedFieldPuns #-}
34
{-# LANGUAGE OverloadedStrings #-}
45
{-# LANGUAGE Rank2Types #-}
56
{-# LANGUAGE ScopedTypeVariables #-}
@@ -199,11 +200,17 @@ haddockWithGhc ghc args = handleTopExceptions $ do
199200

200201
if not (null files) then do
201202
(packages, ifaces, homeLinks) <- readPackagesAndProcessModules flags files
203+
let packageInfo = PackageInfo { piPackageName =
204+
fromMaybe (PackageName mempty) (optPackageName flags)
205+
, piPackageVersion =
206+
fromMaybe (makeVersion []) (optPackageVersion flags)
207+
}
202208

203209
-- Dump an "interface file" (.haddock file), if requested.
204210
forM_ (optDumpInterfaceFile flags) $ \path -> liftIO $ do
205211
writeInterfaceFile path InterfaceFile {
206212
ifInstalledIfaces = map toInstalledIface ifaces
213+
, ifPackageInfo = packageInfo
207214
, ifLinkEnv = homeLinks
208215
}
209216

@@ -277,9 +284,9 @@ renderStep logger dflags unit_state flags sinceQual nameQual pkgs interfaces = d
277284
, ifaceFile)) pkgs)
278285
let
279286
installedIfaces =
280-
concatMap
287+
map
281288
(\(_, showModules, ifaceFilePath, ifaceFile)
282-
-> (showModules,ifaceFilePath,) <$> ifInstalledIfaces ifaceFile)
289+
-> (ifaceFilePath, mkPackageInterfaces showModules ifaceFile))
283290
pkgs
284291
extSrcMap = Map.fromList $ do
285292
((_, Just path), _, _, ifile) <- pkgs
@@ -296,10 +303,16 @@ renderStep logger dflags unit_state flags sinceQual nameQual pkgs interfaces = d
296303

297304
-- | Render the interfaces with whatever backend is specified in the flags.
298305
render :: Logger -> DynFlags -> UnitState -> [Flag] -> SinceQual -> QualOption -> [Interface]
299-
-> [(Visibility, FilePath, InstalledInterface)] -> Map Module FilePath -> IO ()
300-
render logger dflags unit_state flags sinceQual qual ifaces installedIfaces extSrcMap = do
306+
-> [(FilePath, PackageInterfaces)] -> Map Module FilePath -> IO ()
307+
render logger dflags unit_state flags sinceQual qual ifaces packages extSrcMap = do
301308

302309
let
310+
packageInfo = PackageInfo { piPackageName = fromMaybe (PackageName mempty)
311+
$ optPackageName flags
312+
, piPackageVersion = fromMaybe (makeVersion [])
313+
$ optPackageVersion flags
314+
}
315+
303316
title = fromMaybe "" (optTitle flags)
304317
unicode = Flag_UseUnicode `elem` flags
305318
pretty = Flag_PrettyHtml `elem` flags
@@ -317,10 +330,32 @@ render logger dflags unit_state flags sinceQual qual ifaces installedIfaces extS
317330

318331
visibleIfaces = [ i | i <- ifaces, OptHide `notElem` ifaceOptions i ]
319332

320-
-- /All/ visible interfaces including external package modules.
321-
allIfaces = map ((Visible,) . toInstalledIface) ifaces
322-
++ map (\(showModules,_,iface) -> (showModules,iface)) installedIfaces
323-
allVisibleIfaces = [ i | (Visible, i) <- allIfaces, OptHide `notElem` instOptions i ]
333+
-- /All/ interfaces including external package modules, grouped by
334+
-- interface file (package).
335+
allPackages :: [PackageInterfaces]
336+
allPackages = [PackageInterfaces
337+
{ piPackageInfo = packageInfo
338+
, piVisibility = Visible
339+
, piInstalledInterfaces = map toInstalledIface ifaces
340+
}]
341+
++ map snd packages
342+
343+
-- /All/ visible interfaces including external package modules, grouped by
344+
-- interface file (package).
345+
allVisiblePackages :: [PackageInterfaces]
346+
allVisiblePackages = [ pinfo { piInstalledInterfaces =
347+
filter (\i -> OptHide `notElem` instOptions i)
348+
piInstalledInterfaces
349+
}
350+
| pinfo@PackageInterfaces
351+
{ piVisibility = Visible
352+
, piInstalledInterfaces
353+
} <- allPackages
354+
]
355+
356+
-- /All/ installed interfaces.
357+
allInstalledIfaces :: [InstalledInterface]
358+
allInstalledIfaces = concatMap (piInstalledInterfaces . snd) packages
324359

325360
pkgMod = fmap ifaceMod (listToMaybe ifaces)
326361
pkgKey = fmap moduleUnit pkgMod
@@ -364,7 +399,7 @@ render logger dflags unit_state flags sinceQual qual ifaces installedIfaces extS
364399
sourceUrls' = (srcBase, srcModule', pkgSrcMap', pkgSrcLMap')
365400

366401
installedMap :: Map Module InstalledInterface
367-
installedMap = Map.fromList [ (unwire (instMod iface), iface) | (_, _, iface) <- installedIfaces ]
402+
installedMap = Map.fromList [ (unwire (instMod iface), iface) | iface <- allInstalledIfaces ]
368403

369404
-- The user gives use base-4.9.0.0, but the InstalledInterface
370405
-- records the *wired in* identity base. So untranslate it
@@ -400,7 +435,7 @@ render logger dflags unit_state flags sinceQual qual ifaces installedIfaces extS
400435
_ <- {-# SCC ppHtmlIndex #-}
401436
ppHtmlIndex odir title pkgStr
402437
themes opt_mathjax opt_contents_url sourceUrls' opt_wiki_urls
403-
allVisibleIfaces pretty
438+
(concatMap piInstalledInterfaces allVisiblePackages) pretty
404439
return ()
405440

406441
unless withBaseURL $
@@ -411,7 +446,7 @@ render logger dflags unit_state flags sinceQual qual ifaces installedIfaces extS
411446
_ <- {-# SCC ppHtmlContents #-}
412447
ppHtmlContents unit_state odir title pkgStr
413448
themes opt_mathjax opt_index_url sourceUrls' opt_wiki_urls
414-
allVisibleIfaces True prologue pretty
449+
allVisiblePackages True prologue pretty
415450
sincePkg (makeContentsQual qual)
416451
return ()
417452
copyHtmlBits odir libDir themes withQuickjump
@@ -421,18 +456,18 @@ render logger dflags unit_state flags sinceQual qual ifaces installedIfaces extS
421456
unicode Nothing qual
422457
ifaces
423458
( nub
424-
. map (\(_,a,_) -> a)
425-
. filter (\(v,_,_) -> v == Visible)
426-
$ installedIfaces)
459+
. map fst
460+
. filter ((== Visible) . piVisibility . snd)
461+
$ packages)
427462

428463
when (Flag_Html `elem` flags) $ do
429464
withTiming logger dflags' "ppHtml" (const ()) $ do
430465
_ <- {-# SCC ppHtml #-}
431466
ppHtml unit_state title pkgStr visibleIfaces reexportedIfaces odir
432467
prologue
433468
themes opt_mathjax sourceUrls' opt_wiki_urls opt_base_url
434-
opt_contents_url opt_index_url unicode sincePkg qual
435-
pretty withQuickjump
469+
opt_contents_url opt_index_url unicode sincePkg packageInfo
470+
qual pretty withQuickjump
436471
return ()
437472
unless withBaseURL $ do
438473
copyHtmlBits odir libDir themes withQuickjump
@@ -496,7 +531,8 @@ readInterfaceFiles name_cache_accessor pairs bypass_version_check = do
496531
putStrLn (" " ++ err)
497532
putStrLn "Skipping this interface."
498533
return Nothing
499-
Right f -> return (Just (paths, showModules, file, f))
534+
Right f ->
535+
return (Just (paths, showModules, file, f ))
500536

501537

502538
-------------------------------------------------------------------------------

haddock-api/src/Haddock/Backends/Xhtml.hs

Lines changed: 65 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ import Haddock.Backends.Xhtml.Names
2828
import Haddock.Backends.Xhtml.Themes
2929
import Haddock.Backends.Xhtml.Types
3030
import Haddock.Backends.Xhtml.Utils
31+
import Haddock.InterfaceFile (PackageInfo (..), PackageInterfaces (..), ppPackageInfo)
3132
import Haddock.ModuleTree
33+
import Haddock.Options (Visibility (..))
3234
import Haddock.Types
3335
import Haddock.Version
3436
import Haddock.Utils
@@ -78,6 +80,7 @@ ppHtml :: UnitState
7880
-> Maybe String -- ^ The index URL (--use-index)
7981
-> Bool -- ^ Whether to use unicode in output (--use-unicode)
8082
-> Maybe String -- ^ Package name
83+
-> PackageInfo -- ^ Package info
8184
-> QualOption -- ^ How to qualify names
8285
-> Bool -- ^ Output pretty html (newlines and indenting)
8386
-> Bool -- ^ Also write Quickjump index
@@ -86,15 +89,20 @@ ppHtml :: UnitState
8689
ppHtml state doctitle maybe_package ifaces reexported_ifaces odir prologue
8790
themes maybe_mathjax_url maybe_source_url maybe_wiki_url
8891
maybe_base_url maybe_contents_url maybe_index_url unicode
89-
pkg qual debug withQuickjump = do
92+
pkg packageInfo qual debug withQuickjump = do
9093
let
9194
visible_ifaces = filter visible ifaces
9295
visible i = OptHide `notElem` ifaceOptions i
9396

9497
when (isNothing maybe_contents_url) $
9598
ppHtmlContents state odir doctitle maybe_package
9699
themes maybe_mathjax_url maybe_index_url maybe_source_url maybe_wiki_url
97-
(map toInstalledIface visible_ifaces ++ reexported_ifaces)
100+
[PackageInterfaces
101+
{ piPackageInfo = packageInfo
102+
, piVisibility = Visible
103+
, piInstalledInterfaces = map toInstalledIface visible_ifaces
104+
++ reexported_ifaces
105+
}]
98106
False -- we don't want to display the packages in a single-package contents
99107
prologue debug pkg (makeContentsQual qual)
100108

@@ -277,30 +285,42 @@ ppHtmlContents
277285
-> Maybe String
278286
-> SourceURLs
279287
-> WikiURLs
280-
-> [InstalledInterface] -> Bool -> Maybe (MDoc GHC.RdrName)
288+
-> [PackageInterfaces] -> Bool -> Maybe (MDoc GHC.RdrName)
281289
-> Bool
282290
-> Maybe Package -- ^ Current package
283291
-> Qualification -- ^ How to qualify names
284292
-> IO ()
285293
ppHtmlContents state odir doctitle _maybe_package
286294
themes mathjax_url maybe_index_url
287-
maybe_source_url maybe_wiki_url ifaces showPkgs prologue debug pkg qual = do
288-
let tree = mkModuleTree state showPkgs
289-
[(instMod iface, toInstalledDescription iface)
290-
| iface <- ifaces
291-
, not (instIsSig iface)]
292-
sig_tree = mkModuleTree state showPkgs
293-
[(instMod iface, toInstalledDescription iface)
294-
| iface <- ifaces
295-
, instIsSig iface]
295+
maybe_source_url maybe_wiki_url packages showPkgs prologue debug pkg qual = do
296+
let trees =
297+
[ ( piPackageInfo pinfo
298+
, mkModuleTree state showPkgs
299+
[(instMod iface, toInstalledDescription iface)
300+
| iface <- piInstalledInterfaces pinfo
301+
, not (instIsSig iface)
302+
]
303+
)
304+
| pinfo <- packages
305+
]
306+
sig_trees =
307+
[ ( piPackageInfo pinfo
308+
, mkModuleTree state showPkgs
309+
[(instMod iface, toInstalledDescription iface)
310+
| iface <- piInstalledInterfaces pinfo
311+
, instIsSig iface
312+
]
313+
)
314+
| pinfo <- packages
315+
]
296316
html =
297317
headHtml doctitle themes mathjax_url Nothing +++
298318
bodyHtml doctitle Nothing
299319
maybe_source_url maybe_wiki_url
300320
Nothing maybe_index_url << [
301321
ppPrologue pkg qual doctitle prologue,
302-
ppSignatureTree pkg qual sig_tree,
303-
ppModuleTree pkg qual tree
322+
ppSignatureTrees pkg qual sig_trees,
323+
ppModuleTrees pkg qual trees
304324
]
305325
createDirectoryIfMissing True odir
306326
writeUtf8File (joinPath [odir, contentsHtmlFile]) (renderToString debug html)
@@ -315,17 +335,37 @@ ppPrologue _ _ _ Nothing = noHtml
315335
ppPrologue pkg qual title (Just doc) =
316336
divDescription << (h1 << title +++ docElement thediv (rdrDocToHtml pkg qual doc))
317337

318-
319-
ppSignatureTree :: Maybe Package -> Qualification -> [ModuleTree] -> Html
320-
ppSignatureTree _ _ [] = mempty
321-
ppSignatureTree pkg qual ts =
322-
divModuleList << (sectionName << "Signatures" +++ mkNodeList pkg qual [] "n" ts)
323-
324-
325-
ppModuleTree :: Maybe Package -> Qualification -> [ModuleTree] -> Html
326-
ppModuleTree _ _ [] = mempty
327-
ppModuleTree pkg qual ts =
328-
divModuleList << (sectionName << "Modules" +++ mkNodeList pkg qual [] "n" ts)
338+
ppSignatureTrees :: Maybe Package -> Qualification -> [(PackageInfo, [ModuleTree])] -> Html
339+
ppSignatureTrees _ _ tss | all (null . snd) tss = mempty
340+
ppSignatureTrees pkg qual [(info, ts)] =
341+
divPackageList << (sectionName << "Signatures" +++ ppSignatureTree pkg qual "n" info ts)
342+
ppSignatureTrees pkg qual tss =
343+
divModuleList <<
344+
(sectionName << "Signatures"
345+
+++ concatHtml [ ppSignatureTree pkg qual("n."++show i++".") info ts
346+
| (i, (info, ts)) <- zip [(1::Int)..] tss
347+
])
348+
349+
ppSignatureTree :: Maybe Package -> Qualification -> String -> PackageInfo -> [ModuleTree] -> Html
350+
ppSignatureTree _ _ _ _ [] = mempty
351+
ppSignatureTree pkg qual p info ts =
352+
divModuleList << (sectionName << ppPackageInfo info +++ mkNodeList pkg qual [] p ts)
353+
354+
ppModuleTrees :: Maybe Package -> Qualification -> [(PackageInfo, [ModuleTree])] -> Html
355+
ppModuleTrees _ _ tss | all (null . snd) tss = mempty
356+
ppModuleTrees pkg qual [(info, ts)] =
357+
divModuleList << (sectionName << "Modules" +++ ppModuleTree pkg qual "n" info ts)
358+
ppModuleTrees pkg qual tss =
359+
divPackageList <<
360+
(sectionName << "Packages"
361+
+++ concatHtml [ppModuleTree pkg qual ("n."++show i++".") info ts
362+
| (i, (info, ts)) <- zip [(1::Int)..] tss
363+
])
364+
365+
ppModuleTree :: Maybe Package -> Qualification -> String -> PackageInfo -> [ModuleTree] -> Html
366+
ppModuleTree _ _ _ _ [] = mempty
367+
ppModuleTree pkg qual p info ts =
368+
divModuleList << (sectionName << ppPackageInfo info +++ mkNodeList pkg qual [] p ts)
329369

330370

331371
mkNodeList :: Maybe Package -> Qualification -> [String] -> String -> [ModuleTree] -> Html

haddock-api/src/Haddock/Backends/Xhtml/Layout.hs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ module Haddock.Backends.Xhtml.Layout (
1515

1616
divPackageHeader, divContent, divModuleHeader, divFooter,
1717
divTableOfContents, divDescription, divSynopsis, divInterface,
18-
divIndex, divAlphabet, divModuleList, divContentsList,
18+
divIndex, divAlphabet, divPackageList, divModuleList, divContentsList,
1919

2020
sectionName,
2121
nonEmptySectionName,
@@ -81,7 +81,7 @@ nonEmptySectionName c
8181

8282
divPackageHeader, divContent, divModuleHeader, divFooter,
8383
divTableOfContents, divDescription, divSynopsis, divInterface,
84-
divIndex, divAlphabet, divModuleList, divContentsList
84+
divIndex, divAlphabet, divPackageList, divModuleList, divContentsList
8585
:: Html -> Html
8686

8787
divPackageHeader = sectionDiv "package-header"
@@ -96,6 +96,7 @@ divInterface = sectionDiv "interface"
9696
divIndex = sectionDiv "index"
9797
divAlphabet = sectionDiv "alphabet"
9898
divModuleList = sectionDiv "module-list"
99+
divPackageList = sectionDiv "module-list"
99100

100101

101102
--------------------------------------------------------------------------------

0 commit comments

Comments
 (0)