From a7dcf13bfbb97b20e75cc8ce650e2bb628db4660 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Fri, 17 May 2024 11:34:42 -0400 Subject: [PATCH] Reformat with fourmolu Using previously-added configuration and `fourmolu -i .` Note that we exclude the test-cases (`./{hoogle,html-hypsrc,latex}-test`) as they are sensitive to formatting. --- haddock-api/src/Documentation/Haddock.hs | 113 +- haddock-api/src/Haddock/Backends/HaddockDB.hs | 5 +- haddock-api/src/Haddock/Backends/Hoogle.hs | 501 ++-- .../src/Haddock/Backends/Hyperlinker.hs | 143 +- .../Haddock/Backends/Hyperlinker/Parser.hs | 610 ++--- .../Haddock/Backends/Hyperlinker/Renderer.hs | 265 +- .../src/Haddock/Backends/Hyperlinker/Types.hs | 54 +- .../src/Haddock/Backends/Hyperlinker/Utils.hs | 76 +- haddock-api/src/Haddock/Backends/LaTeX.hs | 1603 ++++++------ haddock-api/src/Haddock/Backends/Xhtml.hs | 1526 ++++++----- .../src/Haddock/Backends/Xhtml/Decl.hs | 2233 ++++++++++------- .../src/Haddock/Backends/Xhtml/DocMarkup.hs | 312 ++- .../src/Haddock/Backends/Xhtml/Layout.hs | 358 +-- .../src/Haddock/Backends/Xhtml/Meta.hs | 13 +- .../src/Haddock/Backends/Xhtml/Names.hs | 122 +- .../src/Haddock/Backends/Xhtml/Themes.hs | 117 +- .../src/Haddock/Backends/Xhtml/Types.hs | 26 +- .../src/Haddock/Backends/Xhtml/Utils.hs | 217 +- haddock-api/src/Haddock/Convert.hs | 1336 +++++----- haddock-api/src/Haddock/Doc.hs | 27 +- haddock-api/src/Haddock/GhcUtils.hs | 799 +++--- .../src/Haddock/Interface/AttachInstances.hs | 388 +-- haddock-api/src/Haddock/Interface/Create.hs | 1068 ++++---- haddock-api/src/Haddock/Interface/Json.hs | 187 +- .../src/Haddock/Interface/LexParseRn.hs | 131 +- .../Haddock/Interface/ParseModuleHeader.hs | 162 +- haddock-api/src/Haddock/Interface/Rename.hs | 840 ++++--- .../src/Haddock/Interface/RenameType.hs | 96 +- haddock-api/src/Haddock/InterfaceFile.hs | 833 +++--- haddock-api/src/Haddock/ModuleTree.hs | 67 +- haddock-api/src/Haddock/Options.hs | 635 +++-- haddock-api/src/Haddock/Parser.hs | 47 +- haddock-api/src/Haddock/Types.hs | 1061 ++++---- haddock-api/src/Haddock/Utils.hs | 270 +- haddock-api/src/Haddock/Utils/Json.hs | 449 ++-- haddock-api/src/Haddock/Utils/Json/Parser.hs | 115 +- haddock-api/src/Haddock/Utils/Json/Types.hs | 29 +- haddock-api/src/Haddock/Version.hs | 17 +- .../Backends/Hyperlinker/ParserSpec.hs | 292 ++- haddock-library/Setup.hs | 1 + haddock-library/fixtures/Fixtures.hs | 155 +- haddock-library/src/CompatPrelude.hs | 7 +- .../src/Documentation/Haddock/Doc.hs | 55 +- .../src/Documentation/Haddock/Markup.hs | 160 +- .../src/Documentation/Haddock/Parser.hs | 513 ++-- .../Haddock/Parser/Identifier.hs | 175 +- .../src/Documentation/Haddock/Parser/Monad.hs | 120 +- .../src/Documentation/Haddock/Parser/Util.hs | 39 +- .../src/Documentation/Haddock/Types.hs | 140 +- .../Documentation/Haddock/Parser/UtilSpec.hs | 3 +- .../test/Documentation/Haddock/ParserSpec.hs | 1100 ++++---- haddock-test/src/Test/Haddock.hs | 215 +- haddock-test/src/Test/Haddock/Process.hs | 42 +- haddock-test/src/Test/Haddock/Utils.hs | 34 +- haddock-test/src/Test/Haddock/Xhtml.hs | 111 +- 55 files changed, 11095 insertions(+), 8918 deletions(-) diff --git a/haddock-api/src/Documentation/Haddock.hs b/haddock-api/src/Documentation/Haddock.hs index d14cdaa29b..297dc5ea67 100644 --- a/haddock-api/src/Documentation/Haddock.hs +++ b/haddock-api/src/Documentation/Haddock.hs @@ -1,4 +1,7 @@ ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Documentation.Haddock -- Copyright : (c) David Waern 2010 @@ -10,79 +13,79 @@ -- -- The Haddock API: A rudimentary, highly experimental API exposing some of -- the internals of Haddock. Don't expect it to be stable. ------------------------------------------------------------------------------ -module Documentation.Haddock ( - - -- * Interface - Interface(..), - InstalledInterface(..), - toInstalledIface, - createInterfaces, - processModules, +module Documentation.Haddock + ( -- * Interface + Interface (..) + , InstalledInterface (..) + , toInstalledIface + , createInterfaces + , processModules - -- * Export items & declarations - ExportItem(..), - DocForDecl, - FnArgsDoc, + -- * Export items & declarations + , ExportItem (..) + , DocForDecl + , FnArgsDoc - -- * Cross-referencing - LinkEnv, - DocName(..), + -- * Cross-referencing + , LinkEnv + , DocName (..) - -- * Instances - DocInstance, - InstHead, + -- * Instances + , DocInstance + , InstHead - -- * Documentation comments - Doc, - MDoc, - DocH(..), - Example(..), - Hyperlink(..), - DocMarkup, - DocMarkupH(..), - Documentation(..), - ArgMap, - WarningMap, - DocMap, - HaddockModInfo(..), - markup, + -- * Documentation comments + , Doc + , MDoc + , DocH (..) + , Example (..) + , Hyperlink (..) + , DocMarkup + , DocMarkupH (..) + , Documentation (..) + , ArgMap + , WarningMap + , DocMap + , HaddockModInfo (..) + , markup - -- * Interface files - InterfaceFile(..), - readInterfaceFile, - freshNameCache, + -- * Interface files + , InterfaceFile (..) + , readInterfaceFile + , freshNameCache - -- * Flags and options - Flag(..), - DocOption(..), + -- * Flags and options + , Flag (..) + , DocOption (..) - -- * Error handling - HaddockException(..), + -- * Error handling + , HaddockException (..) - -- * Program entry point - haddock, - haddockWithGhc, - getGhcDirs, - withGhc -) where + -- * Program entry point + , haddock + , haddockWithGhc + , getGhcDirs + , withGhc + ) where import Documentation.Haddock.Markup (markup) -import Haddock.InterfaceFile +import Haddock import Haddock.Interface -import Haddock.Types +import Haddock.InterfaceFile import Haddock.Options -import Haddock - +import Haddock.Types -- | Create 'Interface' structures from a given list of Haddock command-line -- flags and file or module names (as accepted by 'haddock' executable). Flags -- that control documentation generation or show help or version information -- are ignored. createInterfaces - :: [Flag] -- ^ A list of command-line flags - -> [String] -- ^ File or module names - -> IO [Interface] -- ^ Resulting list of interfaces + :: [Flag] + -- ^ A list of command-line flags + -> [String] + -- ^ File or module names + -> IO [Interface] + -- ^ Resulting list of interfaces createInterfaces flags modules = do (_, ifaces, _) <- withGhc flags (readPackagesAndProcessModules flags modules) return ifaces diff --git a/haddock-api/src/Haddock/Backends/HaddockDB.hs b/haddock-api/src/Haddock/Backends/HaddockDB.hs index 6c48804aea..abdcecb69a 100644 --- a/haddock-api/src/Haddock/Backends/HaddockDB.hs +++ b/haddock-api/src/Haddock/Backends/HaddockDB.hs @@ -1,4 +1,7 @@ ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.Backends.HaddockDB -- Copyright : (c) Simon Marlow 2003 @@ -7,7 +10,6 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------ module Haddock.Backends.HaddockDB (ppDocBook) where {- @@ -23,6 +25,7 @@ import Text.PrettyPrint ppDocBook :: a ppDocBook = error "not working" + {- ppDocBook :: FilePath -> [(Module, Interface)] -> String ppDocBook odir mods = render (ppIfaces mods) diff --git a/haddock-api/src/Haddock/Backends/Hoogle.hs b/haddock-api/src/Haddock/Backends/Hoogle.hs index 6625701c40..775ce98a5a 100644 --- a/haddock-api/src/Haddock/Backends/Hoogle.hs +++ b/haddock-api/src/Haddock/Backends/Hoogle.hs @@ -2,6 +2,9 @@ {-# LANGUAGE TypeFamilies #-} ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.Backends.Hoogle -- Copyright : (c) Neil Mitchell 2006-2008 @@ -13,9 +16,8 @@ -- -- Write out Hoogle compatible documentation -- http://www.haskell.org/hoogle/ ------------------------------------------------------------------------------ -module Haddock.Backends.Hoogle ( - -- * Main entry point to Hoogle output generation +module Haddock.Backends.Hoogle + ( -- * Main entry point to Hoogle output generation ppHoogle -- * Utilities for generating Hoogle output during interface creation @@ -30,11 +32,11 @@ import Haddock.Utils hiding (out) import GHC import GHC.Core.InstEnv import GHC.Driver.Ppr -import GHC.Plugins (TopLevelFlag(..)) +import GHC.Plugins (TopLevelFlag (..)) import GHC.Types.SourceText +import GHC.Unit.State import GHC.Utils.Outputable as Outputable import GHC.Utils.Panic -import GHC.Unit.State import Data.Char import Data.Foldable (toList) @@ -46,90 +48,94 @@ import System.Directory import System.FilePath prefix :: [String] -prefix = ["-- Hoogle documentation, generated by Haddock" - ,"-- See Hoogle, http://www.haskell.org/hoogle/" - ,""] - +prefix = + [ "-- Hoogle documentation, generated by Haddock" + , "-- See Hoogle, http://www.haskell.org/hoogle/" + , "" + ] ppHoogle :: DynFlags -> UnitState -> String -> Version -> String -> Maybe (Doc RdrName) -> [Interface] -> FilePath -> IO () ppHoogle dflags unit_state package version synopsis prologue ifaces odir = do - let -- Since Hoogle is line based, we want to avoid breaking long lines. - dflags' = dflags{ pprCols = maxBound } - filename = package ++ ".txt" - contents = prefix ++ - docWith dflags' (drop 2 $ dropWhile (/= ':') synopsis) prologue ++ - ["@package " ++ package] ++ - ["@version " ++ showVersion version - | not (null (versionBranch version)) - ] ++ - concat [ppModule dflags' unit_state i | i <- ifaces, OptHide `notElem` ifaceOptions i] - createDirectoryIfMissing True odir - writeUtf8File (odir filename) (unlines contents) + let + -- Since Hoogle is line based, we want to avoid breaking long lines. + dflags' = dflags{pprCols = maxBound} + filename = package ++ ".txt" + contents = + prefix + ++ docWith dflags' (drop 2 $ dropWhile (/= ':') synopsis) prologue + ++ ["@package " ++ package] + ++ [ "@version " ++ showVersion version + | not (null (versionBranch version)) + ] + ++ concat [ppModule dflags' unit_state i | i <- ifaces, OptHide `notElem` ifaceOptions i] + createDirectoryIfMissing True odir + writeUtf8File (odir filename) (unlines contents) ppModule :: DynFlags -> UnitState -> Interface -> [String] ppModule dflags unit_state iface = - "" : ppDocumentation dflags (ifaceDoc iface) ++ - ["module " ++ moduleString (ifaceMod iface)] ++ - concatMap ppExportItem (ifaceRnExportItems $ iface) ++ - concatMap (ppInstance dflags unit_state) (ifaceInstances iface) + "" + : ppDocumentation dflags (ifaceDoc iface) + ++ ["module " ++ moduleString (ifaceMod iface)] + ++ concatMap ppExportItem (ifaceRnExportItems $ iface) + ++ concatMap (ppInstance dflags unit_state) (ifaceInstances iface) -- | If the export item is an 'ExportDecl', get the attached Hoogle textual -- database entries for that export declaration. ppExportItem :: ExportItem DocNameI -> [String] -ppExportItem (ExportDecl RnExportD { rnExpDHoogle = o }) = o -ppExportItem _ = [] +ppExportItem (ExportDecl RnExportD{rnExpDHoogle = o}) = o +ppExportItem _ = [] --------------------------------------------------------------------- -- Utility functions dropHsDocTy :: HsSigType GhcRn -> HsSigType GhcRn dropHsDocTy = drop_sig_ty - where - drop_sig_ty (HsSig x a b) = HsSig x a (drop_lty b) - drop_sig_ty x@XHsSigType{} = x - - drop_lty (L src x) = L src (drop_ty x) - - drop_ty (HsForAllTy x a e) = HsForAllTy x a (drop_lty e) - drop_ty (HsQualTy x a e) = HsQualTy x a (drop_lty e) - drop_ty (HsBangTy x a b) = HsBangTy x a (drop_lty b) - drop_ty (HsAppTy x a b) = HsAppTy x (drop_lty a) (drop_lty b) - drop_ty (HsAppKindTy x a b) = HsAppKindTy x (drop_lty a) (drop_lty b) - drop_ty (HsFunTy x w a b) = HsFunTy x w (drop_lty a) (drop_lty b) - drop_ty (HsListTy x a) = HsListTy x (drop_lty a) - drop_ty (HsTupleTy x a b) = HsTupleTy x a (map drop_lty b) - drop_ty (HsOpTy x p a b c) = HsOpTy x p (drop_lty a) b (drop_lty c) - drop_ty (HsParTy x a) = HsParTy x (drop_lty a) - drop_ty (HsKindSig x a b) = HsKindSig x (drop_lty a) b - drop_ty (HsDocTy _ a _) = drop_ty $ unL a - drop_ty x = x + where + drop_sig_ty (HsSig x a b) = HsSig x a (drop_lty b) + drop_sig_ty x@XHsSigType{} = x + + drop_lty (L src x) = L src (drop_ty x) + + drop_ty (HsForAllTy x a e) = HsForAllTy x a (drop_lty e) + drop_ty (HsQualTy x a e) = HsQualTy x a (drop_lty e) + drop_ty (HsBangTy x a b) = HsBangTy x a (drop_lty b) + drop_ty (HsAppTy x a b) = HsAppTy x (drop_lty a) (drop_lty b) + drop_ty (HsAppKindTy x a b) = HsAppKindTy x (drop_lty a) (drop_lty b) + drop_ty (HsFunTy x w a b) = HsFunTy x w (drop_lty a) (drop_lty b) + drop_ty (HsListTy x a) = HsListTy x (drop_lty a) + drop_ty (HsTupleTy x a b) = HsTupleTy x a (map drop_lty b) + drop_ty (HsOpTy x p a b c) = HsOpTy x p (drop_lty a) b (drop_lty c) + drop_ty (HsParTy x a) = HsParTy x (drop_lty a) + drop_ty (HsKindSig x a b) = HsKindSig x (drop_lty a) b + drop_ty (HsDocTy _ a _) = drop_ty $ unL a + drop_ty x = x outHsSigType :: DynFlags -> HsSigType GhcRn -> String outHsSigType dflags = out dflags . reparenSigType . dropHsDocTy dropComment :: String -> String -dropComment (' ':'-':'-':' ':_) = [] -dropComment (x:xs) = x : dropComment xs +dropComment (' ' : '-' : '-' : ' ' : _) = [] +dropComment (x : xs) = x : dropComment xs dropComment [] = [] outWith :: Outputable a => (SDoc -> String) -> a -> [Char] outWith p = - f + f . unwords . map (dropWhile isSpace) . lines . p . ppr where - f xs | " " `isPrefixOf` xs = f $ drop 19 xs - f (x:xs) = x : f xs - f [] = [] + f xs | " " `isPrefixOf` xs = f $ drop 19 xs + f (x : xs) = x : f xs + f [] = [] out :: Outputable a => DynFlags -> a -> String out dflags = outWith $ showSDoc dflags operator :: String -> String -operator (x:xs) | not (isAlphaNum x) && x `notElem` "_' ([{" = '(' : x:xs ++ ")" +operator (x : xs) | not (isAlphaNum x) && x `notElem` "_' ([{" = '(' : x : xs ++ ")" operator x = x commaSeparate :: Outputable a => DynFlags -> [a] -> String @@ -139,65 +145,69 @@ commaSeparate dflags = showSDoc dflags . interpp'SP -- How to print each export ppExportD :: DynFlags -> ExportD GhcRn -> [String] -ppExportD dflags - ExportD - { expDDecl = L _ decl - , expDPats = bundledPats - , expDMbDoc = mbDoc - , expDSubDocs = subdocs - , expDFixities = fixities - } - = concat +ppExportD + dflags + ExportD + { expDDecl = L _ decl + , expDPats = bundledPats + , expDMbDoc = mbDoc + , expDSubDocs = subdocs + , expDFixities = fixities + } = + concat [ ppDocumentation dflags' dc ++ f d | (d, (dc, _)) <- (decl, mbDoc) : bundledPats - ] ++ ppFixities - where - -- Since Hoogle is line based, we want to avoid breaking long lines. - dflags' :: DynFlags - dflags' = dflags{ pprCols = maxBound } - - f :: HsDecl GhcRn -> [String] - f (TyClD _ d@DataDecl{}) = ppData dflags' d subdocs - f (TyClD _ d@SynDecl{}) = ppSynonym dflags' d - f (TyClD _ d@ClassDecl{}) = ppClass dflags' d subdocs - f (TyClD _ (FamDecl _ d)) = ppFam dflags' d - f (ForD _ (ForeignImport _ name typ _)) = [pp_sig dflags' [name] typ] - f (ForD _ (ForeignExport _ name typ _)) = [pp_sig dflags' [name] typ] - f (SigD _ sig) = ppSig dflags' sig - f _ = [] - - ppFixities :: [String] - ppFixities = concatMap (ppFixity dflags') fixities - + ] + ++ ppFixities + where + -- Since Hoogle is line based, we want to avoid breaking long lines. + dflags' :: DynFlags + dflags' = dflags{pprCols = maxBound} + + f :: HsDecl GhcRn -> [String] + f (TyClD _ d@DataDecl{}) = ppData dflags' d subdocs + f (TyClD _ d@SynDecl{}) = ppSynonym dflags' d + f (TyClD _ d@ClassDecl{}) = ppClass dflags' d subdocs + f (TyClD _ (FamDecl _ d)) = ppFam dflags' d + f (ForD _ (ForeignImport _ name typ _)) = [pp_sig dflags' [name] typ] + f (ForD _ (ForeignExport _ name typ _)) = [pp_sig dflags' [name] typ] + f (SigD _ sig) = ppSig dflags' sig + f _ = [] + + ppFixities :: [String] + ppFixities = concatMap (ppFixity dflags') fixities ppSigWithDoc :: DynFlags -> Sig GhcRn -> [(Name, DocForDecl Name)] -> [String] ppSigWithDoc dflags sig subdocs = case sig of - TypeSig _ names t -> concatMap (mkDocSig "" (dropWildCards t)) names - PatSynSig _ names t -> concatMap (mkDocSig "pattern " t) names - _ -> [] + TypeSig _ names t -> concatMap (mkDocSig "" (dropWildCards t)) names + PatSynSig _ names t -> concatMap (mkDocSig "pattern " t) names + _ -> [] where - mkDocSig leader typ n = mkSubdocN dflags n subdocs - [leader ++ pp_sig dflags [n] typ] + mkDocSig leader typ n = + mkSubdocN + dflags + n + subdocs + [leader ++ pp_sig dflags [n] typ] ppSig :: DynFlags -> Sig GhcRn -> [String] -ppSig dflags x = ppSigWithDoc dflags x [] +ppSig dflags x = ppSigWithDoc dflags x [] pp_sig :: DynFlags -> [LocatedN Name] -> LHsSigType GhcRn -> String -pp_sig dflags names (L _ typ) = - operator prettyNames ++ " :: " ++ outHsSigType dflags typ - where - prettyNames = intercalate ", " $ map (out dflags) names - - +pp_sig dflags names (L _ typ) = + operator prettyNames ++ " :: " ++ outHsSigType dflags typ + where + prettyNames = intercalate ", " $ map (out dflags) names -- note: does not yet output documentation for class methods ppClass :: DynFlags -> TyClDecl GhcRn -> [(Name, DocForDecl Name)] -> [String] -ppClass dflags decl@(ClassDecl {}) subdocs = - (ppDecl ++ ppTyFams) : ppMethods +ppClass dflags decl@(ClassDecl{}) subdocs = + (ppDecl ++ ppTyFams) : ppMethods where ppDecl :: String ppDecl = - out dflags + out + dflags decl { tcdSigs = [] , tcdATs = [] @@ -214,22 +224,28 @@ ppClass dflags decl@(ClassDecl {}) subdocs = ppTyFams :: String ppTyFams - | null $ tcdATs decl = "" - | otherwise = (" " ++) . showSDoc dflags . whereWrapper $ concat - [ map pprTyFam (tcdATs decl) - , map (pprTyFamInstDecl NotTopLevel . unLoc) (tcdATDefs decl) - ] + | null $ tcdATs decl = "" + | otherwise = + (" " ++) . showSDoc dflags . whereWrapper $ + concat + [ map pprTyFam (tcdATs decl) + , map (pprTyFamInstDecl NotTopLevel . unLoc) (tcdATDefs decl) + ] pprTyFam :: LFamilyDecl GhcRn -> SDoc - pprTyFam (L _ at) = vcat' $ map text $ - mkSubdocN dflags - (fdLName at) - subdocs - -- Associated type families should not be printed as top-level - -- (avoid printing the `family` keyword) - (ppFam dflags at{fdTopLevel = NotTopLevel}) - - whereWrapper elems = vcat' + pprTyFam (L _ at) = + vcat' $ + map text $ + mkSubdocN + dflags + (fdLName at) + subdocs + -- Associated type families should not be printed as top-level + -- (avoid printing the `family` keyword) + (ppFam dflags at{fdTopLevel = NotTopLevel}) + + whereWrapper elems = + vcat' [ text "where" <+> lbrace , nest 4 . vcat . map (Outputable.<> semi) $ elems , rbrace @@ -237,14 +253,14 @@ ppClass dflags decl@(ClassDecl {}) subdocs = ppClass _ _non_cls_decl _ = [] ppFam :: DynFlags -> FamilyDecl GhcRn -> [String] -ppFam dflags decl@(FamilyDecl { fdInfo = info }) - = [out dflags decl'] +ppFam dflags decl@(FamilyDecl{fdInfo = info}) = + [out dflags decl'] where decl' = case info of - -- We don't need to print out a closed type family's equations - -- for Hoogle, so pretend it doesn't have any. - ClosedTypeFamily{} -> decl { fdInfo = OpenTypeFamily } - _ -> decl + -- We don't need to print out a closed type family's equations + -- for Hoogle, so pretend it doesn't have any. + ClosedTypeFamily{} -> decl{fdInfo = OpenTypeFamily} + _ -> decl ppInstance :: DynFlags -> UnitState -> ClsInst -> [String] ppInstance dflags unit_state x = @@ -255,16 +271,22 @@ ppInstance dflags unit_state x = -- safety information to a state where the Outputable instance -- produces no output which means no overlap and unsafe (or [safe] -- is generated). - cls = x { is_flag = OverlapFlag { overlapMode = NoOverlap NoSourceText - , isSafeOverlap = False } } + cls = + x + { is_flag = + OverlapFlag + { overlapMode = NoOverlap NoSourceText + , isSafeOverlap = False + } + } ppSynonym :: DynFlags -> TyClDecl GhcRn -> [String] ppSynonym dflags x = [out dflags x] ppData :: DynFlags -> TyClDecl GhcRn -> [(Name, DocForDecl Name)] -> [String] -ppData dflags decl@DataDecl { tcdLName = name, tcdTyVars = tvs, tcdFixity = fixity, tcdDataDefn = defn } subdocs - = out dflags (ppDataDefnHeader (pp_vanilla_decl_head name tvs fixity) defn) : - concatMap (ppCtor dflags decl subdocs . unLoc) (dd_cons defn) +ppData dflags decl@DataDecl{tcdLName = name, tcdTyVars = tvs, tcdFixity = fixity, tcdDataDefn = defn} subdocs = + out dflags (ppDataDefnHeader (pp_vanilla_decl_head name tvs fixity) defn) + : concatMap (ppCtor dflags decl subdocs . unLoc) (dd_cons defn) ppData _ _ _ = panic "ppData" -- | for constructors, and named-fields... @@ -274,64 +296,77 @@ lookupCon dflags subdocs (L _ name) = case lookup name subdocs of _ -> [] ppCtor :: DynFlags -> TyClDecl GhcRn -> [(Name, DocForDecl Name)] -> ConDecl GhcRn -> [String] -ppCtor dflags dat subdocs con@ConDeclH98 { con_args = con_args' } +ppCtor dflags dat subdocs con@ConDeclH98{con_args = con_args'} = -- AZ:TODO get rid of the concatMap - = concatMap (lookupCon dflags subdocs) [con_name con] ++ f con_args' - where - f (PrefixCon _ args) = [typeSig name $ (map hsScaledThing args) ++ [resType]] - f (InfixCon a1 a2) = f $ PrefixCon [] [a1,a2] - f (RecCon (L _ recs)) = f (PrefixCon [] $ map (hsLinear . cd_fld_type . unLoc) recs) ++ concat - [(concatMap (lookupCon dflags subdocs . noLocA . foExt . unLoc) (cd_fld_names r)) ++ - [out dflags (map (foExt . unLoc) $ cd_fld_names r) `typeSig` [resType, cd_fld_type r]] - | r <- map unLoc recs] - - funs = foldr1 (\x y -> reL $ HsFunTy noExtField (HsUnrestrictedArrow noExtField) x y) - apps = foldl1 (\x y -> reL $ HsAppTy noExtField x y) - - typeSig nm flds = operator nm ++ " :: " ++ - outHsSigType dflags (unL $ mkEmptySigType $ funs flds) - - -- We print the constructors as comma-separated list. See GHC - -- docs for con_names on why it is a list to begin with. - name = commaSeparate dflags . toList $ unL <$> getConNames con - - tyVarArg (UserTyVar _ _ n) = HsTyVar noAnn NotPromoted n - tyVarArg (KindedTyVar _ _ n lty) = HsKindSig noAnn (reL (HsTyVar noAnn NotPromoted n)) lty - tyVarArg _ = panic "ppCtor" - - resType = apps $ map reL $ - (HsTyVar noAnn NotPromoted (reL (tcdName dat))) : - map (tyVarArg . unLoc) (hsQTvExplicit $ tyClDeclTyVars dat) - -ppCtor dflags _dat subdocs (ConDeclGADT { con_names = names - , con_bndrs = L _ outer_bndrs - , con_mb_cxt = mcxt - , con_g_args = args - , con_res_ty = res_ty }) - = concatMap (lookupCon dflags subdocs) names ++ [typeSig] + concatMap (lookupCon dflags subdocs) [con_name con] ++ f con_args' + where + f (PrefixCon _ args) = [typeSig name $ (map hsScaledThing args) ++ [resType]] + f (InfixCon a1 a2) = f $ PrefixCon [] [a1, a2] + f (RecCon (L _ recs)) = + f (PrefixCon [] $ map (hsLinear . cd_fld_type . unLoc) recs) + ++ concat + [ (concatMap (lookupCon dflags subdocs . noLocA . foExt . unLoc) (cd_fld_names r)) + ++ [out dflags (map (foExt . unLoc) $ cd_fld_names r) `typeSig` [resType, cd_fld_type r]] + | r <- map unLoc recs + ] + + funs = foldr1 (\x y -> reL $ HsFunTy noExtField (HsUnrestrictedArrow noExtField) x y) + apps = foldl1 (\x y -> reL $ HsAppTy noExtField x y) + + typeSig nm flds = + operator nm + ++ " :: " + ++ outHsSigType dflags (unL $ mkEmptySigType $ funs flds) + + -- We print the constructors as comma-separated list. See GHC + -- docs for con_names on why it is a list to begin with. + name = commaSeparate dflags . toList $ unL <$> getConNames con + + tyVarArg (UserTyVar _ _ n) = HsTyVar noAnn NotPromoted n + tyVarArg (KindedTyVar _ _ n lty) = HsKindSig noAnn (reL (HsTyVar noAnn NotPromoted n)) lty + tyVarArg _ = panic "ppCtor" + + resType = + apps $ + map reL $ + (HsTyVar noAnn NotPromoted (reL (tcdName dat))) + : map (tyVarArg . unLoc) (hsQTvExplicit $ tyClDeclTyVars dat) +ppCtor + dflags + _dat + subdocs + ( ConDeclGADT + { con_names = names + , con_bndrs = L _ outer_bndrs + , con_mb_cxt = mcxt + , con_g_args = args + , con_res_ty = res_ty + } + ) = + concatMap (lookupCon dflags subdocs) names ++ [typeSig] where - typeSig = operator name ++ " :: " ++ outHsSigType dflags con_sig_ty - name = out dflags $ unL <$> names - con_sig_ty = HsSig noExtField outer_bndrs theta_ty where + typeSig = operator name ++ " :: " ++ outHsSigType dflags con_sig_ty + name = out dflags $ unL <$> names + con_sig_ty = HsSig noExtField outer_bndrs theta_ty + where theta_ty = case mcxt of - Just theta -> noLocA (HsQualTy { hst_xqual = noExtField, hst_ctxt = theta, hst_body = tau_ty }) + Just theta -> noLocA (HsQualTy{hst_xqual = noExtField, hst_ctxt = theta, hst_body = tau_ty}) Nothing -> tau_ty tau_ty = foldr mkFunTy res_ty $ - case args of PrefixConGADT _ pos_args -> map hsScaledThing pos_args - RecConGADT _ (L _ flds) -> map (cd_fld_type . unL) flds + case args of + PrefixConGADT _ pos_args -> map hsScaledThing pos_args + RecConGADT _ (L _ flds) -> map (cd_fld_type . unL) flds mkFunTy a b = noLocA (HsFunTy noExtField (HsUnrestrictedArrow noExtField) a b) ppFixity :: DynFlags -> (Name, Fixity) -> [String] ppFixity dflags (name, fixity) = [out dflags ((FixitySig NoNamespaceSpecifier [noLocA name] fixity) :: FixitySig GhcRn)] - --------------------------------------------------------------------- -- DOCUMENTATION ppDocumentation :: Outputable o => DynFlags -> Documentation o -> [String] ppDocumentation dflags (Documentation d w) = mdoc dflags d ++ doc dflags w - doc :: Outputable o => DynFlags -> Maybe (Doc o) -> [String] doc dflags = docWith dflags "" @@ -340,21 +375,23 @@ mdoc dflags = docWith dflags "" . fmap _doc docWith :: Outputable o => DynFlags -> String -> Maybe (Doc o) -> [String] docWith _ [] Nothing = [] -docWith dflags header d - = ("":) $ zipWith (++) ("-- | " : repeat "-- ") $ - lines header ++ ["" | header /= "" && isJust d] ++ - maybe [] (showTags . markup (markupTag dflags)) d +docWith dflags header d = + ("" :) $ + zipWith (++) ("-- | " : repeat "-- ") $ + lines header + ++ ["" | header /= "" && isJust d] + ++ maybe [] (showTags . markup (markupTag dflags)) d mkSubdocN :: DynFlags -> LocatedN Name -> [(Name, DocForDecl Name)] -> [String] -> [String] mkSubdocN dflags n subdocs s = mkSubdoc dflags (la2la n) subdocs s mkSubdoc :: DynFlags -> LocatedA Name -> [(Name, DocForDecl Name)] -> [String] -> [String] mkSubdoc dflags n subdocs s = concatMap (ppDocumentation dflags) getDoc ++ s - where - getDoc = maybe [] (return . fst) (lookup (unLoc n) subdocs) + where + getDoc = maybe [] (return . fst) (lookup (unLoc n) subdocs) data Tag = TagL Char [Tags] | TagP Tags | TagPre Tags | TagInline String Tags | Str String - deriving Show + deriving (Show) type Tags = [Tag] @@ -372,98 +409,94 @@ str a = [Str a] -- entities (&,>,<) should always be appropriately escaped markupTag :: Outputable o => DynFlags -> DocMarkup o [Tag] -markupTag dflags = Markup { - markupParagraph = box TagP, - markupEmpty = str "", - markupString = str, - markupAppend = (++), - markupIdentifier = box (TagInline "a") . str . out dflags, - markupIdentifierUnchecked = box (TagInline "a") . str . showWrapped (out dflags . snd), - markupModule = \(ModLink m label) -> box (TagInline "a") (fromMaybe (str m) label), - markupWarning = box (TagInline "i"), - markupEmphasis = box (TagInline "i"), - markupBold = box (TagInline "b"), - markupMonospaced = box (TagInline "tt"), - markupPic = const $ str " ", - markupMathInline = const $ str "", - markupMathDisplay = const $ str "", - markupUnorderedList = box (TagL 'u'), - markupOrderedList = box (TagL 'o') . map snd, - markupDefList = box (TagL 'u') . map (\(a,b) -> TagInline "i" a : Str " " : b), - markupCodeBlock = box TagPre, - markupHyperlink = \(Hyperlink url mLabel) -> box (TagInline "a") (fromMaybe (str url) mLabel), - markupAName = const $ str "", - markupProperty = box TagPre . str, - markupExample = box TagPre . str . unlines . map exampleToString, - markupHeader = \(Header l h) -> box (TagInline $ "h" ++ show l) h, - markupTable = \(Table _ _) -> str "TODO: table" - } - +markupTag dflags = + Markup + { markupParagraph = box TagP + , markupEmpty = str "" + , markupString = str + , markupAppend = (++) + , markupIdentifier = box (TagInline "a") . str . out dflags + , markupIdentifierUnchecked = box (TagInline "a") . str . showWrapped (out dflags . snd) + , markupModule = \(ModLink m label) -> box (TagInline "a") (fromMaybe (str m) label) + , markupWarning = box (TagInline "i") + , markupEmphasis = box (TagInline "i") + , markupBold = box (TagInline "b") + , markupMonospaced = box (TagInline "tt") + , markupPic = const $ str " " + , markupMathInline = const $ str "" + , markupMathDisplay = const $ str "" + , markupUnorderedList = box (TagL 'u') + , markupOrderedList = box (TagL 'o') . map snd + , markupDefList = box (TagL 'u') . map (\(a, b) -> TagInline "i" a : Str " " : b) + , markupCodeBlock = box TagPre + , markupHyperlink = \(Hyperlink url mLabel) -> box (TagInline "a") (fromMaybe (str url) mLabel) + , markupAName = const $ str "" + , markupProperty = box TagPre . str + , markupExample = box TagPre . str . unlines . map exampleToString + , markupHeader = \(Header l h) -> box (TagInline $ "h" ++ show l) h + , markupTable = \(Table _ _) -> str "TODO: table" + } showTags :: [Tag] -> [String] showTags = intercalate [""] . map showBlock - showBlock :: Tag -> [String] showBlock (TagP xs) = showInline xs -showBlock (TagL t xs) = ['<':t:"l>"] ++ mid ++ ['<':'/':t:"l>"] - where mid = concatMap (showInline . box (TagInline "li")) xs +showBlock (TagL t xs) = ['<' : t : "l>"] ++ mid ++ ['<' : '/' : t : "l>"] + where + mid = concatMap (showInline . box (TagInline "li")) xs showBlock (TagPre xs) = ["
"] ++ showPre xs ++ ["
"] showBlock x = showInline [x] - asInline :: Tag -> Tags asInline (TagP xs) = xs asInline (TagPre xs) = [TagInline "pre" xs] -asInline (TagL t xs) = [TagInline (t:"l") $ map (TagInline "li") xs] +asInline (TagL t xs) = [TagInline (t : "l") $ map (TagInline "li") xs] asInline x = [x] - showInline :: [Tag] -> [String] showInline = unwordsWrap 70 . words . concatMap f - where - fs = concatMap f - f (Str x) = escape x - f (TagInline s xs) = "<"++s++">" ++ (if s == "li" then trim else id) (fs xs) ++ "" - f x = fs $ asInline x - - trim = dropWhile isSpace . reverse . dropWhile isSpace . reverse + where + fs = concatMap f + f (Str x) = escape x + f (TagInline s xs) = "<" ++ s ++ ">" ++ (if s == "li" then trim else id) (fs xs) ++ "" + f x = fs $ asInline x + trim = dropWhile isSpace . reverse . dropWhile isSpace . reverse showPre :: [Tag] -> [String] showPre = trimFront . trimLines . lines . concatMap f - where - trimLines = dropWhile null . reverse . dropWhile null . reverse - trimFront xs = map (drop i) xs - where - ns = [length a | x <- xs, let (a,b) = span isSpace x, b /= ""] - i = if null ns then 0 else minimum ns - - fs = concatMap f - f (Str x) = escape x - f (TagInline s xs) = "<"++s++">" ++ fs xs ++ "" - f x = fs $ asInline x + where + trimLines = dropWhile null . reverse . dropWhile null . reverse + trimFront xs = map (drop i) xs + where + ns = [length a | x <- xs, let (a, b) = span isSpace x, b /= ""] + i = if null ns then 0 else minimum ns + fs = concatMap f + f (Str x) = escape x + f (TagInline s xs) = "<" ++ s ++ ">" ++ fs xs ++ "" + f x = fs $ asInline x unwordsWrap :: Int -> [String] -> [String] unwordsWrap n = f n [] - where - f _ s [] = [g s | s /= []] - f i s (x:xs) | nx > i = g s : f (n - nx - 1) [x] xs - | otherwise = f (i - nx - 1) (x:s) xs - where nx = length x - - g = unwords . reverse + where + f _ s [] = [g s | s /= []] + f i s (x : xs) + | nx > i = g s : f (n - nx - 1) [x] xs + | otherwise = f (i - nx - 1) (x : s) xs + where + nx = length x + g = unwords . reverse escape :: String -> String escape = concatMap f - where - f '<' = "<" - f '>' = ">" - f '&' = "&" - f x = [x] - + where + f '<' = "<" + f '>' = ">" + f '&' = "&" + f x = [x] -- | Just like 'vcat' but uses '($+$)' instead of '($$)'. vcat' :: [SDoc] -> SDoc diff --git a/haddock-api/src/Haddock/Backends/Hyperlinker.hs b/haddock-api/src/Haddock/Backends/Hyperlinker.hs index 84ccaf60e2..3c29ec0866 100644 --- a/haddock-api/src/Haddock/Backends/Hyperlinker.hs +++ b/haddock-api/src/Haddock/Backends/Hyperlinker.hs @@ -1,54 +1,60 @@ {-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternSynonyms #-} -module Haddock.Backends.Hyperlinker - ( ppHyperlinkedSource - , module Haddock.Backends.Hyperlinker.Types - , module Haddock.Backends.Hyperlinker.Utils - ) where +module Haddock.Backends.Hyperlinker + ( ppHyperlinkedSource + , module Haddock.Backends.Hyperlinker.Types + , module Haddock.Backends.Hyperlinker.Utils + ) where -import Haddock.Types -import Haddock.Utils (writeUtf8File, out, verbose, Verbosity) -import Haddock.InterfaceFile -import Haddock.Backends.Hyperlinker.Renderer import Haddock.Backends.Hyperlinker.Parser +import Haddock.Backends.Hyperlinker.Renderer import Haddock.Backends.Hyperlinker.Types import Haddock.Backends.Hyperlinker.Utils -import Haddock.Backends.Xhtml.Utils ( renderToString ) +import Haddock.Backends.Xhtml.Utils (renderToString) +import Haddock.InterfaceFile +import Haddock.Types +import Haddock.Utils (Verbosity, out, verbose, writeUtf8File) import Data.Maybe import System.Directory import System.FilePath -import GHC.Iface.Ext.Types ( pattern HiePath, HieFile(..), HieASTs(..), HieAST(..), SourcedNodeInfo(..) ) -import GHC.Iface.Ext.Binary ( readHieFile, hie_file_result ) -import GHC.Types.SrcLoc ( realSrcLocSpan, mkRealSrcLoc, srcSpanFile ) import Data.Map as M -import GHC.Data.FastString ( mkFastString ) -import GHC.Unit.Module ( Module, moduleName ) - +import GHC.Data.FastString (mkFastString) +import GHC.Iface.Ext.Binary (hie_file_result, readHieFile) +import GHC.Iface.Ext.Types (HieAST (..), HieASTs (..), HieFile (..), SourcedNodeInfo (..), pattern HiePath) +import GHC.Types.SrcLoc (mkRealSrcLoc, realSrcLocSpan, srcSpanFile) +import GHC.Unit.Module (Module, moduleName) -- | Generate hyperlinked source for given interfaces. -- -- Note that list of interfaces should also contain interfaces normally hidden -- when generating documentation. Otherwise this could lead to dead links in -- produced source. -ppHyperlinkedSource :: Verbosity - -> FilePath -- ^ Output directory - -> FilePath -- ^ Resource directory - -> Maybe FilePath -- ^ Custom CSS file path - -> Bool -- ^ Flag indicating whether to pretty-print HTML - -> M.Map Module SrcPath -- ^ Paths to sources - -> [Interface] -- ^ Interfaces for which we create source - -> IO () +ppHyperlinkedSource + :: Verbosity + -> FilePath + -- ^ Output directory + -> FilePath + -- ^ Resource directory + -> Maybe FilePath + -- ^ Custom CSS file path + -> Bool + -- ^ Flag indicating whether to pretty-print HTML + -> M.Map Module SrcPath + -- ^ Paths to sources + -> [Interface] + -- ^ Interfaces for which we create source + -> IO () ppHyperlinkedSource verbosity outdir libdir mstyle pretty srcs' ifaces = do - createDirectoryIfMissing True srcdir - let cssFile = fromMaybe (defaultCssFile libdir) mstyle - copyFile cssFile $ srcdir srcCssFile - copyFile (libdir "html" highlightScript) $ - srcdir highlightScript - mapM_ (ppHyperlinkedModuleSource verbosity srcdir pretty srcs) ifaces + createDirectoryIfMissing True srcdir + let cssFile = fromMaybe (defaultCssFile libdir) mstyle + copyFile cssFile $ srcdir srcCssFile + copyFile (libdir "html" highlightScript) $ + srcdir highlightScript + mapM_ (ppHyperlinkedModuleSource verbosity srcdir pretty srcs) ifaces where srcdir = outdir hypSrcDir srcs = (srcs', M.mapKeys moduleName srcs') @@ -56,49 +62,58 @@ ppHyperlinkedSource verbosity outdir libdir mstyle pretty srcs' ifaces = do -- | Generate hyperlinked source for particular interface. ppHyperlinkedModuleSource :: Verbosity -> FilePath -> Bool -> SrcMaps -> Interface -> IO () ppHyperlinkedModuleSource verbosity srcdir pretty srcs iface = do - -- Parse the GHC-produced HIE file - nc <- freshNameCache - HieFile { hie_hs_file = file - , hie_asts = HieASTs asts - , hie_types = types - , hie_hs_src = rawSrc - } <- hie_file_result - <$> (readHieFile nc iface.ifaceHieFile ) + -- Parse the GHC-produced HIE file + nc <- freshNameCache + HieFile + { hie_hs_file = file + , hie_asts = HieASTs asts + , hie_types = types + , hie_hs_src = rawSrc + } <- + hie_file_result + <$> (readHieFile nc iface.ifaceHieFile) - -- Get the AST and tokens corresponding to the source file we want - let fileFs = mkFastString file - mast | M.size asts == 1 = snd <$> M.lookupMin asts - | otherwise = M.lookup (HiePath (mkFastString file)) asts - tokens' = parse df file rawSrc - ast = fromMaybe (emptyHieAst fileFs) mast - fullAst = recoverFullIfaceTypes df types ast + -- Get the AST and tokens corresponding to the source file we want + let fileFs = mkFastString file + mast + | M.size asts == 1 = snd <$> M.lookupMin asts + | otherwise = M.lookup (HiePath (mkFastString file)) asts + tokens' = parse df file rawSrc + ast = fromMaybe (emptyHieAst fileFs) mast + fullAst = recoverFullIfaceTypes df types ast - -- Warn if we didn't find an AST, but there were still ASTs - if M.null asts - then pure () - else out verbosity verbose $ unwords [ "couldn't find ast for" - , file, show (M.keys asts) ] + -- Warn if we didn't find an AST, but there were still ASTs + if M.null asts + then pure () + else + out verbosity verbose $ + unwords + [ "couldn't find ast for" + , file + , show (M.keys asts) + ] - -- The C preprocessor can double the backslashes on tokens (see #19236), - -- which means the source spans will not be comparable and we will not - -- be able to associate the HieAST with the correct tokens. - -- - -- We work around this by setting the source span of the tokens to the file - -- name from the HieAST - let tokens = fmap (\tk -> tk {tkSpan = (tkSpan tk){srcSpanFile = srcSpanFile $ nodeSpan fullAst}}) tokens' + -- The C preprocessor can double the backslashes on tokens (see #19236), + -- which means the source spans will not be comparable and we will not + -- be able to associate the HieAST with the correct tokens. + -- + -- We work around this by setting the source span of the tokens to the file + -- name from the HieAST + let tokens = fmap (\tk -> tk{tkSpan = (tkSpan tk){srcSpanFile = srcSpanFile $ nodeSpan fullAst}}) tokens' - -- Produce and write out the hyperlinked sources - writeUtf8File path . renderToString pretty . render' fullAst $ tokens + -- Produce and write out the hyperlinked sources + writeUtf8File path . renderToString pretty . render' fullAst $ tokens where df = ifaceDynFlags iface render' = render (Just srcCssFile) (Just highlightScript) srcs path = srcdir hypSrcModuleFile (ifaceMod iface) - emptyHieAst fileFs = Node - { nodeSpan = realSrcLocSpan (mkRealSrcLoc fileFs 1 0) - , nodeChildren = [] - , sourcedNodeInfo = SourcedNodeInfo mempty - } + emptyHieAst fileFs = + Node + { nodeSpan = realSrcLocSpan (mkRealSrcLoc fileFs 1 0) + , nodeChildren = [] + , sourcedNodeInfo = SourcedNodeInfo mempty + } -- | Name of CSS file in output directory. srcCssFile :: FilePath diff --git a/haddock-api/src/Haddock/Backends/Hyperlinker/Parser.hs b/haddock-api/src/Haddock/Backends/Hyperlinker/Parser.hs index 1d70e532bd..5a0c611780 100644 --- a/haddock-api/src/Haddock/Backends/Hyperlinker/Parser.hs +++ b/haddock-api/src/Haddock/Backends/Hyperlinker/Parser.hs @@ -1,32 +1,40 @@ {-# LANGUAGE OverloadedStrings #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} + module Haddock.Backends.Hyperlinker.Parser (parse) where -import Control.Monad.Trans.Maybe +import Control.Applicative (Alternative (..)) import Control.Monad.Trans.Class -import Control.Applicative ( Alternative(..) ) -import Data.List ( isPrefixOf, isSuffixOf ) +import Control.Monad.Trans.Maybe +import Data.List (isPrefixOf, isSuffixOf) import qualified Data.ByteString as BS -import GHC.Platform -import GHC.Types.SourceText -import GHC.Driver.Session +import GHC.Data.Bag (bagToList) +import GHC.Data.FastString (mkFastString) +import GHC.Data.StringBuffer (StringBuffer, atEnd) import GHC.Driver.Config.Diagnostic -import GHC.Utils.Error ( pprLocMsgEnvelopeDefault ) -import GHC.Data.FastString ( mkFastString ) +import GHC.Driver.Ppr (showSDoc) +import GHC.Driver.Session import GHC.Parser.Errors.Ppr () +import GHC.Parser.Lexer as Lexer + ( P (..) + , PState (..) + , ParseResult (..) + , Token (..) + , getPsErrorMessages + , initParserState + , lexer + , mkParserOpts + ) +import GHC.Platform import qualified GHC.Types.Error as E -import GHC.Parser.Lexer as Lexer - ( P(..), ParseResult(..), PState(..), Token(..) - , initParserState, lexer, mkParserOpts, getPsErrorMessages) -import GHC.Data.Bag ( bagToList ) -import GHC.Utils.Outputable ( text, ($$) ) -import GHC.Utils.Panic ( panic ) -import GHC.Driver.Ppr ( showSDoc ) +import GHC.Types.SourceText import GHC.Types.SrcLoc -import GHC.Data.StringBuffer ( StringBuffer, atEnd ) +import GHC.Utils.Error (pprLocMsgEnvelopeDefault) +import GHC.Utils.Outputable (text, ($$)) +import GHC.Utils.Panic (panic) import Haddock.Backends.Hyperlinker.Types as T import Haddock.GhcUtils @@ -36,33 +44,40 @@ import Haddock.GhcUtils -- Result should retain original file layout (including comments, -- whitespace, and CPP). parse - :: DynFlags -- ^ Flags for this module - -> FilePath -- ^ Path to the source of this module - -> BS.ByteString -- ^ Raw UTF-8 encoded source of this module + :: DynFlags + -- ^ Flags for this module + -> FilePath + -- ^ Path to the source of this module + -> BS.ByteString + -- ^ Raw UTF-8 encoded source of this module -> [T.Token] parse dflags fpath bs = case unP (go False []) initState of - POk _ toks -> reverse toks - PFailed pst -> - let err:_ = bagToList (E.getMessages $ getPsErrorMessages pst) in - panic $ showSDoc dflags $ - text "Hyperlinker parse error:" $$ pprLocMsgEnvelopeDefault err + POk _ toks -> reverse toks + PFailed pst -> + let err : _ = bagToList (E.getMessages $ getPsErrorMessages pst) + in panic $ + showSDoc dflags $ + text "Hyperlinker parse error:" $$ pprLocMsgEnvelopeDefault err where - initState = initParserState pflags buf start buf = stringBufferFromByteString bs start = mkRealSrcLoc (mkFastString fpath) 1 1 arch_os = platformArchOS (targetPlatform dflags) - pflags = mkParserOpts (extensionFlags dflags) - (initDiagOpts dflags) - (supportedLanguagesAndExtensions arch_os) - (safeImportsOn dflags) - False -- lex Haddocks as comment tokens - True -- produce comment tokens - False -- produce position pragmas tokens - - go :: Bool -- ^ are we currently in a pragma? - -> [T.Token] -- ^ tokens accumulated so far (in reverse) - -> P [T.Token] + pflags = + mkParserOpts + (extensionFlags dflags) + (initDiagOpts dflags) + (supportedLanguagesAndExtensions arch_os) + (safeImportsOn dflags) + False -- lex Haddocks as comment tokens + True -- produce comment tokens + False -- produce position pragmas tokens + go + :: Bool + -- \^ are we currently in a pragma? + -> [T.Token] + -- \^ tokens accumulated so far (in reverse) + -> P [T.Token] go inPrag toks = do (b, _) <- getInput if not (atEnd b) @@ -72,33 +87,36 @@ parse dflags fpath bs = case unP (go False []) initState of Nothing -> unknownLine Just a -> pure a go inPrag' (newToks ++ toks) - else - pure toks + else pure toks - -- | Like 'Lexer.lexer', but slower, with a better API, and filtering out empty tokens + -- \| Like 'Lexer.lexer', but slower, with a better API, and filtering out empty tokens wrappedLexer :: P (RealLocated Lexer.Token) wrappedLexer = Lexer.lexer False andThen - where andThen (L (RealSrcSpan s _) t) - | srcSpanStartLine s /= srcSpanEndLine s || - srcSpanStartCol s /= srcSpanEndCol s - = pure (L s t) - andThen (L (RealSrcSpan s _) ITeof) = pure (L s ITeof) - andThen _ = wrappedLexer - - -- | Try to parse a CPP line (can fail) + where + andThen (L (RealSrcSpan s _) t) + | srcSpanStartLine s /= srcSpanEndLine s + || srcSpanStartCol s /= srcSpanEndCol s = + pure (L s t) + andThen (L (RealSrcSpan s _) ITeof) = pure (L s ITeof) + andThen _ = wrappedLexer + + -- \| Try to parse a CPP line (can fail) parseCppLine :: MaybeT P ([T.Token], Bool) parseCppLine = MaybeT $ do (b, l) <- getInput case tryCppLine l b of - Just (cppBStr, l', b') - -> let cppTok = T.Token { tkType = TkCpp - , tkValue = cppBStr - , tkSpan = mkRealSrcSpan l l' } - in setInput (b', l') *> pure (Just ([cppTok], False)) - _ -> return Nothing - - -- | Try to parse a regular old token (can fail) - parsePlainTok :: Bool -> MaybeT P ([T.Token], Bool) -- return list is only ever 0-2 elements + Just (cppBStr, l', b') -> + let cppTok = + T.Token + { tkType = TkCpp + , tkValue = cppBStr + , tkSpan = mkRealSrcSpan l l' + } + in setInput (b', l') *> pure (Just ([cppTok], False)) + _ -> return Nothing + + -- \| Try to parse a regular old token (can fail) + parsePlainTok :: Bool -> MaybeT P ([T.Token], Bool) -- return list is only ever 0-2 elements parsePlainTok inPrag = do (bInit, lInit) <- lift getInput L sp tok <- tryP (Lexer.lexer False return) @@ -112,12 +130,11 @@ parse dflags fpath bs = case unP (go False []) initState of inPragDef = inPragma inPrag tok (bEnd', inPrag') <- case tok of - -- Update internal line + file position if this is a LINE pragma ITline_prag _ -> tryOrElse (bEnd, inPragDef) $ do - L _ (ITinteger (IL { il_value = line })) <- tryP wrappedLexer - L _ (ITstring _ file) <- tryP wrappedLexer - L spF ITclose_prag <- tryP wrappedLexer + L _ (ITinteger (IL{il_value = line})) <- tryP wrappedLexer + L _ (ITstring _ file) <- tryP wrappedLexer + L spF ITclose_prag <- tryP wrappedLexer let newLoc = mkRealSrcLoc file (fromIntegral line - 1) (srcSpanEndCol spF) (bEnd'', _) <- lift getInput @@ -127,48 +144,55 @@ parse dflags fpath bs = case unP (go False []) initState of -- Update internal column position if this is a COLUMN pragma ITcolumn_prag _ -> tryOrElse (bEnd, inPragDef) $ do - L _ (ITinteger (IL { il_value = col })) <- tryP wrappedLexer - L spF ITclose_prag <- tryP wrappedLexer + L _ (ITinteger (IL{il_value = col})) <- tryP wrappedLexer + L spF ITclose_prag <- tryP wrappedLexer let newLoc = mkRealSrcLoc (srcSpanFile spF) (srcSpanEndLine spF) (fromIntegral col) (bEnd'', _) <- lift getInput lift $ setInput (bEnd'', newLoc) pure (bEnd'', False) - _ -> pure (bEnd, inPragDef) let tokBStr = splitStringBuffer bStart bEnd' - plainTok = T.Token { tkType = typ - , tkValue = tokBStr - , tkSpan = rsp } - spaceTok = T.Token { tkType = TkSpace - , tkValue = spaceBStr - , tkSpan = mkRealSrcSpan lInit lStart } - - pure (plainTok : [ spaceTok | not (BS.null spaceBStr) ], inPrag') - - -- | Parse whatever remains of the line as an unknown token (can't fail) + plainTok = + T.Token + { tkType = typ + , tkValue = tokBStr + , tkSpan = rsp + } + spaceTok = + T.Token + { tkType = TkSpace + , tkValue = spaceBStr + , tkSpan = mkRealSrcSpan lInit lStart + } + + pure (plainTok : [spaceTok | not (BS.null spaceBStr)], inPrag') + + -- \| Parse whatever remains of the line as an unknown token (can't fail) unknownLine :: P ([T.Token], Bool) unknownLine = do (b, l) <- getInput let (unkBStr, l', b') = spanLine l b - unkTok = T.Token { tkType = TkUnknown - , tkValue = unkBStr - , tkSpan = mkRealSrcSpan l l' } + unkTok = + T.Token + { tkType = TkUnknown + , tkValue = unkBStr + , tkSpan = mkRealSrcSpan l l' + } setInput (b', l') pure ([unkTok], False) - -- | Get the input getInput :: P (StringBuffer, RealSrcLoc) -getInput = P $ \p@PState { buffer = buf, loc = srcLoc } -> POk p (buf, psRealLoc srcLoc) +getInput = P $ \p@PState{buffer = buf, loc = srcLoc} -> POk p (buf, psRealLoc srcLoc) -- | Set the input setInput :: (StringBuffer, RealSrcLoc) -> P () setInput (buf, srcLoc) = - P $ \p@PState{ loc = PsLoc _ buf_loc } -> - POk (p { buffer = buf, loc = PsLoc srcLoc buf_loc }) () + P $ \p@PState{loc = PsLoc _ buf_loc} -> + POk (p{buffer = buf, loc = PsLoc srcLoc buf_loc}) () tryP :: P a -> MaybeT P a tryP (P f) = MaybeT $ P $ \s -> case f s of @@ -182,233 +206,221 @@ tryOrElse x p = p <|> pure x classify :: Lexer.Token -> TokenType classify tok = case tok of - ITas -> TkKeyword - ITcase -> TkKeyword - ITclass -> TkKeyword - ITdata -> TkKeyword - ITdefault -> TkKeyword - ITderiving -> TkKeyword - ITdo {} -> TkKeyword - ITelse -> TkKeyword - IThiding -> TkKeyword - ITforeign -> TkKeyword - ITif -> TkKeyword - ITimport -> TkKeyword - ITin -> TkKeyword - ITinfix -> TkKeyword - ITinfixl -> TkKeyword - ITinfixr -> TkKeyword - ITinstance -> TkKeyword - ITlet -> TkKeyword - ITmodule -> TkKeyword - ITnewtype -> TkKeyword - ITof -> TkKeyword - ITqualified -> TkKeyword - ITthen -> TkKeyword - ITtype -> TkKeyword - ITvia -> TkKeyword - ITwhere -> TkKeyword - - ITforall {} -> TkKeyword - ITexport -> TkKeyword - ITlabel -> TkKeyword - ITdynamic -> TkKeyword - ITsafe -> TkKeyword - ITinterruptible -> TkKeyword - ITunsafe -> TkKeyword - ITstdcallconv -> TkKeyword - ITccallconv -> TkKeyword - ITcapiconv -> TkKeyword - ITprimcallconv -> TkKeyword - ITjavascriptcallconv -> TkKeyword - ITmdo {} -> TkKeyword - ITfamily -> TkKeyword - ITrole -> TkKeyword - ITgroup -> TkKeyword - ITby -> TkKeyword - ITusing -> TkKeyword - ITpattern -> TkKeyword - ITstatic -> TkKeyword - ITstock -> TkKeyword - ITanyclass -> TkKeyword - - ITunit -> TkKeyword - ITsignature -> TkKeyword - ITdependency -> TkKeyword - ITrequires -> TkKeyword - - ITinline_prag {} -> TkPragma - ITopaque_prag {} -> TkPragma - ITspec_prag {} -> TkPragma - ITspec_inline_prag {} -> TkPragma - ITsource_prag {} -> TkPragma - ITrules_prag {} -> TkPragma - ITwarning_prag {} -> TkPragma - ITdeprecated_prag {} -> TkPragma - ITline_prag {} -> TkPragma - ITcolumn_prag {} -> TkPragma - ITscc_prag {} -> TkPragma - ITunpack_prag {} -> TkPragma - ITnounpack_prag {} -> TkPragma - ITann_prag {} -> TkPragma - ITcomplete_prag {} -> TkPragma - ITclose_prag -> TkPragma - IToptions_prag {} -> TkPragma - ITinclude_prag {} -> TkPragma - ITlanguage_prag -> TkPragma - ITminimal_prag {} -> TkPragma - IToverlappable_prag {} -> TkPragma - IToverlapping_prag {} -> TkPragma - IToverlaps_prag {} -> TkPragma - ITincoherent_prag {} -> TkPragma - ITctype {} -> TkPragma - - ITdotdot -> TkGlyph - ITcolon -> TkGlyph - ITdcolon {} -> TkGlyph - ITequal -> TkGlyph - ITlam -> TkGlyph - ITlcase -> TkGlyph - ITlcases -> TkGlyph - ITvbar -> TkGlyph - ITlarrow {} -> TkGlyph - ITrarrow {} -> TkGlyph - ITlolly {} -> TkGlyph - ITat -> TkGlyph - ITtilde -> TkGlyph - ITdarrow {} -> TkGlyph - ITminus -> TkGlyph - ITprefixminus -> TkGlyph - ITbang -> TkGlyph - ITdot -> TkOperator - ITproj {} -> TkOperator - ITstar {} -> TkOperator - ITtypeApp -> TkGlyph - ITpercent -> TkGlyph - - ITbiglam -> TkGlyph - - ITocurly -> TkSpecial - ITccurly -> TkSpecial - ITvocurly -> TkSpecial - ITvccurly -> TkSpecial - ITobrack -> TkSpecial - ITopabrack -> TkSpecial - ITcpabrack -> TkSpecial - ITcbrack -> TkSpecial - IToparen -> TkSpecial - ITcparen -> TkSpecial - IToubxparen -> TkSpecial - ITcubxparen -> TkSpecial - ITsemi -> TkSpecial - ITcomma -> TkSpecial - ITunderscore -> TkIdentifier - ITbackquote -> TkSpecial - ITsimpleQuote -> TkSpecial - - ITvarid {} -> TkIdentifier - ITconid {} -> TkIdentifier - ITvarsym {} -> TkOperator - ITconsym {} -> TkOperator - ITqvarid {} -> TkIdentifier - ITqconid {} -> TkIdentifier - ITqvarsym {} -> TkOperator - ITqconsym {} -> TkOperator - - ITdupipvarid {} -> TkUnknown - ITlabelvarid {} -> TkUnknown - - ITchar {} -> TkChar - ITstring {} -> TkString - ITinteger {} -> TkNumber - ITrational {} -> TkNumber - - ITprimchar {} -> TkChar - ITprimstring {} -> TkString - ITprimint {} -> TkNumber - ITprimword {} -> TkNumber - ITprimint8 {} -> TkNumber - ITprimint16 {} -> TkNumber - ITprimint32 {} -> TkNumber - ITprimint64 {} -> TkNumber - ITprimword8 {} -> TkNumber - ITprimword16 {} -> TkNumber - ITprimword32 {} -> TkNumber - ITprimword64 {} -> TkNumber - ITprimfloat {} -> TkNumber - ITprimdouble {} -> TkNumber - - ITopenExpQuote {} -> TkSpecial - ITopenPatQuote -> TkSpecial - ITopenDecQuote -> TkSpecial - ITopenTypQuote -> TkSpecial - ITcloseQuote {} -> TkSpecial - ITopenTExpQuote {} -> TkSpecial - ITcloseTExpQuote -> TkSpecial - ITdollar -> TkSpecial - ITdollardollar -> TkSpecial - ITtyQuote -> TkSpecial - ITquasiQuote {} -> TkUnknown - ITqQuasiQuote {} -> TkUnknown - - ITproc -> TkKeyword - ITrec -> TkKeyword - IToparenbar {} -> TkGlyph - ITcparenbar {} -> TkGlyph - ITlarrowtail {} -> TkGlyph - ITrarrowtail {} -> TkGlyph - ITLarrowtail {} -> TkGlyph - ITRarrowtail {} -> TkGlyph - - ITcomment_line_prag -> TkUnknown - ITunknown {} -> TkUnknown - ITeof -> TkUnknown - - ITlineComment {} -> TkComment - ITdocComment {} -> TkComment - ITdocOptions {} -> TkComment - + ITas -> TkKeyword + ITcase -> TkKeyword + ITclass -> TkKeyword + ITdata -> TkKeyword + ITdefault -> TkKeyword + ITderiving -> TkKeyword + ITdo{} -> TkKeyword + ITelse -> TkKeyword + IThiding -> TkKeyword + ITforeign -> TkKeyword + ITif -> TkKeyword + ITimport -> TkKeyword + ITin -> TkKeyword + ITinfix -> TkKeyword + ITinfixl -> TkKeyword + ITinfixr -> TkKeyword + ITinstance -> TkKeyword + ITlet -> TkKeyword + ITmodule -> TkKeyword + ITnewtype -> TkKeyword + ITof -> TkKeyword + ITqualified -> TkKeyword + ITthen -> TkKeyword + ITtype -> TkKeyword + ITvia -> TkKeyword + ITwhere -> TkKeyword + ITforall{} -> TkKeyword + ITexport -> TkKeyword + ITlabel -> TkKeyword + ITdynamic -> TkKeyword + ITsafe -> TkKeyword + ITinterruptible -> TkKeyword + ITunsafe -> TkKeyword + ITstdcallconv -> TkKeyword + ITccallconv -> TkKeyword + ITcapiconv -> TkKeyword + ITprimcallconv -> TkKeyword + ITjavascriptcallconv -> TkKeyword + ITmdo{} -> TkKeyword + ITfamily -> TkKeyword + ITrole -> TkKeyword + ITgroup -> TkKeyword + ITby -> TkKeyword + ITusing -> TkKeyword + ITpattern -> TkKeyword + ITstatic -> TkKeyword + ITstock -> TkKeyword + ITanyclass -> TkKeyword + ITunit -> TkKeyword + ITsignature -> TkKeyword + ITdependency -> TkKeyword + ITrequires -> TkKeyword + ITinline_prag{} -> TkPragma + ITopaque_prag{} -> TkPragma + ITspec_prag{} -> TkPragma + ITspec_inline_prag{} -> TkPragma + ITsource_prag{} -> TkPragma + ITrules_prag{} -> TkPragma + ITwarning_prag{} -> TkPragma + ITdeprecated_prag{} -> TkPragma + ITline_prag{} -> TkPragma + ITcolumn_prag{} -> TkPragma + ITscc_prag{} -> TkPragma + ITunpack_prag{} -> TkPragma + ITnounpack_prag{} -> TkPragma + ITann_prag{} -> TkPragma + ITcomplete_prag{} -> TkPragma + ITclose_prag -> TkPragma + IToptions_prag{} -> TkPragma + ITinclude_prag{} -> TkPragma + ITlanguage_prag -> TkPragma + ITminimal_prag{} -> TkPragma + IToverlappable_prag{} -> TkPragma + IToverlapping_prag{} -> TkPragma + IToverlaps_prag{} -> TkPragma + ITincoherent_prag{} -> TkPragma + ITctype{} -> TkPragma + ITdotdot -> TkGlyph + ITcolon -> TkGlyph + ITdcolon{} -> TkGlyph + ITequal -> TkGlyph + ITlam -> TkGlyph + ITlcase -> TkGlyph + ITlcases -> TkGlyph + ITvbar -> TkGlyph + ITlarrow{} -> TkGlyph + ITrarrow{} -> TkGlyph + ITlolly{} -> TkGlyph + ITat -> TkGlyph + ITtilde -> TkGlyph + ITdarrow{} -> TkGlyph + ITminus -> TkGlyph + ITprefixminus -> TkGlyph + ITbang -> TkGlyph + ITdot -> TkOperator + ITproj{} -> TkOperator + ITstar{} -> TkOperator + ITtypeApp -> TkGlyph + ITpercent -> TkGlyph + ITbiglam -> TkGlyph + ITocurly -> TkSpecial + ITccurly -> TkSpecial + ITvocurly -> TkSpecial + ITvccurly -> TkSpecial + ITobrack -> TkSpecial + ITopabrack -> TkSpecial + ITcpabrack -> TkSpecial + ITcbrack -> TkSpecial + IToparen -> TkSpecial + ITcparen -> TkSpecial + IToubxparen -> TkSpecial + ITcubxparen -> TkSpecial + ITsemi -> TkSpecial + ITcomma -> TkSpecial + ITunderscore -> TkIdentifier + ITbackquote -> TkSpecial + ITsimpleQuote -> TkSpecial + ITvarid{} -> TkIdentifier + ITconid{} -> TkIdentifier + ITvarsym{} -> TkOperator + ITconsym{} -> TkOperator + ITqvarid{} -> TkIdentifier + ITqconid{} -> TkIdentifier + ITqvarsym{} -> TkOperator + ITqconsym{} -> TkOperator + ITdupipvarid{} -> TkUnknown + ITlabelvarid{} -> TkUnknown + ITchar{} -> TkChar + ITstring{} -> TkString + ITinteger{} -> TkNumber + ITrational{} -> TkNumber + ITprimchar{} -> TkChar + ITprimstring{} -> TkString + ITprimint{} -> TkNumber + ITprimword{} -> TkNumber + ITprimint8{} -> TkNumber + ITprimint16{} -> TkNumber + ITprimint32{} -> TkNumber + ITprimint64{} -> TkNumber + ITprimword8{} -> TkNumber + ITprimword16{} -> TkNumber + ITprimword32{} -> TkNumber + ITprimword64{} -> TkNumber + ITprimfloat{} -> TkNumber + ITprimdouble{} -> TkNumber + ITopenExpQuote{} -> TkSpecial + ITopenPatQuote -> TkSpecial + ITopenDecQuote -> TkSpecial + ITopenTypQuote -> TkSpecial + ITcloseQuote{} -> TkSpecial + ITopenTExpQuote{} -> TkSpecial + ITcloseTExpQuote -> TkSpecial + ITdollar -> TkSpecial + ITdollardollar -> TkSpecial + ITtyQuote -> TkSpecial + ITquasiQuote{} -> TkUnknown + ITqQuasiQuote{} -> TkUnknown + ITproc -> TkKeyword + ITrec -> TkKeyword + IToparenbar{} -> TkGlyph + ITcparenbar{} -> TkGlyph + ITlarrowtail{} -> TkGlyph + ITrarrowtail{} -> TkGlyph + ITLarrowtail{} -> TkGlyph + ITRarrowtail{} -> TkGlyph + ITcomment_line_prag -> TkUnknown + ITunknown{} -> TkUnknown + ITeof -> TkUnknown + ITlineComment{} -> TkComment + ITdocComment{} -> TkComment + ITdocOptions{} -> TkComment -- The lexer considers top-level pragmas as comments (see `pragState` in -- the GHC lexer for more), so we have to manually reverse this. The -- following is a hammer: it smashes _all_ pragma-like block comments into -- pragmas. ITblockComment c _ | isPrefixOf "{-#" c - , isSuffixOf "#-}" c -> TkPragma - | otherwise -> TkComment + , isSuffixOf "#-}" c -> + TkPragma + | otherwise -> TkComment -- | Classify given tokens as beginning pragmas (or not). -inPragma :: Bool -- ^ currently in pragma - -> Lexer.Token -- ^ current token - -> Bool -- ^ new information about whether we are in a pragma +inPragma + :: Bool + -- ^ currently in pragma + -> Lexer.Token + -- ^ current token + -> Bool + -- ^ new information about whether we are in a pragma inPragma _ ITclose_prag = False inPragma True _ = True inPragma False tok = case tok of - ITinline_prag {} -> True - ITopaque_prag {} -> True - ITspec_prag {} -> True - ITspec_inline_prag {} -> True - ITsource_prag {} -> True - ITrules_prag {} -> True - ITwarning_prag {} -> True - ITdeprecated_prag {} -> True - ITline_prag {} -> True - ITcolumn_prag {} -> True - ITscc_prag {} -> True - ITunpack_prag {} -> True - ITnounpack_prag {} -> True - ITann_prag {} -> True - ITcomplete_prag {} -> True - IToptions_prag {} -> True - ITinclude_prag {} -> True - ITlanguage_prag -> True - ITminimal_prag {} -> True - IToverlappable_prag {} -> True - IToverlapping_prag {} -> True - IToverlaps_prag {} -> True - ITincoherent_prag {} -> True - ITctype {} -> True - - _ -> False - + ITinline_prag{} -> True + ITopaque_prag{} -> True + ITspec_prag{} -> True + ITspec_inline_prag{} -> True + ITsource_prag{} -> True + ITrules_prag{} -> True + ITwarning_prag{} -> True + ITdeprecated_prag{} -> True + ITline_prag{} -> True + ITcolumn_prag{} -> True + ITscc_prag{} -> True + ITunpack_prag{} -> True + ITnounpack_prag{} -> True + ITann_prag{} -> True + ITcomplete_prag{} -> True + IToptions_prag{} -> True + ITinclude_prag{} -> True + ITlanguage_prag -> True + ITminimal_prag{} -> True + IToverlappable_prag{} -> True + IToverlapping_prag{} -> True + IToverlaps_prag{} -> True + ITincoherent_prag{} -> True + ITctype{} -> True + _ -> False diff --git a/haddock-api/src/Haddock/Backends/Hyperlinker/Renderer.hs b/haddock-api/src/Haddock/Backends/Hyperlinker/Renderer.hs index fa162b23dc..64028296e7 100644 --- a/haddock-api/src/Haddock/Backends/Hyperlinker/Renderer.hs +++ b/haddock-api/src/Haddock/Backends/Hyperlinker/Renderer.hs @@ -1,43 +1,46 @@ +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ViewPatterns #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE BangPatterns #-} module Haddock.Backends.Hyperlinker.Renderer (render) where - import Haddock.Backends.Hyperlinker.Types import Haddock.Backends.Hyperlinker.Utils import qualified Data.ByteString as BS import GHC.Iface.Ext.Types -import GHC.Iface.Ext.Utils ( isEvidenceContext , emptyNodeInfo ) -import GHC.Unit.Module ( ModuleName, moduleNameString ) -import GHC.Types.Name ( getOccString, isInternalName, Name, nameModule, nameUnique ) +import GHC.Iface.Ext.Utils (emptyNodeInfo, isEvidenceContext) +import GHC.Types.Name (Name, getOccString, isInternalName, nameModule, nameUnique) import GHC.Types.SrcLoc -import GHC.Types.Unique ( getKey ) -import GHC.Utils.Encoding ( utf8DecodeByteString ) +import GHC.Types.Unique (getKey) +import GHC.Unit.Module (ModuleName, moduleNameString) +import GHC.Utils.Encoding (utf8DecodeByteString) import System.FilePath.Posix (()) +import qualified Data.List as List import qualified Data.Map as Map import qualified Data.Set as Set -import qualified Data.List as List import Text.XHtml (Html, HtmlAttr, (!)) import qualified Text.XHtml as Html - type StyleClass = String -- | Produce the HTML corresponding to a hyperlinked Haskell source render - :: Maybe FilePath -- ^ path to the CSS file - -> Maybe FilePath -- ^ path to the JS file - -> SrcMaps -- ^ Paths to sources - -> HieAST PrintedType -- ^ ASTs from @.hie@ files - -> [Token] -- ^ tokens to render + :: Maybe FilePath + -- ^ path to the CSS file + -> Maybe FilePath + -- ^ path to the JS file + -> SrcMaps + -- ^ Paths to sources + -> HieAST PrintedType + -- ^ ASTs from @.hie@ files + -> [Token] + -- ^ tokens to render -> Html render mcss mjs srcs ast tokens = header mcss mjs <> body srcs ast tokens @@ -51,23 +54,24 @@ header Nothing Nothing = Html.noHtml header mcss mjs = Html.header $ css mcss <> js mjs where css Nothing = Html.noHtml - css (Just cssFile) = Html.thelink Html.noHtml ! - [ Html.rel "stylesheet" - , Html.thetype "text/css" - , Html.href cssFile - ] + css (Just cssFile) = + Html.thelink Html.noHtml + ! [ Html.rel "stylesheet" + , Html.thetype "text/css" + , Html.href cssFile + ] js Nothing = Html.noHtml - js (Just scriptFile) = Html.script Html.noHtml ! - [ Html.thetype "text/javascript" - , Html.src scriptFile - ] - - -splitTokens :: HieAST PrintedType -> [Token] -> ([Token],[Token],[Token]) -splitTokens ast toks = (before,during,after) + js (Just scriptFile) = + Html.script Html.noHtml + ! [ Html.thetype "text/javascript" + , Html.src scriptFile + ] + +splitTokens :: HieAST PrintedType -> [Token] -> ([Token], [Token], [Token]) +splitTokens ast toks = (before, during, after) where - (before,rest) = span leftOf toks - (during,after) = span inAst rest + (before, rest) = span leftOf toks + (during, after) = span inAst rest leftOf t = realSrcSpanEnd (tkSpan t) <= realSrcSpanStart nodeSp inAst t = nodeSp `containsSpan` tkSpan t nodeSp = nodeSpan ast @@ -76,66 +80,73 @@ splitTokens ast toks = (before,during,after) -- information from the 'HieAST'. renderWithAst :: SrcMaps -> HieAST PrintedType -> [Token] -> Html renderWithAst srcs Node{..} toks = anchored $ case toks of - - [tok] | nodeSpan == tkSpan tok -> richToken srcs nodeInfo tok - - -- NB: the GHC lexer lexes backquoted identifiers and parenthesized operators - -- as multiple tokens. - -- - -- * @a `elem` b@ turns into @[a, `, elem, `, b]@ (excluding space tokens) - -- * @(+) 1 2@ turns into @[(, +, ), 1, 2]@ (excluding space tokens) - -- - -- However, the HIE ast considers @`elem`@ and @(+)@ to be single nodes. In - -- order to make sure these get hyperlinked properly, we intercept these - -- special sequences of tokens and merge them into just one identifier or - -- operator token. - [BacktickTok s1, tok@Token{ tkType = TkIdentifier }, BacktickTok s2] - | realSrcSpanStart s1 == realSrcSpanStart nodeSpan - , realSrcSpanEnd s2 == realSrcSpanEnd nodeSpan - -> richToken srcs nodeInfo - (Token{ tkValue = "`" <> tkValue tok <> "`" - , tkType = TkOperator - , tkSpan = nodeSpan }) - [OpenParenTok s1, tok@Token{ tkType = TkOperator }, CloseParenTok s2] - | realSrcSpanStart s1 == realSrcSpanStart nodeSpan - , realSrcSpanEnd s2 == realSrcSpanEnd nodeSpan - -> richToken srcs nodeInfo - (Token{ tkValue = "(" <> tkValue tok <> ")" - , tkType = TkOperator - , tkSpan = nodeSpan }) - - _ -> go nodeChildren toks + [tok] | nodeSpan == tkSpan tok -> richToken srcs nodeInfo tok + -- NB: the GHC lexer lexes backquoted identifiers and parenthesized operators + -- as multiple tokens. + -- + -- * @a `elem` b@ turns into @[a, `, elem, `, b]@ (excluding space tokens) + -- * @(+) 1 2@ turns into @[(, +, ), 1, 2]@ (excluding space tokens) + -- + -- However, the HIE ast considers @`elem`@ and @(+)@ to be single nodes. In + -- order to make sure these get hyperlinked properly, we intercept these + -- special sequences of tokens and merge them into just one identifier or + -- operator token. + [BacktickTok s1, tok@Token{tkType = TkIdentifier}, BacktickTok s2] + | realSrcSpanStart s1 == realSrcSpanStart nodeSpan + , realSrcSpanEnd s2 == realSrcSpanEnd nodeSpan -> + richToken + srcs + nodeInfo + ( Token + { tkValue = "`" <> tkValue tok <> "`" + , tkType = TkOperator + , tkSpan = nodeSpan + } + ) + [OpenParenTok s1, tok@Token{tkType = TkOperator}, CloseParenTok s2] + | realSrcSpanStart s1 == realSrcSpanStart nodeSpan + , realSrcSpanEnd s2 == realSrcSpanEnd nodeSpan -> + richToken + srcs + nodeInfo + ( Token + { tkValue = "(" <> tkValue tok <> ")" + , tkType = TkOperator + , tkSpan = nodeSpan + } + ) + _ -> go nodeChildren toks where nodeInfo = maybe emptyNodeInfo id (Map.lookup SourceInfo $ getSourcedNodeInfo sourcedNodeInfo) go _ [] = mempty go [] xs = foldMap renderToken xs - go (cur:rest) xs = - foldMap renderToken before <> renderWithAst srcs cur during <> go rest after + go (cur : rest) xs = + foldMap renderToken before <> renderWithAst srcs cur during <> go rest after where - (before,during,after) = splitTokens cur xs + (before, during, after) = splitTokens cur xs anchored c = Map.foldrWithKey anchorOne c (nodeIdentifiers nodeInfo) anchorOne n dets c = externalAnchor n d $ internalAnchor n d c - where d = identInfo dets + where + d = identInfo dets renderToken :: Token -> Html renderToken Token{..} - | BS.null tkValue = mempty - | tkType == TkSpace = renderSpace (srcSpanStartLine tkSpan) tkValue' - | otherwise = tokenSpan ! [ multiclass style ] + | BS.null tkValue = mempty + | tkType == TkSpace = renderSpace (srcSpanStartLine tkSpan) tkValue' + | otherwise = tokenSpan ! [multiclass style] where tkValue' = filterCRLF $ utf8DecodeByteString tkValue style = tokenStyle tkType tokenSpan = Html.thespan (Html.toHtml tkValue') - -- | Given information about the source position of definitions, render a token richToken :: SrcMaps -> NodeInfo PrintedType -> Token -> Html richToken srcs details Token{..} - | tkType == TkSpace = renderSpace (srcSpanStartLine tkSpan) tkValue' - | otherwise = annotate details $ linked content + | tkType == TkSpace = renderSpace (srcSpanStartLine tkSpan) tkValue' + | otherwise = annotate details $ linked content where tkValue' = filterCRLF $ utf8DecodeByteString tkValue - content = tokenSpan ! [ multiclass style ] + content = tokenSpan ! [multiclass style] tokenSpan = Html.thespan (Html.toHtml tkValue') style = tokenStyle tkType ++ concatMap (richTokenStyle (null (nodeType details))) contexts @@ -147,52 +158,55 @@ richToken srcs details Token{..} -- If we have name information, we can make links linked = case identDet of - Just (n,_) -> hyperlink srcs n + Just (n, _) -> hyperlink srcs n Nothing -> id -- | Remove CRLFs from source filterCRLF :: String -> String -filterCRLF ('\r':'\n':cs) = '\n' : filterCRLF cs -filterCRLF (c:cs) = c : filterCRLF cs +filterCRLF ('\r' : '\n' : cs) = '\n' : filterCRLF cs +filterCRLF (c : cs) = c : filterCRLF cs filterCRLF [] = [] annotate :: NodeInfo PrintedType -> Html -> Html -annotate ni content = - Html.thespan (annot <> content) ! [ Html.theclass "annot" ] +annotate ni content = + Html.thespan (annot <> content) ! [Html.theclass "annot"] where annot | not (null annotation) = - Html.thespan (Html.toHtml annotation) ! [ Html.theclass "annottext" ] + Html.thespan (Html.toHtml annotation) ! [Html.theclass "annottext"] | otherwise = mempty annotation = typ ++ identTyps typ = unlines (nodeType ni) - typedIdents = [ (n,t) | (n, c@(identType -> Just t)) <- Map.toList $ nodeIdentifiers ni - , not (any isEvidenceContext $ identInfo c) ] + typedIdents = + [ (n, t) | (n, c@(identType -> Just t)) <- Map.toList $ nodeIdentifiers ni, not (any isEvidenceContext $ identInfo c) + ] identTyps - | length typedIdents > 1 || null (nodeType ni) - = concatMap (\(n,t) -> printName n ++ " :: " ++ t ++ "\n") typedIdents + | length typedIdents > 1 || null (nodeType ni) = + concatMap (\(n, t) -> printName n ++ " :: " ++ t ++ "\n") typedIdents | otherwise = "" printName :: Either ModuleName Name -> String printName = either moduleNameString getOccString richTokenStyle - :: Bool -- ^ are we lacking a type annotation? - -> ContextInfo -- ^ in what context did this token show up? + :: Bool + -- ^ are we lacking a type annotation? + -> ContextInfo + -- ^ in what context did this token show up? -> [StyleClass] -richTokenStyle True Use = ["hs-type"] -richTokenStyle False Use = ["hs-var"] -richTokenStyle _ RecField{} = ["hs-var"] -richTokenStyle _ PatternBind{} = ["hs-var"] -richTokenStyle _ MatchBind{} = ["hs-var"] -richTokenStyle _ TyVarBind{} = ["hs-type"] -richTokenStyle _ ValBind{} = ["hs-var"] -richTokenStyle _ TyDecl = ["hs-type"] -richTokenStyle _ ClassTyDecl{} = ["hs-type"] -richTokenStyle _ Decl{} = ["hs-var"] -richTokenStyle _ IEThing{} = [] -- could be either a value or type -richTokenStyle _ EvidenceVarBind{} = [] -richTokenStyle _ EvidenceVarUse{} = [] +richTokenStyle True Use = ["hs-type"] +richTokenStyle False Use = ["hs-var"] +richTokenStyle _ RecField{} = ["hs-var"] +richTokenStyle _ PatternBind{} = ["hs-var"] +richTokenStyle _ MatchBind{} = ["hs-var"] +richTokenStyle _ TyVarBind{} = ["hs-type"] +richTokenStyle _ ValBind{} = ["hs-var"] +richTokenStyle _ TyDecl = ["hs-type"] +richTokenStyle _ ClassTyDecl{} = ["hs-type"] +richTokenStyle _ Decl{} = ["hs-var"] +richTokenStyle _ IEThing{} = [] -- could be either a value or type +richTokenStyle _ EvidenceVarBind{} = [] +richTokenStyle _ EvidenceVarUse{} = [] tokenStyle :: TokenType -> [StyleClass] tokenStyle TkIdentifier = ["hs-identifier"] @@ -215,8 +229,8 @@ multiclass = Html.theclass . unwords externalAnchor :: Identifier -> Set.Set ContextInfo -> Html -> Html externalAnchor (Right name) contexts content | not (isInternalName name) - , any isBinding contexts - = Html.thespan content ! [ Html.identifier $ externalAnchorIdent name ] + , any isBinding contexts = + Html.thespan content ! [Html.identifier $ externalAnchorIdent name] externalAnchor _ _ content = content isBinding :: ContextInfo -> Bool @@ -231,8 +245,8 @@ isBinding _ = False internalAnchor :: Identifier -> Set.Set ContextInfo -> Html -> Html internalAnchor (Right name) contexts content | isInternalName name - , any isBinding contexts - = Html.thespan content ! [ Html.identifier $ internalAnchorIdent name ] + , any isBinding contexts = + Html.thespan content ! [Html.identifier $ internalAnchorIdent name] internalAnchor _ _ content = content externalAnchorIdent :: Name -> String @@ -244,51 +258,52 @@ internalAnchorIdent = ("local-" ++) . show . getKey . nameUnique -- | Generate the HTML hyperlink for an identifier hyperlink :: SrcMaps -> Identifier -> Html -> Html hyperlink (srcs, srcs') ident = case ident of - Right name | isInternalName name -> internalHyperlink name - | otherwise -> externalNameHyperlink name - Left name -> externalModHyperlink name - + Right name + | isInternalName name -> internalHyperlink name + | otherwise -> externalNameHyperlink name + Left name -> externalModHyperlink name where -- In a Nix environment, we have file:// URLs with absolute paths makeHyperlinkUrl url | List.isPrefixOf "file://" url = url makeHyperlinkUrl url = ".." url internalHyperlink name content = - Html.anchor content ! [ Html.href $ "#" ++ internalAnchorIdent name ] + Html.anchor content ! [Html.href $ "#" ++ internalAnchorIdent name] externalNameHyperlink name content = case Map.lookup mdl srcs of - Just SrcLocal -> Html.anchor content ! - [ Html.href $ hypSrcModuleNameUrl mdl name ] - Just (SrcExternal path) -> - let hyperlinkUrl = makeHyperlinkUrl path hypSrcModuleNameUrl mdl name - in Html.anchor content ! - [ Html.href $ spliceURL (Just mdl) (Just name) Nothing hyperlinkUrl ] - Nothing -> content + Just SrcLocal -> + Html.anchor content + ! [Html.href $ hypSrcModuleNameUrl mdl name] + Just (SrcExternal path) -> + let hyperlinkUrl = makeHyperlinkUrl path hypSrcModuleNameUrl mdl name + in Html.anchor content + ! [Html.href $ spliceURL (Just mdl) (Just name) Nothing hyperlinkUrl] + Nothing -> content where mdl = nameModule name externalModHyperlink moduleName content = - case Map.lookup moduleName srcs' of - Just SrcLocal -> Html.anchor content ! - [ Html.href $ hypSrcModuleUrl' moduleName ] - Just (SrcExternal path) -> - let hyperlinkUrl = makeHyperlinkUrl path hypSrcModuleUrl' moduleName - in Html.anchor content ! - [ Html.href $ spliceURL' (Just moduleName) Nothing Nothing hyperlinkUrl ] - Nothing -> content - + case Map.lookup moduleName srcs' of + Just SrcLocal -> + Html.anchor content + ! [Html.href $ hypSrcModuleUrl' moduleName] + Just (SrcExternal path) -> + let hyperlinkUrl = makeHyperlinkUrl path hypSrcModuleUrl' moduleName + in Html.anchor content + ! [Html.href $ spliceURL' (Just moduleName) Nothing Nothing hyperlinkUrl] + Nothing -> content renderSpace :: Int -> String -> Html renderSpace !_ "" = Html.noHtml -renderSpace !line ('\n':rest) = mconcat +renderSpace !line ('\n' : rest) = + mconcat [ Html.thespan (Html.toHtml '\n') , lineAnchor (line + 1) , renderSpace (line + 1) rest ] renderSpace line space = - let (hspace, rest) = span (/= '\n') space - in (Html.thespan . Html.toHtml) hspace <> renderSpace line rest - + let (hspace, rest) = span (/= '\n') space + in (Html.thespan . Html.toHtml) hspace <> renderSpace line rest lineAnchor :: Int -> Html -lineAnchor line = Html.thespan Html.noHtml ! [ Html.identifier $ hypSrcLineUrl line ] +lineAnchor line = Html.thespan Html.noHtml ! [Html.identifier $ hypSrcLineUrl line] diff --git a/haddock-api/src/Haddock/Backends/Hyperlinker/Types.hs b/haddock-api/src/Haddock/Backends/Hyperlinker/Types.hs index 50916937ef..2ed49f9b60 100644 --- a/haddock-api/src/Haddock/Backends/Hyperlinker/Types.hs +++ b/haddock-api/src/Haddock/Backends/Hyperlinker/Types.hs @@ -1,51 +1,53 @@ -{-# LANGUAGE PatternSynonyms, OverloadedStrings #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE PatternSynonyms #-} + module Haddock.Backends.Hyperlinker.Types where import qualified GHC -import Data.ByteString ( ByteString ) +import Data.ByteString (ByteString) import Data.Map (Map) data Token = Token - { tkType :: TokenType - , tkValue :: ByteString -- ^ UTF-8 encoded - , tkSpan :: {-# UNPACK #-} !Span - } - deriving (Show) + { tkType :: TokenType + , tkValue :: ByteString + -- ^ UTF-8 encoded + , tkSpan :: {-# UNPACK #-} !Span + } + deriving (Show) pattern BacktickTok, OpenParenTok, CloseParenTok :: Span -> Token -pattern BacktickTok sp = Token TkSpecial "`" sp -pattern OpenParenTok sp = Token TkSpecial "(" sp +pattern BacktickTok sp = Token TkSpecial "`" sp +pattern OpenParenTok sp = Token TkSpecial "(" sp pattern CloseParenTok sp = Token TkSpecial ")" sp type Position = GHC.RealSrcLoc type Span = GHC.RealSrcSpan data TokenType - = TkIdentifier - | TkKeyword - | TkString - | TkChar - | TkNumber - | TkOperator - | TkGlyph - | TkSpecial - | TkSpace - | TkComment - | TkCpp - | TkPragma - | TkUnknown - deriving (Show, Eq) + = TkIdentifier + | TkKeyword + | TkString + | TkChar + | TkNumber + | TkOperator + | TkGlyph + | TkSpecial + | TkSpace + | TkComment + | TkCpp + | TkPragma + | TkUnknown + deriving (Show, Eq) -- | Path for making cross-package hyperlinks in generated sources. -- -- Used in 'SrcMap' to determine whether module originates in current package -- or in an external package. data SrcPath - = SrcExternal FilePath - | SrcLocal + = SrcExternal FilePath + | SrcLocal -- | Mapping from modules to cross-package source paths. type SrcMaps = (Map GHC.Module SrcPath, Map GHC.ModuleName SrcPath) - diff --git a/haddock-api/src/Haddock/Backends/Hyperlinker/Utils.hs b/haddock-api/src/Haddock/Backends/Hyperlinker/Utils.hs index 5124480a66..0274cd0a38 100644 --- a/haddock-api/src/Haddock/Backends/Hyperlinker/Utils.hs +++ b/haddock-api/src/Haddock/Backends/Hyperlinker/Utils.hs @@ -1,34 +1,40 @@ {-# LANGUAGE OverloadedStrings #-} + module Haddock.Backends.Hyperlinker.Utils - ( hypSrcDir, hypSrcModuleFile, hypSrcModuleFile' - , hypSrcModuleUrl, hypSrcModuleUrl' - , hypSrcNameUrl - , hypSrcLineUrl - , hypSrcModuleNameUrl, hypSrcModuleLineUrl - , hypSrcModuleUrlFormat - , hypSrcModuleNameUrlFormat, hypSrcModuleLineUrlFormat - , spliceURL, spliceURL' + ( hypSrcDir + , hypSrcModuleFile + , hypSrcModuleFile' + , hypSrcModuleUrl + , hypSrcModuleUrl' + , hypSrcNameUrl + , hypSrcLineUrl + , hypSrcModuleNameUrl + , hypSrcModuleLineUrl + , hypSrcModuleUrlFormat + , hypSrcModuleNameUrlFormat + , hypSrcModuleLineUrlFormat + , spliceURL + , spliceURL' -- * HIE file processing - , PrintedType - , recoverFullIfaceTypes - ) where + , PrintedType + , recoverFullIfaceTypes + ) where -import Haddock.Utils import Haddock.Backends.Xhtml.Utils +import Haddock.Utils import GHC -import GHC.Iface.Ext.Types ( HieAST(..), HieType(..), HieArgs(..), TypeIndex, HieTypeFlat ) +import GHC.Driver.Ppr (showSDoc) +import GHC.Iface.Ext.Types (HieAST (..), HieArgs (..), HieType (..), HieTypeFlat, TypeIndex) import GHC.Iface.Type -import GHC.Types.Name ( getOccFS, getOccString ) -import GHC.Driver.Ppr ( showSDoc ) -import GHC.Types.Var ( VarBndr(..), visArg, invisArg, TypeOrConstraint(..) ) +import GHC.Types.Name (getOccFS, getOccString) +import GHC.Types.Var (TypeOrConstraint (..), VarBndr (..), invisArg, visArg) -import System.FilePath.Posix ((), (<.>)) +import System.FilePath.Posix ((<.>), ()) import qualified Data.Array as A - {-# INLINE hypSrcDir #-} hypSrcDir :: FilePath hypSrcDir = "src" @@ -38,8 +44,12 @@ hypSrcModuleFile :: Module -> FilePath hypSrcModuleFile m = moduleNameString (moduleName m) <.> "html" hypSrcModuleFile' :: ModuleName -> FilePath -hypSrcModuleFile' mdl = spliceURL' - (Just mdl) Nothing Nothing moduleFormat +hypSrcModuleFile' mdl = + spliceURL' + (Just mdl) + Nothing + Nothing + moduleFormat hypSrcModuleUrl :: Module -> String hypSrcModuleUrl = hypSrcModuleFile @@ -81,7 +91,6 @@ nameFormat = "%{NAME}" lineFormat :: String lineFormat = "line-%{LINE}" - -- * HIE file processing -- This belongs in GHC.Iface.Ext.Utils... @@ -106,12 +115,14 @@ type PrintedType = String -- function fixes that. recoverFullIfaceTypes :: DynFlags - -> A.Array TypeIndex HieTypeFlat -- ^ flat types - -> HieAST TypeIndex -- ^ flattened AST - -> HieAST PrintedType -- ^ full AST + -> A.Array TypeIndex HieTypeFlat + -- ^ flat types + -> HieAST TypeIndex + -- ^ flattened AST + -> HieAST PrintedType + -- ^ full AST recoverFullIfaceTypes df flattened ast = fmap (printed A.!) ast - where - + where -- Splitting this out into its own array is also important: we don't want -- to pretty print the same type many times printed :: A.Array TypeIndex PrintedType @@ -127,10 +138,11 @@ recoverFullIfaceTypes df flattened ast = fmap (printed A.!) ast go (HTyVarTy n) = IfaceTyVar (mkIfLclName $ getOccFS n) go (HAppTy a b) = IfaceAppTy a (hieToIfaceArgs b) go (HLitTy l) = IfaceLitTy l - go (HForAllTy ((n,k),af) t) = let b = (mkIfLclName $ getOccFS n, k) - in IfaceForAllTy (Bndr (IfaceTvBndr b) af) t - go (HFunTy w a b) = IfaceFunTy (visArg TypeLike) w a b -- t1 -> t2 - go (HQualTy con b) = IfaceFunTy (invisArg TypeLike) many_ty con b -- c => t + go (HForAllTy ((n, k), af) t) = + let b = (mkIfLclName $ getOccFS n, k) + in IfaceForAllTy (Bndr (IfaceTvBndr b) af) t + go (HFunTy w a b) = IfaceFunTy (visArg TypeLike) w a b -- t1 -> t2 + go (HQualTy con b) = IfaceFunTy (invisArg TypeLike) many_ty con b -- c => t go (HCastTy a) = a go HCoercionTy = IfaceTyVar $ mkIfLclName "" go (HTyConApp a xs) = IfaceTyConApp a (hieToIfaceArgs xs) @@ -140,5 +152,5 @@ recoverFullIfaceTypes df flattened ast = fmap (printed A.!) ast hieToIfaceArgs (HieArgs args) = go' args where go' [] = IA_Nil - go' ((True ,x):xs) = IA_Arg x Required $ go' xs - go' ((False,x):xs) = IA_Arg x Specified $ go' xs + go' ((True, x) : xs) = IA_Arg x Required $ go' xs + go' ((False, x) : xs) = IA_Arg x Specified $ go' xs diff --git a/haddock-api/src/Haddock/Backends/LaTeX.hs b/haddock-api/src/Haddock/Backends/LaTeX.hs index d5ba315d86..b15cec989c 100644 --- a/haddock-api/src/Haddock/Backends/LaTeX.hs +++ b/haddock-api/src/Haddock/Backends/LaTeX.hs @@ -1,9 +1,12 @@ -{-# OPTIONS_GHC -fno-warn-name-shadowing #-} +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE FlexibleInstances #-} +{-# OPTIONS_GHC -fno-warn-name-shadowing #-} ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.Backends.LaTeX -- Copyright : (c) Simon Marlow 2010, @@ -13,35 +16,34 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------ -module Haddock.Backends.LaTeX ( - ppLaTeX, -) where +module Haddock.Backends.LaTeX + ( ppLaTeX + ) where import Documentation.Haddock.Markup +import GHC.Utils.Ppr hiding (Doc, quote) +import qualified GHC.Utils.Ppr as Pretty import Haddock.Doc (combineDocumentation) +import Haddock.GhcUtils import Haddock.Types import Haddock.Utils -import Haddock.GhcUtils -import GHC.Utils.Ppr hiding (Doc, quote) -import qualified GHC.Utils.Ppr as Pretty -import GHC hiding (fromMaybeContext ) +import GHC hiding (fromMaybeContext) +import GHC.Core.Type (Specificity (..)) +import GHC.Data.FastString (unpackFS) +import GHC.Types.Name (getOccString, nameOccName, tidyNameOcc) import GHC.Types.Name.Occurrence -import GHC.Types.Name ( nameOccName, getOccString, tidyNameOcc ) -import GHC.Types.Name.Reader ( rdrNameOcc ) -import GHC.Core.Type ( Specificity(..) ) -import GHC.Data.FastString ( unpackFS ) +import GHC.Types.Name.Reader (rdrNameOcc) +import Control.Monad +import Data.Char +import Data.Foldable (toList) +import Data.List (sort) +import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.Map as Map +import Data.Maybe import System.Directory import System.FilePath -import Data.Char -import Control.Monad -import Data.Maybe -import Data.List ( sort ) -import Data.List.NonEmpty ( NonEmpty (..) ) -import Data.Foldable ( toList ) import Prelude hiding ((<>)) {- SAMPLE OUTPUT @@ -73,33 +75,30 @@ Extract the last element of a list, which must be finite and non-empty. \end{haddockdesc} -} - {- TODO * don't forget fixity!! -} -ppLaTeX :: String -- Title - -> Maybe String -- Package name - -> [Interface] - -> FilePath -- destination directory - -> Maybe (Doc GHC.RdrName) -- prologue text, maybe - -> Maybe String -- style file - -> FilePath - -> IO () - -ppLaTeX title packageStr visible_ifaces odir prologue maybe_style libdir - = do - createDirectoryIfMissing True odir - when (isNothing maybe_style) $ - copyFile (libdir "latex" haddockSty) (odir haddockSty) - ppLaTeXTop title packageStr odir prologue maybe_style visible_ifaces - mapM_ (ppLaTeXModule title odir) visible_ifaces - +ppLaTeX + :: String -- Title + -> Maybe String -- Package name + -> [Interface] + -> FilePath -- destination directory + -> Maybe (Doc GHC.RdrName) -- prologue text, maybe + -> Maybe String -- style file + -> FilePath + -> IO () +ppLaTeX title packageStr visible_ifaces odir prologue maybe_style libdir = + do + createDirectoryIfMissing True odir + when (isNothing maybe_style) $ + copyFile (libdir "latex" haddockSty) (odir haddockSty) + ppLaTeXTop title packageStr odir prologue maybe_style visible_ifaces + mapM_ (ppLaTeXModule title odir) visible_ifaces haddockSty :: FilePath haddockSty = "haddock.sty" - type LaTeX = Pretty.Doc -- | Default way of rendering a 'LaTeX'. The width is 90 by default (since 100 @@ -108,403 +107,474 @@ latex2String :: LaTeX -> String latex2String = fullRender (PageMode True) 90 1 txtPrinter "" ppLaTeXTop - :: String - -> Maybe String - -> FilePath - -> Maybe (Doc GHC.RdrName) - -> Maybe String - -> [Interface] - -> IO () - + :: String + -> Maybe String + -> FilePath + -> Maybe (Doc GHC.RdrName) + -> Maybe String + -> [Interface] + -> IO () ppLaTeXTop doctitle packageStr odir prologue maybe_style ifaces = do + let tex = + vcat + [ text "\\documentclass{book}" + , text "\\usepackage" <> braces (maybe (text "haddock") text maybe_style) + , text "\\begin{document}" + , text "\\begin{titlepage}" + , text "\\begin{haddocktitle}" + , text doctitle + , text "\\end{haddocktitle}" + , case prologue of + Nothing -> empty + Just d -> + vcat + [ text "\\begin{haddockprologue}" + , rdrDocToLaTeX d + , text "\\end{haddockprologue}" + ] + , text "\\end{titlepage}" + , text "\\tableofcontents" + , vcat [text "\\input" <> braces (text mdl) | mdl <- mods] + , text "\\end{document}" + ] - let tex = vcat [ - text "\\documentclass{book}", - text "\\usepackage" <> braces (maybe (text "haddock") text maybe_style), - text "\\begin{document}", - text "\\begin{titlepage}", - text "\\begin{haddocktitle}", - text doctitle, - text "\\end{haddocktitle}", - case prologue of - Nothing -> empty - Just d -> vcat [text "\\begin{haddockprologue}", - rdrDocToLaTeX d, - text "\\end{haddockprologue}"], - text "\\end{titlepage}", - text "\\tableofcontents", - vcat [ text "\\input" <> braces (text mdl) | mdl <- mods ], - text "\\end{document}" - ] - - mods = sort (map (moduleBasename.ifaceMod) ifaces) + mods = sort (map (moduleBasename . ifaceMod) ifaces) filename = odir (fromMaybe "haddock" packageStr <.> "tex") writeUtf8File filename (show tex) - ppLaTeXModule :: String -> FilePath -> Interface -> IO () ppLaTeXModule _title odir iface = do createDirectoryIfMissing True odir let - mdl = ifaceMod iface - mdl_str = moduleString mdl - - exports = ifaceRnExportItems iface - - tex = vcat [ - text "\\haddockmoduleheading" <> braces (text mdl_str), - text "\\label{module:" <> text mdl_str <> char '}', - text "\\haddockbeginheader", - verb $ vcat [ - text "module" <+> text mdl_str <+> lparen, - text " " <> fsep (punctuate (char ',') $ - map exportListItem $ - filter forSummary exports), - text " ) where" - ], - text "\\haddockendheader" $$ text "", - description, - body - ] - - description - = (fromMaybe empty . documentationToLaTeX . ifaceRnDoc) iface - - body = processExports exports + mdl = ifaceMod iface + mdl_str = moduleString mdl + + exports = ifaceRnExportItems iface + + tex = + vcat + [ text "\\haddockmoduleheading" <> braces (text mdl_str) + , text "\\label{module:" <> text mdl_str <> char '}' + , text "\\haddockbeginheader" + , verb $ + vcat + [ text "module" <+> text mdl_str <+> lparen + , text " " + <> fsep + ( punctuate (char ',') $ + map exportListItem $ + filter forSummary exports + ) + , text " ) where" + ] + , text "\\haddockendheader" $$ text "" + , description + , body + ] + + description = + (fromMaybe empty . documentationToLaTeX . ifaceRnDoc) iface + + body = processExports exports -- writeUtf8File (odir moduleLaTeXFile mdl) (fullRender (PageMode True) 80 1 txtPrinter "" tex) -- | Prints out an entry in a module export list. exportListItem :: ExportItem DocNameI -> LaTeX exportListItem - ( ExportDecl + ( ExportDecl ( RnExportD - { rnExpDExpD = - ( ExportD - { expDDecl = decl - , expDSubDocs = subdocs - } - ) - } - ) - ) - = let (leader, names) = declNames decl - go (n,_) + { rnExpDExpD = + ( ExportD + { expDDecl = decl + , expDSubDocs = subdocs + } + ) + } + ) + ) = + let (leader, names) = declNames decl + go (n, _) | isDefaultMethodOcc (occName n) = Nothing | otherwise = Just $ ppDocBinder n - - in sep (punctuate comma [ leader <+> ppDocBinder name | name <- names ]) <> - case subdocs of - [] -> empty - _ -> parens (sep (punctuate comma (mapMaybe go subdocs))) - -exportListItem (ExportNoDecl y []) - = ppDocBinder y -exportListItem (ExportNoDecl y subs) - = ppDocBinder y <> parens (sep (punctuate comma (map ppDocBinder subs))) -exportListItem (ExportModule mdl) - = text "module" <+> text (moduleString mdl) -exportListItem _ - = error "exportListItem" - + in sep (punctuate comma [leader <+> ppDocBinder name | name <- names]) + <> case subdocs of + [] -> empty + _ -> parens (sep (punctuate comma (mapMaybe go subdocs))) +exportListItem (ExportNoDecl y []) = + ppDocBinder y +exportListItem (ExportNoDecl y subs) = + ppDocBinder y <> parens (sep (punctuate comma (map ppDocBinder subs))) +exportListItem (ExportModule mdl) = + text "module" <+> text (moduleString mdl) +exportListItem _ = + error "exportListItem" -- Deal with a group of undocumented exports together, to avoid lots -- of blank vertical space between them. processExports :: [ExportItem DocNameI] -> LaTeX processExports [] = empty processExports (decl : es) - | Just sig <- isSimpleSig decl - = multiDecl [ ppTypeSig (map getName names) typ False - | (names,typ) <- sig:sigs ] $$ - processExports es' - where (sigs, es') = spanWith isSimpleSig es -processExports (ExportModule mdl : es) - = declWithDoc (vcat [ text "module" <+> text (moduleString m) | m <- mdl:mdls ]) Nothing $$ - processExports es' - where (mdls, es') = spanWith isExportModule es + | Just sig <- isSimpleSig decl = + multiDecl + [ ppTypeSig (map getName names) typ False + | (names, typ) <- sig : sigs + ] + $$ processExports es' + where + (sigs, es') = spanWith isSimpleSig es +processExports (ExportModule mdl : es) = + declWithDoc (vcat [text "module" <+> text (moduleString m) | m <- mdl : mdls]) Nothing + $$ processExports es' + where + (mdls, es') = spanWith isExportModule es processExports (e : es) = processExport e $$ processExports es - isSimpleSig :: ExportItem DocNameI -> Maybe ([DocName], HsSigType DocNameI) isSimpleSig - ( ExportDecl + ( ExportDecl ( RnExportD - { rnExpDExpD = - ExportD - { expDDecl = L _ (SigD _ (TypeSig _ lnames t)) - , expDMbDoc = (Documentation Nothing Nothing, argDocs) + { rnExpDExpD = + ExportD + { expDDecl = L _ (SigD _ (TypeSig _ lnames t)) + , expDMbDoc = (Documentation Nothing Nothing, argDocs) + } } - } - ) + ) ) | Map.null argDocs = Just (map unLoc lnames, unLoc (dropWildCards t)) isSimpleSig _ = Nothing - isExportModule :: ExportItem DocNameI -> Maybe Module isExportModule (ExportModule m) = Just m isExportModule _ = Nothing - processExport :: ExportItem DocNameI -> LaTeX -processExport (ExportGroup lev _id0 doc) - = ppDocGroup lev (docToLaTeX doc) -processExport (ExportDecl (RnExportD (ExportD decl pats doc subdocs insts fixities _splice) _)) - = ppDecl decl pats doc insts subdocs fixities -processExport (ExportNoDecl y []) - = ppDocName y -processExport (ExportNoDecl y subs) - = ppDocName y <> parens (sep (punctuate comma (map ppDocName subs))) -processExport (ExportModule mdl) - = declWithDoc (text "module" <+> text (moduleString mdl)) Nothing -processExport (ExportDoc doc) - = docToLaTeX $ _doc doc - +processExport (ExportGroup lev _id0 doc) = + ppDocGroup lev (docToLaTeX doc) +processExport (ExportDecl (RnExportD (ExportD decl pats doc subdocs insts fixities _splice) _)) = + ppDecl decl pats doc insts subdocs fixities +processExport (ExportNoDecl y []) = + ppDocName y +processExport (ExportNoDecl y subs) = + ppDocName y <> parens (sep (punctuate comma (map ppDocName subs))) +processExport (ExportModule mdl) = + declWithDoc (text "module" <+> text (moduleString mdl)) Nothing +processExport (ExportDoc doc) = + docToLaTeX $ _doc doc ppDocGroup :: Int -> LaTeX -> LaTeX ppDocGroup lev doc = sec lev <> braces doc - where sec 1 = text "\\section" - sec 2 = text "\\subsection" - sec 3 = text "\\subsubsection" - sec _ = text "\\paragraph" - + where + sec 1 = text "\\section" + sec 2 = text "\\subsection" + sec 3 = text "\\subsubsection" + sec _ = text "\\paragraph" -- | Given a declaration, extract out the names being declared -declNames :: LHsDecl DocNameI - -> ( LaTeX -- to print before each name in an export list - , [DocName] -- names being declared - ) +declNames + :: LHsDecl DocNameI + -> ( LaTeX -- to print before each name in an export list + , [DocName] -- names being declared + ) declNames (L _ decl) = case decl of - TyClD _ d -> (empty, [tcdNameI d]) - SigD _ (TypeSig _ lnames _ ) -> (empty, map unLoc lnames) + TyClD _ d -> (empty, [tcdNameI d]) + SigD _ (TypeSig _ lnames _) -> (empty, map unLoc lnames) SigD _ (PatSynSig _ lnames _) -> (text "pattern", map unLoc lnames) ForD _ (ForeignImport _ (L _ n) _ _) -> (empty, [n]) ForD _ (ForeignExport _ (L _ n) _ _) -> (empty, [n]) _ -> error "declaration not supported by declNames" - forSummary :: (ExportItem DocNameI) -> Bool forSummary (ExportGroup _ _ _) = False -forSummary (ExportDoc _) = False -forSummary _ = True - +forSummary (ExportDoc _) = False +forSummary _ = True moduleLaTeXFile :: Module -> FilePath moduleLaTeXFile mdl = moduleBasename mdl ++ ".tex" - moduleBasename :: Module -> FilePath -moduleBasename mdl = map (\c -> if c == '.' then '-' else c) - (moduleNameString (moduleName mdl)) - +moduleBasename mdl = + map + (\c -> if c == '.' then '-' else c) + (moduleNameString (moduleName mdl)) ------------------------------------------------------------------------------- + -- * Decls + ------------------------------------------------------------------------------- -- | Pretty print a declaration -ppDecl :: LHsDecl DocNameI -- ^ decl to print - -> [(HsDecl DocNameI, DocForDecl DocName)] -- ^ all pattern decls - -> DocForDecl DocName -- ^ documentation for decl - -> [DocInstance DocNameI] -- ^ all instances - -> [(DocName, DocForDecl DocName)] -- ^ all subdocs - -> [(DocName, Fixity)] -- ^ all fixities - -> LaTeX - +ppDecl + :: LHsDecl DocNameI + -- ^ decl to print + -> [(HsDecl DocNameI, DocForDecl DocName)] + -- ^ all pattern decls + -> DocForDecl DocName + -- ^ documentation for decl + -> [DocInstance DocNameI] + -- ^ all instances + -> [(DocName, DocForDecl DocName)] + -- ^ all subdocs + -> [(DocName, Fixity)] + -- ^ all fixities + -> LaTeX ppDecl decl pats (doc, fnArgsDoc) instances subdocs _fxts = case unLoc decl of - TyClD _ d@FamDecl {} -> ppFamDecl False doc instances d unicode - TyClD _ d@DataDecl {} -> ppDataDecl pats instances subdocs (Just doc) d unicode - TyClD _ d@SynDecl {} -> ppTySyn (doc, fnArgsDoc) d unicode - TyClD _ d@ClassDecl{} -> ppClassDecl instances doc subdocs d unicode - SigD _ (TypeSig _ lnames ty) -> ppFunSig Nothing (doc, fnArgsDoc) (map unLoc lnames) (dropWildCards ty) unicode + TyClD _ d@FamDecl{} -> ppFamDecl False doc instances d unicode + TyClD _ d@DataDecl{} -> ppDataDecl pats instances subdocs (Just doc) d unicode + TyClD _ d@SynDecl{} -> ppTySyn (doc, fnArgsDoc) d unicode + TyClD _ d@ClassDecl{} -> ppClassDecl instances doc subdocs d unicode + SigD _ (TypeSig _ lnames ty) -> ppFunSig Nothing (doc, fnArgsDoc) (map unLoc lnames) (dropWildCards ty) unicode SigD _ (PatSynSig _ lnames ty) -> ppLPatSig (doc, fnArgsDoc) (map unLoc lnames) ty unicode - ForD _ d -> ppFor (doc, fnArgsDoc) d unicode - InstD _ _ -> empty - DerivD _ _ -> empty - _ -> error "declaration not supported by ppDecl" + ForD _ d -> ppFor (doc, fnArgsDoc) d unicode + InstD _ _ -> empty + DerivD _ _ -> empty + _ -> error "declaration not supported by ppDecl" where unicode = False - ppFor :: DocForDecl DocName -> ForeignDecl DocNameI -> Bool -> LaTeX ppFor doc (ForeignImport _ (L _ name) typ _) unicode = ppFunSig Nothing doc [name] typ unicode ppFor _ _ _ = error "ppFor error in Haddock.Backends.LaTeX" --- error "foreign declarations are currently not supported by --latex" +-- error "foreign declarations are currently not supported by --latex" ------------------------------------------------------------------------------- + -- * Type families + ------------------------------------------------------------------------------- -- | Pretty-print a data\/type family declaration -ppFamDecl :: Bool -- ^ is the family associated? - -> Documentation DocName -- ^ this decl's docs - -> [DocInstance DocNameI] -- ^ relevant instances - -> TyClDecl DocNameI -- ^ family to print - -> Bool -- ^ unicode - -> LaTeX +ppFamDecl + :: Bool + -- ^ is the family associated? + -> Documentation DocName + -- ^ this decl's docs + -> [DocInstance DocNameI] + -- ^ relevant instances + -> TyClDecl DocNameI + -- ^ family to print + -> Bool + -- ^ unicode + -> LaTeX ppFamDecl associated doc instances decl unicode = - declWithDoc (ppFamHeader (tcdFam decl) unicode associated <+> whereBit) - (if null body then Nothing else Just (vcat body)) - $$ instancesBit + declWithDoc + (ppFamHeader (tcdFam decl) unicode associated <+> whereBit) + (if null body then Nothing else Just (vcat body)) + $$ instancesBit where body = catMaybes [familyEqns, documentationToLaTeX doc] whereBit = case fdInfo (tcdFam decl) of ClosedTypeFamily _ -> keyword "where" - _ -> empty + _ -> empty familyEqns - | FamilyDecl { fdInfo = ClosedTypeFamily (Just eqns) } <- tcdFam decl - , not (null eqns) - = Just (text "\\haddockbeginargs" $$ - vcat [ decltt (ppFamDeclEqn eqn) <+> nl | L _ eqn <- eqns ] $$ - text "\\end{tabulary}\\par") + | FamilyDecl{fdInfo = ClosedTypeFamily (Just eqns)} <- tcdFam decl + , not (null eqns) = + Just + ( text "\\haddockbeginargs" + $$ vcat [decltt (ppFamDeclEqn eqn) <+> nl | L _ eqn <- eqns] + $$ text "\\end{tabulary}\\par" + ) | otherwise = Nothing -- Individual equations of a closed type family ppFamDeclEqn :: TyFamInstEqn DocNameI -> LaTeX - ppFamDeclEqn (FamEqn { feqn_tycon = L _ n - , feqn_rhs = rhs - , feqn_pats = ts }) - = hsep [ ppAppNameTypeArgs n ts unicode - , equals - , ppType unicode (unLoc rhs) - ] + ppFamDeclEqn + ( FamEqn + { feqn_tycon = L _ n + , feqn_rhs = rhs + , feqn_pats = ts + } + ) = + hsep + [ ppAppNameTypeArgs n ts unicode + , equals + , ppType unicode (unLoc rhs) + ] instancesBit = ppDocInstances unicode instances -- | Print the LHS of a type\/data family declaration. -ppFamHeader :: FamilyDecl DocNameI -- ^ family header to print - -> Bool -- ^ unicode - -> Bool -- ^ is the family associated? - -> LaTeX -ppFamHeader (FamilyDecl { fdLName = L _ name - , fdTyVars = tvs - , fdInfo = info - , fdResultSig = L _ result - , fdInjectivityAnn = injectivity }) - unicode associated = - famly leader <+> famName <+> famSig <+> injAnn - where - leader = case info of - OpenTypeFamily -> keyword "type" - ClosedTypeFamily _ -> keyword "type" - DataFamily -> keyword "data" - - famly | associated = id - | otherwise = (<+> keyword "family") - - famName = ppAppDocNameTyVarBndrs unicode name (hsq_explicit tvs) - - famSig = case result of - NoSig _ -> empty - KindSig _ kind -> dcolon unicode <+> ppLKind unicode kind - TyVarSig _ (L _ bndr) -> equals <+> ppHsTyVarBndr unicode bndr - - injAnn = case injectivity of - Nothing -> empty - Just (L _ (InjectivityAnn _ lhs rhs)) -> hsep ( decltt (text "|") - : ppLDocName lhs - : arrow unicode - : map ppLDocName rhs) - Just _ -> empty - - +ppFamHeader + :: FamilyDecl DocNameI + -- ^ family header to print + -> Bool + -- ^ unicode + -> Bool + -- ^ is the family associated? + -> LaTeX +ppFamHeader + ( FamilyDecl + { fdLName = L _ name + , fdTyVars = tvs + , fdInfo = info + , fdResultSig = L _ result + , fdInjectivityAnn = injectivity + } + ) + unicode + associated = + famly leader <+> famName <+> famSig <+> injAnn + where + leader = case info of + OpenTypeFamily -> keyword "type" + ClosedTypeFamily _ -> keyword "type" + DataFamily -> keyword "data" + + famly + | associated = id + | otherwise = (<+> keyword "family") + + famName = ppAppDocNameTyVarBndrs unicode name (hsq_explicit tvs) + + famSig = case result of + NoSig _ -> empty + KindSig _ kind -> dcolon unicode <+> ppLKind unicode kind + TyVarSig _ (L _ bndr) -> equals <+> ppHsTyVarBndr unicode bndr + + injAnn = case injectivity of + Nothing -> empty + Just (L _ (InjectivityAnn _ lhs rhs)) -> + hsep + ( decltt (text "|") + : ppLDocName lhs + : arrow unicode + : map ppLDocName rhs + ) + Just _ -> empty ------------------------------------------------------------------------------- + -- * Type Synonyms -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- -- we skip type patterns for now ppTySyn :: DocForDecl DocName -> TyClDecl DocNameI -> Bool -> LaTeX - -ppTySyn doc (SynDecl { tcdLName = L _ name, tcdTyVars = ltyvars - , tcdRhs = ltype }) unicode - = ppTypeOrFunSig (mkHsImplicitSigTypeI ltype) doc (full, hdr, char '=') unicode - where - hdr = hsep (keyword "type" - : ppDocBinder name - : map ppSymName (tyvarNames ltyvars)) - full = hdr <+> char '=' <+> ppLType unicode ltype - +ppTySyn + doc + ( SynDecl + { tcdLName = L _ name + , tcdTyVars = ltyvars + , tcdRhs = ltype + } + ) + unicode = + ppTypeOrFunSig (mkHsImplicitSigTypeI ltype) doc (full, hdr, char '=') unicode + where + hdr = + hsep + ( keyword "type" + : ppDocBinder name + : map ppSymName (tyvarNames ltyvars) + ) + full = hdr <+> char '=' <+> ppLType unicode ltype ppTySyn _ _ _ = error "declaration not supported by ppTySyn" - ------------------------------------------------------------------------------- + -- * Function signatures -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- ppFunSig - :: Maybe LaTeX -- ^ a prefix to put right before the signature - -> DocForDecl DocName -- ^ documentation - -> [DocName] -- ^ pattern names in the pattern signature - -> LHsSigType DocNameI -- ^ type of the pattern synonym - -> Bool -- ^ unicode + :: Maybe LaTeX + -- ^ a prefix to put right before the signature + -> DocForDecl DocName + -- ^ documentation + -> [DocName] + -- ^ pattern names in the pattern signature + -> LHsSigType DocNameI + -- ^ type of the pattern synonym + -> Bool + -- ^ unicode -> LaTeX ppFunSig leader doc docnames (L _ typ) unicode = - ppTypeOrFunSig typ doc + ppTypeOrFunSig + typ + doc ( lead $ ppTypeSig names typ False , lead $ hsep . punctuate comma $ map ppSymName names , dcolon unicode ) unicode - where - names = map getName docnames - lead = maybe id (<+>) leader + where + names = map getName docnames + lead = maybe id (<+>) leader -- | Pretty-print a pattern synonym -ppLPatSig :: DocForDecl DocName -- ^ documentation - -> [DocName] -- ^ pattern names in the pattern signature - -> LHsSigType DocNameI -- ^ type of the pattern synonym - -> Bool -- ^ unicode - -> LaTeX -ppLPatSig doc docnames ty unicode - = ppFunSig (Just (keyword "pattern")) doc docnames ty unicode +ppLPatSig + :: DocForDecl DocName + -- ^ documentation + -> [DocName] + -- ^ pattern names in the pattern signature + -> LHsSigType DocNameI + -- ^ type of the pattern synonym + -> Bool + -- ^ unicode + -> LaTeX +ppLPatSig doc docnames ty unicode = + ppFunSig (Just (keyword "pattern")) doc docnames ty unicode -- | Pretty-print a type, adding documentation to the whole type and its -- arguments as needed. -ppTypeOrFunSig :: HsSigType DocNameI - -> DocForDecl DocName -- ^ documentation - -> ( LaTeX -- first-line (no-argument docs only) - , LaTeX -- first-line (argument docs only) - , LaTeX -- type prefix (argument docs only) - ) - -> Bool -- ^ unicode - -> LaTeX +ppTypeOrFunSig + :: HsSigType DocNameI + -> DocForDecl DocName + -- ^ documentation + -> ( LaTeX -- first-line (no-argument docs only) + , LaTeX -- first-line (argument docs only) + , LaTeX -- type prefix (argument docs only) + ) + -> Bool + -- ^ unicode + -> LaTeX ppTypeOrFunSig typ (doc, argDocs) (pref1, pref2, sep0) unicode | Map.null argDocs = declWithDoc pref1 (documentationToLaTeX doc) - | otherwise = declWithDoc pref2 $ Just $ - text "\\haddockbeginargs" $$ - vcat (map (uncurry (<->)) (ppSubSigLike unicode typ argDocs [] sep0)) $$ - text "\\end{tabulary}\\par" $$ - fromMaybe empty (documentationToLaTeX doc) + | otherwise = + declWithDoc pref2 $ + Just $ + text "\\haddockbeginargs" + $$ vcat (map (uncurry (<->)) (ppSubSigLike unicode typ argDocs [] sep0)) + $$ text "\\end{tabulary}\\par" + $$ fromMaybe empty (documentationToLaTeX doc) -- | This splits up a type signature along @->@ and adds docs (when they exist) -- to the arguments. The output is a list of (leader/seperator, argument and -- its doc) -ppSubSigLike :: Bool -- ^ unicode - -> HsSigType DocNameI -- ^ type signature - -> FnArgsDoc DocName -- ^ docs to add - -> [(DocName, DocForDecl DocName)] -- ^ all subdocs (useful when we have `HsRecTy`) - -> LaTeX -- ^ seperator (beginning of first line) - -> [(LaTeX, LaTeX)] -- ^ arguments (leader/sep, type) +ppSubSigLike + :: Bool + -- ^ unicode + -> HsSigType DocNameI + -- ^ type signature + -> FnArgsDoc DocName + -- ^ docs to add + -> [(DocName, DocForDecl DocName)] + -- ^ all subdocs (useful when we have `HsRecTy`) + -> LaTeX + -- ^ seperator (beginning of first line) + -> [(LaTeX, LaTeX)] + -- ^ arguments (leader/sep, type) ppSubSigLike unicode typ argDocs subdocs leader = do_sig_args 0 leader typ where do_sig_args :: Int -> LaTeX -> HsSigType DocNameI -> [(LaTeX, LaTeX)] - do_sig_args n leader (HsSig { sig_bndrs = outer_bndrs, sig_body = ltype }) = + do_sig_args n leader (HsSig{sig_bndrs = outer_bndrs, sig_body = ltype}) = case outer_bndrs of HsOuterExplicit{hso_bndrs = bndrs} -> - [ ( decltt leader + [ + ( decltt leader , decltt (ppHsForAllTelescope (mkHsForAllInvisTeleI bndrs) unicode) <+> ppLType unicode ltype - ) ] + ) + ] HsOuterImplicit{} -> do_largs n leader ltype do_largs :: Int -> LaTeX -> LHsType DocNameI -> [(LaTeX, LaTeX)] @@ -513,27 +583,29 @@ ppSubSigLike unicode typ argDocs subdocs leader = do_sig_args 0 leader typ arg_doc n = rDoc . fmap _doc $ Map.lookup n argDocs do_args :: Int -> LaTeX -> HsType DocNameI -> [(LaTeX, LaTeX)] - do_args _n leader (HsForAllTy _ tele ltype) - = [ ( decltt leader - , decltt (ppHsForAllTelescope tele unicode) - <+> ppLType unicode ltype - ) ] - do_args n leader (HsQualTy _ lctxt ltype) - = ( decltt leader - , decltt (ppLContextNoArrow lctxt unicode) <+> nl - ) : do_largs n (darrow unicode) ltype - - do_args n leader (HsFunTy _ _w (L _ (HsRecTy _ fields)) r) - = [ (decltt ldr, latex <+> nl) - | (L _ field, ldr) <- zip fields (leader <+> gadtOpen : repeat gadtComma) - , let latex = ppSideBySideField subdocs unicode field - ] - ++ do_largs (n+1) (gadtEnd <+> arrow unicode) r - do_args n leader (HsFunTy _ _w lt r) - = (decltt leader, decltt (ppLFunLhType unicode lt) <-> arg_doc n <+> nl) - : do_largs (n+1) (arrow unicode) r - do_args n leader t - = [ (decltt leader, decltt (ppType unicode t) <-> arg_doc n <+> nl) ] + do_args _n leader (HsForAllTy _ tele ltype) = + [ + ( decltt leader + , decltt (ppHsForAllTelescope tele unicode) + <+> ppLType unicode ltype + ) + ] + do_args n leader (HsQualTy _ lctxt ltype) = + ( decltt leader + , decltt (ppLContextNoArrow lctxt unicode) <+> nl + ) + : do_largs n (darrow unicode) ltype + do_args n leader (HsFunTy _ _w (L _ (HsRecTy _ fields)) r) = + [ (decltt ldr, latex <+> nl) + | (L _ field, ldr) <- zip fields (leader <+> gadtOpen : repeat gadtComma) + , let latex = ppSideBySideField subdocs unicode field + ] + ++ do_largs (n + 1) (gadtEnd <+> arrow unicode) r + do_args n leader (HsFunTy _ _w lt r) = + (decltt leader, decltt (ppLFunLhType unicode lt) <-> arg_doc n <+> nl) + : do_largs (n + 1) (arrow unicode) r + do_args n leader t = + [(decltt leader, decltt (ppType unicode t) <-> arg_doc n <+> nl)] -- FIXME: this should be done more elegantly -- @@ -544,8 +616,7 @@ ppSubSigLike unicode typ argDocs subdocs leader = do_sig_args 0 leader typ gadtEnd = hcat (replicate (if unicode then 3 else 4) (char ' ')) <> char '}' gadtOpen = char '{' - -ppTypeSig :: [Name] -> HsSigType DocNameI -> Bool -> LaTeX +ppTypeSig :: [Name] -> HsSigType DocNameI -> Bool -> LaTeX ppTypeSig nms ty unicode = hsep (punctuate comma $ map ppSymName nms) <+> dcolon unicode @@ -554,158 +625,176 @@ ppTypeSig nms ty unicode = ppHsOuterTyVarBndrs :: RenderableBndrFlag flag => HsOuterTyVarBndrs flag DocNameI -> Bool -> LaTeX ppHsOuterTyVarBndrs (HsOuterImplicit{}) _ = empty ppHsOuterTyVarBndrs (HsOuterExplicit{hso_bndrs = bndrs}) unicode = - hsep (forallSymbol unicode : ppTyVars unicode bndrs) <> dot + hsep (forallSymbol unicode : ppTyVars unicode bndrs) <> dot ppHsForAllTelescope :: HsForAllTelescope DocNameI -> Bool -> LaTeX ppHsForAllTelescope tele unicode = case tele of - HsForAllVis { hsf_vis_bndrs = bndrs } -> + HsForAllVis{hsf_vis_bndrs = bndrs} -> hsep (forallSymbol unicode : ppTyVars unicode bndrs) <> text "\\" <> arrow unicode - HsForAllInvis { hsf_invis_bndrs = bndrs } -> + HsForAllInvis{hsf_invis_bndrs = bndrs} -> hsep (forallSymbol unicode : ppTyVars unicode bndrs) <> dot - ppTyVars :: RenderableBndrFlag flag => Bool -> [LHsTyVarBndr flag DocNameI] -> [LaTeX] ppTyVars unicode tvs = map (ppHsTyVarBndr unicode . unLoc) tvs - tyvarNames :: LHsQTyVars DocNameI -> [Name] tyvarNames = map (getName . hsLTyVarNameI) . hsQTvExplicit - declWithDoc :: LaTeX -> Maybe LaTeX -> LaTeX declWithDoc decl doc = - text "\\begin{haddockdesc}" $$ - text "\\item[\\begin{tabular}{@{}l}" $$ - text (latexMonoFilter (latex2String decl)) $$ - text "\\end{tabular}]" $$ - maybe empty (\x -> text "{\\haddockbegindoc" $$ x <> text "}") doc $$ - text "\\end{haddockdesc}" - + text "\\begin{haddockdesc}" + $$ text "\\item[\\begin{tabular}{@{}l}" + $$ text (latexMonoFilter (latex2String decl)) + $$ text "\\end{tabular}]" + $$ maybe empty (\x -> text "{\\haddockbegindoc" $$ x <> text "}") doc + $$ text "\\end{haddockdesc}" -- in a group of decls, we don't put them all in the same tabular, -- because that would prevent the group being broken over a page -- boundary (breaks Foreign.C.Error for example). multiDecl :: [LaTeX] -> LaTeX multiDecl decls = - text "\\begin{haddockdesc}" $$ - vcat [ - text "\\item[\\begin{tabular}{@{}l}" $$ - text (latexMonoFilter (latex2String decl)) $$ - text "\\end{tabular}]" - | decl <- decls ] $$ - text "\\end{haddockdesc}" - + text "\\begin{haddockdesc}" + $$ vcat + [ text "\\item[\\begin{tabular}{@{}l}" + $$ text (latexMonoFilter (latex2String decl)) + $$ text "\\end{tabular}]" + | decl <- decls + ] + $$ text "\\end{haddockdesc}" ------------------------------------------------------------------------------- + -- * Rendering Doc -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- maybeDoc :: Maybe (Doc DocName) -> LaTeX maybeDoc = maybe empty docToLaTeX - -- for table cells, we strip paragraphs out to avoid extra vertical space -- and don't add a quote environment. -rDoc :: Maybe (Doc DocName) -> LaTeX +rDoc :: Maybe (Doc DocName) -> LaTeX rDoc = maybeDoc . fmap latexStripTrailingWhitespace - ------------------------------------------------------------------------------- + -- * Class declarations -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- -ppClassHdr :: Bool -> Maybe (LocatedC [LHsType DocNameI]) -> DocName - -> LHsQTyVars DocNameI -> [LHsFunDep DocNameI] - -> Bool -> LaTeX +ppClassHdr + :: Bool + -> Maybe (LocatedC [LHsType DocNameI]) + -> DocName + -> LHsQTyVars DocNameI + -> [LHsFunDep DocNameI] + -> Bool + -> LaTeX ppClassHdr summ lctxt n tvs fds unicode = keyword "class" - <+> (if not (null $ fromMaybeContext lctxt) then ppLContext lctxt unicode else empty) - <+> ppAppDocNameNames summ n (tyvarNames tvs) - <+> ppFds fds unicode + <+> (if not (null $ fromMaybeContext lctxt) then ppLContext lctxt unicode else empty) + <+> ppAppDocNameNames summ n (tyvarNames tvs) + <+> ppFds fds unicode -- ppFds :: [Located ([LocatedA DocName], [LocatedA DocName])] -> Bool -> LaTeX ppFds :: [LHsFunDep DocNameI] -> Bool -> LaTeX ppFds fds unicode = - if null fds then empty else - char '|' <+> hsep (punctuate comma (map (fundep . unLoc) fds)) + if null fds + then empty + else char '|' <+> hsep (punctuate comma (map (fundep . unLoc) fds)) where - fundep (FunDep _ vars1 vars2) - = hsep (map (ppDocName . unLoc) vars1) <+> arrow unicode <+> - hsep (map (ppDocName . unLoc) vars2) + fundep (FunDep _ vars1 vars2) = + hsep (map (ppDocName . unLoc) vars1) + <+> arrow unicode + <+> hsep (map (ppDocName . unLoc) vars2) fundep (XFunDep _) = error "ppFds" - -- TODO: associated type defaults, docs on default methods -ppClassDecl :: [DocInstance DocNameI] - -> Documentation DocName -> [(DocName, DocForDecl DocName)] - -> TyClDecl DocNameI -> Bool -> LaTeX -ppClassDecl instances doc subdocs - (ClassDecl { tcdCtxt = lctxt, tcdLName = lname, tcdTyVars = ltyvars, tcdFDs = lfds - , tcdSigs = lsigs, tcdATs = ats, tcdATDefs = at_defs }) unicode - = declWithDoc classheader (if null body then Nothing else Just (vcat body)) $$ - instancesBit - where - classheader - | null lsigs = hdr unicode - | otherwise = hdr unicode <+> keyword "where" - - hdr = ppClassHdr False lctxt (unLoc lname) ltyvars lfds - - body = catMaybes [documentationToLaTeX doc, body_] - - body_ - | null lsigs, null ats, null at_defs = Nothing - | null ats, null at_defs = Just methodTable - | otherwise = Just (atTable $$ methodTable) - - atTable = - text "\\haddockpremethods{}" <> emph (text "Associated Types") $$ - vcat [ ppFamDecl True (fst doc) [] (FamDecl noExtField decl) True +ppClassDecl + :: [DocInstance DocNameI] + -> Documentation DocName + -> [(DocName, DocForDecl DocName)] + -> TyClDecl DocNameI + -> Bool + -> LaTeX +ppClassDecl + instances + doc + subdocs + ( ClassDecl + { tcdCtxt = lctxt + , tcdLName = lname + , tcdTyVars = ltyvars + , tcdFDs = lfds + , tcdSigs = lsigs + , tcdATs = ats + , tcdATDefs = at_defs + } + ) + unicode = + declWithDoc classheader (if null body then Nothing else Just (vcat body)) + $$ instancesBit + where + classheader + | null lsigs = hdr unicode + | otherwise = hdr unicode <+> keyword "where" + + hdr = ppClassHdr False lctxt (unLoc lname) ltyvars lfds + + body = catMaybes [documentationToLaTeX doc, body_] + + body_ + | null lsigs, null ats, null at_defs = Nothing + | null ats, null at_defs = Just methodTable + | otherwise = Just (atTable $$ methodTable) + + atTable = + text "\\haddockpremethods{}" <> emph (text "Associated Types") + $$ vcat + [ ppFamDecl True (fst doc) [] (FamDecl noExtField decl) True | L _ decl <- ats , let name = unLoc . fdLName $ decl doc = lookupAnySubdoc name subdocs ] - - methodTable = - text "\\haddockpremethods{}" <> emph (text "Methods") $$ - vcat [ ppFunSig leader doc names typ unicode + methodTable = + text "\\haddockpremethods{}" <> emph (text "Methods") + $$ vcat + [ ppFunSig leader doc names typ unicode | L _ (ClassOpSig _ is_def lnames typ) <- lsigs - , let doc | is_def = noDocForDecl - | otherwise = lookupAnySubdoc (head names) subdocs + , let doc + | is_def = noDocForDecl + | otherwise = lookupAnySubdoc (head names) subdocs names = map (cleanName . unLoc) lnames leader = if is_def then Just (keyword "default") else Nothing ] - -- N.B. taking just the first name is ok. Signatures with multiple - -- names are expanded so that each name gets its own signature. - -- Get rid of the ugly '$dm' prefix on default method names - cleanName n - | isDefaultMethodOcc (occName n) - , '$':'d':'m':occStr <- getOccString n - = setName (tidyNameOcc (getName n) (mkOccName varName occStr)) n - | otherwise = n - - - instancesBit = ppDocInstances unicode instances - + -- N.B. taking just the first name is ok. Signatures with multiple + -- names are expanded so that each name gets its own signature. + -- Get rid of the ugly '$dm' prefix on default method names + cleanName n + | isDefaultMethodOcc (occName n) + , '$' : 'd' : 'm' : occStr <- getOccString n = + setName (tidyNameOcc (getName n) (mkOccName varName occStr)) n + | otherwise = n + + instancesBit = ppDocInstances unicode instances ppClassDecl _ _ _ _ _ = error "declaration type not supported by ppShortClassDecl" ppDocInstances :: Bool -> [DocInstance DocNameI] -> LaTeX ppDocInstances _unicode [] = empty ppDocInstances unicode (i : rest) - | Just ihead <- isUndocdInstance i - = declWithDoc (vcat (map (ppInstDecl unicode) (ihead:is))) Nothing $$ - ppDocInstances unicode rest' - | otherwise - = ppDocInstance unicode i $$ ppDocInstances unicode rest + | Just ihead <- isUndocdInstance i = + declWithDoc (vcat (map (ppInstDecl unicode) (ihead : is))) Nothing + $$ ppDocInstances unicode rest' + | otherwise = + ppDocInstance unicode i $$ ppDocInstances unicode rest where (is, rest') = spanWith isUndocdInstance rest isUndocdInstance :: DocInstance a -> Maybe (InstHead a) -isUndocdInstance (i,Nothing,_,_) = Just i -isUndocdInstance (i,Just (MetaDoc _ DocEmpty),_,_) = Just i +isUndocdInstance (i, Nothing, _, _) = Just i +isUndocdInstance (i, Just (MetaDoc _ DocEmpty), _, _) = Just i isUndocdInstance _ = Nothing -- | Print a possibly commented instance. The instance header is printed inside @@ -715,83 +804,100 @@ ppDocInstance :: Bool -> DocInstance DocNameI -> LaTeX ppDocInstance unicode (instHead, doc, _, _) = declWithDoc (ppInstDecl unicode instHead) (fmap docToLaTeX $ fmap _doc doc) - ppInstDecl :: Bool -> InstHead DocNameI -> LaTeX -ppInstDecl unicode (InstHead {..}) = case ihdInstType of +ppInstDecl unicode (InstHead{..}) = case ihdInstType of ClassInst ctx _ _ _ -> keyword "instance" <+> ppContextNoLocs ctx unicode <+> typ TypeInst rhs -> keyword "type" <+> keyword "instance" <+> typ <+> tibody rhs DataInst dd -> let cons = dd_cons (tcdDataDefn dd) - pref = case cons of { NewTypeCon _ -> keyword "newtype"; DataTypeCons _ _ -> keyword "data" } - in pref <+> keyword "instance" <+> typ + pref = case cons of NewTypeCon _ -> keyword "newtype"; DataTypeCons _ _ -> keyword "data" + in pref <+> keyword "instance" <+> typ where typ = ppAppNameTypes ihdClsName ihdTypes unicode tibody = maybe empty (\t -> equals <+> ppType unicode t) -lookupAnySubdoc :: (Eq name1) => - name1 -> [(name1, DocForDecl name2)] -> DocForDecl name2 +lookupAnySubdoc + :: Eq name1 + => name1 + -> [(name1, DocForDecl name2)] + -> DocForDecl name2 lookupAnySubdoc n subdocs = case lookup n subdocs of Nothing -> noDocForDecl Just docs -> docs - ------------------------------------------------------------------------------- + -- * Data & newtype declarations + ------------------------------------------------------------------------------- -- | Pretty-print a data declaration -ppDataDecl :: [(HsDecl DocNameI, DocForDecl DocName)] -- ^ relevant patterns - -> [DocInstance DocNameI] -- ^ relevant instances - -> [(DocName, DocForDecl DocName)] -- ^ relevant decl docs - -> Maybe (Documentation DocName) -- ^ this decl's docs - -> TyClDecl DocNameI -- ^ data decl to print - -> Bool -- ^ unicode - -> LaTeX +ppDataDecl + :: [(HsDecl DocNameI, DocForDecl DocName)] + -- ^ relevant patterns + -> [DocInstance DocNameI] + -- ^ relevant instances + -> [(DocName, DocForDecl DocName)] + -- ^ relevant decl docs + -> Maybe (Documentation DocName) + -- ^ this decl's docs + -> TyClDecl DocNameI + -- ^ data decl to print + -> Bool + -- ^ unicode + -> LaTeX ppDataDecl pats instances subdocs doc dataDecl unicode = - declWithDoc (ppDataHeader dataDecl unicode <+> whereBit) - (if null body then Nothing else Just (vcat body)) - $$ instancesBit - + declWithDoc + (ppDataHeader dataDecl unicode <+> whereBit) + (if null body then Nothing else Just (vcat body)) + $$ instancesBit where - cons = dd_cons (tcdDataDefn dataDecl) + cons = dd_cons (tcdDataDefn dataDecl) - body = catMaybes [doc >>= documentationToLaTeX, constrBit,patternBit] + body = catMaybes [doc >>= documentationToLaTeX, constrBit, patternBit] (whereBit, leaders) | null cons - , null pats = (empty,[]) + , null pats = + (empty, []) | null cons = (text "where", repeat empty) | otherwise = case toList cons of - L _ ConDeclGADT{} : _ -> (text "where", repeat empty) - _ -> (empty, (decltt (text "=") : repeat (decltt (text "|")))) + L _ ConDeclGADT{} : _ -> (text "where", repeat empty) + _ -> (empty, (decltt (text "=") : repeat (decltt (text "|")))) constrBit | null cons = Nothing - | otherwise = Just $ - text "\\enspace" <+> emph (text "Constructors") <> text "\\par" $$ - text "\\haddockbeginconstrs" $$ - vcat (zipWith (ppSideBySideConstr subdocs unicode) leaders (toList cons)) $$ - text "\\end{tabulary}\\par" + | otherwise = + Just $ + text "\\enspace" <+> emph (text "Constructors") <> text "\\par" + $$ text "\\haddockbeginconstrs" + $$ vcat (zipWith (ppSideBySideConstr subdocs unicode) leaders (toList cons)) + $$ text "\\end{tabulary}\\par" patternBit | null pats = Nothing - | otherwise = Just $ - text "\\enspace" <+> emph (text "Bundled Patterns") <> text "\\par" $$ - text "\\haddockbeginconstrs" $$ - vcat [ empty <-> ppSideBySidePat lnames typ d unicode - | (SigD _ (PatSynSig _ lnames typ), d) <- pats - ] $$ - text "\\end{tabulary}\\par" + | otherwise = + Just $ + text "\\enspace" <+> emph (text "Bundled Patterns") <> text "\\par" + $$ text "\\haddockbeginconstrs" + $$ vcat + [ empty <-> ppSideBySidePat lnames typ d unicode + | (SigD _ (PatSynSig _ lnames typ), d) <- pats + ] + $$ text "\\end{tabulary}\\par" instancesBit = ppDocInstances unicode instances - -- ppConstrHdr is for (non-GADT) existentials constructors' syntax ppConstrHdr - :: Bool -- ^ print explicit foralls - -> [LHsTyVarBndr Specificity DocNameI] -- ^ type variables - -> HsContext DocNameI -- ^ context - -> Bool -- ^ unicode + :: Bool + -- ^ print explicit foralls + -> [LHsTyVarBndr Specificity DocNameI] + -- ^ type variables + -> HsContext DocNameI + -- ^ context + -> Bool + -- ^ unicode -> LaTeX ppConstrHdr forall_ tvs ctxt unicode = ppForall <> ppCtxt where @@ -803,24 +909,28 @@ ppConstrHdr forall_ tvs ctxt unicode = ppForall <> ppCtxt | null ctxt = empty | otherwise = ppContextNoArrow ctxt unicode <+> darrow unicode <> space - -- | Pretty-print a constructor -ppSideBySideConstr :: [(DocName, DocForDecl DocName)] -- ^ all decl docs - -> Bool -- ^ unicode - -> LaTeX -- ^ prefix to decl - -> LConDecl DocNameI -- ^ constructor decl - -> LaTeX +ppSideBySideConstr + :: [(DocName, DocForDecl DocName)] + -- ^ all decl docs + -> Bool + -- ^ unicode + -> LaTeX + -- ^ prefix to decl + -> LConDecl DocNameI + -- ^ constructor decl + -> LaTeX ppSideBySideConstr subdocs unicode leader (L _ con) = leader <-> decltt decl <-> rDoc mbDoc <+> nl - $$ fieldPart + $$ fieldPart where -- Find the name of a constructors in the decl (`getConName` always returns -- a non-empty list) L _ aConName :| _ = getConNamesI con - occ = toList $ nameOccName . getName . unLoc <$> getConNamesI con + occ = toList $ nameOccName . getName . unLoc <$> getConNamesI con - ppOcc = cat (punctuate comma (map ppBinder occ)) + ppOcc = cat (punctuate comma (map ppBinder occ)) ppOccInfix = cat (punctuate comma (map ppBinderInfix occ)) -- Extract out the map of of docs corresponding to the constructors arguments @@ -829,190 +939,215 @@ ppSideBySideConstr subdocs unicode leader (L _ con) = -- First line of the constructor (no doc, no fields, single-line) decl = case con of - ConDeclH98{ con_args = det - , con_ex_tvs = tyVars - , con_forall = forall_ - , con_mb_cxt = cxt - } -> let context = fromMaybeContext cxt - header_ = ppConstrHdr forall_ tyVars context unicode - in case det of - -- Prefix constructor, e.g. 'Just a' - PrefixCon _ args - | hasArgDocs -> header_ <+> ppOcc - | otherwise -> hsep [ header_ - , ppOcc - , hsep (map (ppLParendType unicode . hsScaledThing) args) - ] - - -- Record constructor, e.g. 'Identity { runIdentity :: a }' - RecCon _ -> header_ <+> ppOcc - - -- Infix constructor, e.g. 'a :| [a]' - InfixCon arg1 arg2 - | hasArgDocs -> header_ <+> ppOcc - | otherwise -> hsep [ header_ - , ppLParendType unicode (hsScaledThing arg1) - , ppOccInfix - , ppLParendType unicode (hsScaledThing arg2) - ] - + ConDeclH98 + { con_args = det + , con_ex_tvs = tyVars + , con_forall = forall_ + , con_mb_cxt = cxt + } -> + let context = fromMaybeContext cxt + header_ = ppConstrHdr forall_ tyVars context unicode + in case det of + -- Prefix constructor, e.g. 'Just a' + PrefixCon _ args + | hasArgDocs -> header_ <+> ppOcc + | otherwise -> + hsep + [ header_ + , ppOcc + , hsep (map (ppLParendType unicode . hsScaledThing) args) + ] + -- Record constructor, e.g. 'Identity { runIdentity :: a }' + RecCon _ -> header_ <+> ppOcc + -- Infix constructor, e.g. 'a :| [a]' + InfixCon arg1 arg2 + | hasArgDocs -> header_ <+> ppOcc + | otherwise -> + hsep + [ header_ + , ppLParendType unicode (hsScaledThing arg1) + , ppOccInfix + , ppLParendType unicode (hsScaledThing arg2) + ] ConDeclGADT{} | hasArgDocs || not (isEmpty fieldPart) -> ppOcc - | otherwise -> hsep [ ppOcc - , dcolon unicode - -- ++AZ++ make this prepend "{..}" when it is a record style GADT - , ppLSigType unicode (getGADTConType con) - ] + | otherwise -> + hsep + [ ppOcc + , dcolon unicode + , -- ++AZ++ make this prepend "{..}" when it is a record style GADT + ppLSigType unicode (getGADTConType con) + ] fieldPart = case con of - ConDeclGADT{con_g_args = con_args'} -> case con_args' of - -- GADT record declarations - RecConGADT _ _ -> doConstrArgsWithDocs [] - -- GADT prefix data constructors - PrefixConGADT _ args | hasArgDocs -> doConstrArgsWithDocs (map hsScaledThing args) - _ -> empty - - ConDeclH98{con_args = con_args'} -> case con_args' of - -- H98 record declarations - RecCon (L _ fields) -> doRecordFields fields - -- H98 prefix data constructors - PrefixCon _ args | hasArgDocs -> doConstrArgsWithDocs (map hsScaledThing args) - -- H98 infix data constructor - InfixCon arg1 arg2 | hasArgDocs -> doConstrArgsWithDocs (map hsScaledThing [arg1,arg2]) - _ -> empty + ConDeclGADT{con_g_args = con_args'} -> case con_args' of + -- GADT record declarations + RecConGADT _ _ -> doConstrArgsWithDocs [] + -- GADT prefix data constructors + PrefixConGADT _ args | hasArgDocs -> doConstrArgsWithDocs (map hsScaledThing args) + _ -> empty + ConDeclH98{con_args = con_args'} -> case con_args' of + -- H98 record declarations + RecCon (L _ fields) -> doRecordFields fields + -- H98 prefix data constructors + PrefixCon _ args | hasArgDocs -> doConstrArgsWithDocs (map hsScaledThing args) + -- H98 infix data constructor + InfixCon arg1 arg2 | hasArgDocs -> doConstrArgsWithDocs (map hsScaledThing [arg1, arg2]) + _ -> empty doRecordFields fields = - vcat [ empty <-> tt (text begin) <+> ppSideBySideField subdocs unicode field <+> nl - | (begin, L _ field) <- zip ("\\qquad \\{" : repeat "\\qquad ,") fields - ] - $$ - empty <-> tt (text "\\qquad \\}") <+> nl + vcat + [ empty <-> tt (text begin) <+> ppSideBySideField subdocs unicode field <+> nl + | (begin, L _ field) <- zip ("\\qquad \\{" : repeat "\\qquad ,") fields + ] + $$ empty <-> tt (text "\\qquad \\}") <+> nl doConstrArgsWithDocs args = vcat $ map (\l -> empty <-> text "\\qquad" <+> l) $ case con of ConDeclH98{} -> [ decltt (ppLParendType unicode arg) <-> rDoc (fmap _doc mdoc) <+> nl - | (i, arg) <- zip [0..] args + | (i, arg) <- zip [0 ..] args , let mdoc = Map.lookup i argDocs ] ConDeclGADT{} -> [ l <+> text "\\enspace" <+> r - | (l,r) <- ppSubSigLike unicode (unLoc (getGADTConType con)) argDocs subdocs (dcolon unicode) + | (l, r) <- ppSubSigLike unicode (unLoc (getGADTConType con)) argDocs subdocs (dcolon unicode) ] - -- don't use "con_doc con", in case it's reconstructed from a .hi file, -- or also because we want Haddock to do the doc-parsing, not GHC. mbDoc = case getConNamesI con of - cn:|_ -> lookup (unLoc cn) subdocs >>= - fmap _doc . combineDocumentation . fst - + cn :| _ -> + lookup (unLoc cn) subdocs + >>= fmap _doc . combineDocumentation . fst -- | Pretty-print a record field -ppSideBySideField :: [(DocName, DocForDecl DocName)] -> Bool -> ConDeclField DocNameI -> LaTeX +ppSideBySideField :: [(DocName, DocForDecl DocName)] -> Bool -> ConDeclField DocNameI -> LaTeX ppSideBySideField subdocs unicode (ConDeclField _ names ltype _) = - decltt (cat (punctuate comma (map (ppBinder . rdrNameOcc . unLoc . foLabel . unLoc) names)) - <+> dcolon unicode <+> ppLType unicode ltype) <-> rDoc mbDoc + decltt + ( cat (punctuate comma (map (ppBinder . rdrNameOcc . unLoc . foLabel . unLoc) names)) + <+> dcolon unicode + <+> ppLType unicode ltype + ) + <-> rDoc mbDoc where -- don't use cd_fld_doc for same reason we don't use con_doc above -- Where there is more than one name, they all have the same documentation mbDoc = lookup (foExt $ unLoc $ head names) subdocs >>= fmap _doc . combineDocumentation . fst - -- | Pretty-print a bundled pattern synonym -ppSideBySidePat :: [LocatedN DocName] -- ^ pattern name(s) - -> LHsSigType DocNameI -- ^ type of pattern(s) - -> DocForDecl DocName -- ^ doc map - -> Bool -- ^ unicode - -> LaTeX +ppSideBySidePat + :: [LocatedN DocName] + -- ^ pattern name(s) + -> LHsSigType DocNameI + -- ^ type of pattern(s) + -> DocForDecl DocName + -- ^ doc map + -> Bool + -- ^ unicode + -> LaTeX ppSideBySidePat lnames typ (doc, argDocs) unicode = decltt decl <-> rDoc mDoc <+> nl - $$ fieldPart + $$ fieldPart where hasArgDocs = not $ Map.null argDocs ppOcc = hsep (punctuate comma (map (ppDocBinder . unLoc) lnames)) - decl | hasArgDocs = keyword "pattern" <+> ppOcc - | otherwise = hsep [ keyword "pattern" - , ppOcc - , dcolon unicode - , ppLSigType unicode typ - ] + decl + | hasArgDocs = keyword "pattern" <+> ppOcc + | otherwise = + hsep + [ keyword "pattern" + , ppOcc + , dcolon unicode + , ppLSigType unicode typ + ] fieldPart | not hasArgDocs = empty - | otherwise = vcat - [ empty <-> text "\\qquad" <+> l <+> text "\\enspace" <+> r - | (l,r) <- ppSubSigLike unicode (unLoc typ) argDocs [] (dcolon unicode) - ] + | otherwise = + vcat + [ empty <-> text "\\qquad" <+> l <+> text "\\enspace" <+> r + | (l, r) <- ppSubSigLike unicode (unLoc typ) argDocs [] (dcolon unicode) + ] mDoc = fmap _doc $ combineDocumentation doc - -- | Print the LHS of a data\/newtype declaration. -- Currently doesn't handle 'data instance' decls or kind signatures ppDataHeader :: TyClDecl DocNameI -> Bool -> LaTeX -ppDataHeader (DataDecl { tcdLName = L _ name, tcdTyVars = tyvars - , tcdDataDefn = HsDataDefn { dd_cons = cons, dd_ctxt = ctxt } }) unicode - = -- newtype or data - (case cons of - { NewTypeCon _ -> keyword "newtype" - ; DataTypeCons False _ -> keyword "data" - ; DataTypeCons True _ -> keyword "type" <+> keyword "data" - }) <+> - -- context - ppLContext ctxt unicode <+> - -- T a b c ..., or a :+: b - ppAppDocNameNames False name (tyvarNames tyvars) +ppDataHeader + ( DataDecl + { tcdLName = L _ name + , tcdTyVars = tyvars + , tcdDataDefn = HsDataDefn{dd_cons = cons, dd_ctxt = ctxt} + } + ) + unicode = + -- newtype or data + ( case cons of + NewTypeCon _ -> keyword "newtype" + DataTypeCons False _ -> keyword "data" + DataTypeCons True _ -> keyword "type" <+> keyword "data" + ) + <+> + -- context + ppLContext ctxt unicode + <+> + -- T a b c ..., or a :+: b + ppAppDocNameNames False name (tyvarNames tyvars) ppDataHeader _ _ = error "ppDataHeader: illegal argument" - -------------------------------------------------------------------------------- + -- * Type applications + -------------------------------------------------------------------------------- -ppAppDocNameTyVarBndrs :: RenderableBndrFlag flag => - Bool -> DocName -> [LHsTyVarBndr flag DocNameI] -> LaTeX +ppAppDocNameTyVarBndrs + :: RenderableBndrFlag flag + => Bool + -> DocName + -> [LHsTyVarBndr flag DocNameI] + -> LaTeX ppAppDocNameTyVarBndrs unicode n vs = - ppTypeApp n vs ppDN (ppHsTyVarBndr unicode . unLoc) + ppTypeApp n vs ppDN (ppHsTyVarBndr unicode . unLoc) where ppDN = ppBinder . nameOccName . getName - -- | Print an application of a DocName to its list of HsTypes ppAppNameTypes :: DocName -> [HsType DocNameI] -> Bool -> LaTeX ppAppNameTypes n ts unicode = ppTypeApp n ts ppDocName (ppParendType unicode) ppAppNameTypeArgs :: DocName -> [LHsTypeArg DocNameI] -> Bool -> LaTeX -ppAppNameTypeArgs n args@(HsValArg _ _:HsValArg _ _:_) unicode - = ppTypeApp n args ppDocName (ppLHsTypeArg unicode) -ppAppNameTypeArgs n args unicode - = ppDocName n <+> hsep (map (ppLHsTypeArg unicode) args) +ppAppNameTypeArgs n args@(HsValArg _ _ : HsValArg _ _ : _) unicode = + ppTypeApp n args ppDocName (ppLHsTypeArg unicode) +ppAppNameTypeArgs n args unicode = + ppDocName n <+> hsep (map (ppLHsTypeArg unicode) args) -- | Print an application of a DocName and a list of Names ppAppDocNameNames :: Bool -> DocName -> [Name] -> LaTeX ppAppDocNameNames _summ n ns = ppTypeApp n ns (ppBinder . nameOccName . getName) ppSymName - -- | General printing of type applications ppTypeApp :: DocName -> [a] -> (DocName -> LaTeX) -> (a -> LaTeX) -> LaTeX -ppTypeApp n (t1:t2:rest) ppDN ppT +ppTypeApp n (t1 : t2 : rest) ppDN ppT | operator, not . null $ rest = parens opApp <+> hsep (map ppT rest) - | operator = opApp + | operator = opApp where operator = isNameSym . getName $ n opApp = ppT t1 <+> ppDN n <+> ppT t2 - ppTypeApp n ts ppDN ppT = ppDN n <+> hsep (map ppT ts) ------------------------------------------------------------------------------- + -- * Contexts -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- ppLContext :: Maybe (LHsContext DocNameI) -> Bool -> LaTeX ppLContext Nothing _ = empty -ppLContext (Just ctxt) unicode = ppContext (unLoc ctxt) unicode +ppLContext (Just ctxt) unicode = ppContext (unLoc ctxt) unicode ppLContextNoArrow :: LHsContext DocNameI -> Bool -> LaTeX ppLContextNoArrow ctxt unicode = ppContextNoArrow (unLoc ctxt) unicode @@ -1022,64 +1157,62 @@ ppContextNoLocsMaybe [] _ = Nothing ppContextNoLocsMaybe cxt unicode = Just $ pp_hs_context cxt unicode ppContextNoArrow :: HsContext DocNameI -> Bool -> LaTeX -ppContextNoArrow cxt unicode = fromMaybe empty $ - ppContextNoLocsMaybe (map unLoc cxt) unicode - +ppContextNoArrow cxt unicode = + fromMaybe empty $ + ppContextNoLocsMaybe (map unLoc cxt) unicode ppContextNoLocs :: [HsType DocNameI] -> Bool -> LaTeX -ppContextNoLocs cxt unicode = maybe empty (<+> darrow unicode) $ - ppContextNoLocsMaybe cxt unicode - +ppContextNoLocs cxt unicode = + maybe empty (<+> darrow unicode) $ + ppContextNoLocsMaybe cxt unicode ppContext :: HsContext DocNameI -> Bool -> LaTeX ppContext cxt unicode = ppContextNoLocs (map unLoc cxt) unicode - pp_hs_context :: [HsType DocNameI] -> Bool -> LaTeX -pp_hs_context [] _ = empty +pp_hs_context [] _ = empty pp_hs_context [p] unicode = ppCtxType unicode p pp_hs_context cxt unicode = parenList (map (ppType unicode) cxt) - ------------------------------------------------------------------------------- + -- * Types and contexts -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- ppBang :: HsSrcBang -> LaTeX ppBang (HsSrcBang _ _ SrcStrict) = char '!' -ppBang (HsSrcBang _ _ SrcLazy) = char '~' -ppBang _ = empty - +ppBang (HsSrcBang _ _ SrcLazy) = char '~' +ppBang _ = empty tupleParens :: HsTupleSort -> [LaTeX] -> LaTeX tupleParens HsUnboxedTuple = ubxParenList -tupleParens _ = parenList - +tupleParens _ = parenList sumParens :: [LaTeX] -> LaTeX sumParens = ubxparens . hsep . punctuate (text " |") - ------------------------------------------------------------------------------- + -- * Rendering of HsType + -- -- Stolen from Html and tweaked for LaTeX generation ------------------------------------------------------------------------------- ppLType, ppLParendType, ppLFunLhType :: Bool -> LHsType DocNameI -> LaTeX -ppLType unicode y = ppType unicode (unLoc y) +ppLType unicode y = ppType unicode (unLoc y) ppLParendType unicode y = ppParendType unicode (unLoc y) -ppLFunLhType unicode y = ppFunLhType unicode (unLoc y) +ppLFunLhType unicode y = ppFunLhType unicode (unLoc y) ppLSigType :: Bool -> LHsSigType DocNameI -> LaTeX ppLSigType unicode y = ppSigType unicode (unLoc y) ppType, ppParendType, ppFunLhType, ppCtxType :: Bool -> HsType DocNameI -> LaTeX -ppType unicode ty = ppr_mono_ty (reparenTypePrec PREC_TOP ty) unicode +ppType unicode ty = ppr_mono_ty (reparenTypePrec PREC_TOP ty) unicode ppParendType unicode ty = ppr_mono_ty (reparenTypePrec PREC_TOP ty) unicode -ppFunLhType unicode ty = ppr_mono_ty (reparenTypePrec PREC_FUN ty) unicode -ppCtxType unicode ty = ppr_mono_ty (reparenTypePrec PREC_CTX ty) unicode +ppFunLhType unicode ty = ppr_mono_ty (reparenTypePrec PREC_FUN ty) unicode +ppCtxType unicode ty = ppr_mono_ty (reparenTypePrec PREC_CTX ty) unicode ppSigType :: Bool -> HsSigType DocNameI -> LaTeX ppSigType unicode sig_ty = ppr_sig_ty (reparenSigType sig_ty) unicode @@ -1110,7 +1243,7 @@ instance RenderableBndrFlag (HsBndrVis DocNameI) where ppHsBndrVis bvis $ ppDocName name ppHsTyVarBndr unicode (KindedTyVar _ bvis (L _ name) kind) = ppHsBndrVis bvis $ - parens (ppDocName name <+> dcolon unicode <+> ppLKind unicode kind) + parens (ppDocName name <+> dcolon unicode <+> ppLKind unicode kind) ppHsBndrVis :: HsBndrVis DocNameI -> LaTeX -> LaTeX ppHsBndrVis (HsBndrRequired _) d = d @@ -1126,192 +1259,191 @@ ppKind unicode ki = ppr_mono_ty (reparenTypePrec PREC_TOP ki) unicode -- since they are implicit in Haskell ppr_sig_ty :: HsSigType DocNameI -> Bool -> LaTeX -ppr_sig_ty (HsSig { sig_bndrs = outer_bndrs, sig_body = ltype }) unicode - = sep [ ppHsOuterTyVarBndrs outer_bndrs unicode - , ppr_mono_lty ltype unicode ] +ppr_sig_ty (HsSig{sig_bndrs = outer_bndrs, sig_body = ltype}) unicode = + sep + [ ppHsOuterTyVarBndrs outer_bndrs unicode + , ppr_mono_lty ltype unicode + ] ppr_mono_lty :: LHsType DocNameI -> Bool -> LaTeX ppr_mono_lty ty unicode = ppr_mono_ty (unLoc ty) unicode - ppr_mono_ty :: HsType DocNameI -> Bool -> LaTeX -ppr_mono_ty (HsForAllTy _ tele ty) unicode - = sep [ ppHsForAllTelescope tele unicode - , ppr_mono_lty ty unicode ] -ppr_mono_ty (HsQualTy _ ctxt ty) unicode - = sep [ ppLContext (Just ctxt) unicode - , ppr_mono_lty ty unicode ] -ppr_mono_ty (HsFunTy _ mult ty1 ty2) u - = sep [ ppr_mono_lty ty1 u - , arr <+> ppr_mono_lty ty2 u ] - where arr = case mult of - HsLinearArrow _ -> lollipop u - HsUnrestrictedArrow _ -> arrow u - HsExplicitMult _ m -> multAnnotation <> ppr_mono_lty m u <+> arrow u - -ppr_mono_ty (HsBangTy _ b ty) u = ppBang b <> ppLParendType u ty +ppr_mono_ty (HsForAllTy _ tele ty) unicode = + sep + [ ppHsForAllTelescope tele unicode + , ppr_mono_lty ty unicode + ] +ppr_mono_ty (HsQualTy _ ctxt ty) unicode = + sep + [ ppLContext (Just ctxt) unicode + , ppr_mono_lty ty unicode + ] +ppr_mono_ty (HsFunTy _ mult ty1 ty2) u = + sep + [ ppr_mono_lty ty1 u + , arr <+> ppr_mono_lty ty2 u + ] + where + arr = case mult of + HsLinearArrow _ -> lollipop u + HsUnrestrictedArrow _ -> arrow u + HsExplicitMult _ m -> multAnnotation <> ppr_mono_lty m u <+> arrow u +ppr_mono_ty (HsBangTy _ b ty) u = ppBang b <> ppLParendType u ty ppr_mono_ty (HsTyVar _ NotPromoted (L _ name)) _ = ppDocName name -ppr_mono_ty (HsTyVar _ IsPromoted (L _ name)) _ = char '\'' <> ppDocName name +ppr_mono_ty (HsTyVar _ IsPromoted (L _ name)) _ = char '\'' <> ppDocName name ppr_mono_ty (HsTupleTy _ con tys) u = tupleParens con (map (ppLType u) tys) -ppr_mono_ty (HsSumTy _ tys) u = sumParens (map (ppLType u) tys) +ppr_mono_ty (HsSumTy _ tys) u = sumParens (map (ppLType u) tys) ppr_mono_ty (HsKindSig _ ty kind) u = parens (ppr_mono_lty ty u <+> dcolon u <+> ppLKind u kind) -ppr_mono_ty (HsListTy _ ty) u = brackets (ppr_mono_lty ty u) +ppr_mono_ty (HsListTy _ ty) u = brackets (ppr_mono_lty ty u) ppr_mono_ty (HsIParamTy _ (L _ n) ty) u = ppIPName n <+> dcolon u <+> ppr_mono_lty ty u -ppr_mono_ty (HsSpliceTy v _) _ = dataConCantHappen v -ppr_mono_ty (HsRecTy {}) _ = text "{..}" -ppr_mono_ty (XHsType {}) _ = error "ppr_mono_ty HsCoreTy" +ppr_mono_ty (HsSpliceTy v _) _ = dataConCantHappen v +ppr_mono_ty (HsRecTy{}) _ = text "{..}" +ppr_mono_ty (XHsType{}) _ = error "ppr_mono_ty HsCoreTy" ppr_mono_ty (HsExplicitListTy _ IsPromoted tys) u = Pretty.quote $ brackets $ hsep $ punctuate comma $ map (ppLType u) tys ppr_mono_ty (HsExplicitListTy _ NotPromoted tys) u = brackets $ hsep $ punctuate comma $ map (ppLType u) tys ppr_mono_ty (HsExplicitTupleTy _ tys) u = Pretty.quote $ parenList $ map (ppLType u) tys - -ppr_mono_ty (HsAppTy _ fun_ty arg_ty) unicode - = hsep [ppr_mono_lty fun_ty unicode, ppr_mono_lty arg_ty unicode] - -ppr_mono_ty (HsAppKindTy _ fun_ty arg_ki) unicode - = hsep [ppr_mono_lty fun_ty unicode, atSign <> ppr_mono_lty arg_ki unicode] - -ppr_mono_ty (HsOpTy _ prom ty1 op ty2) unicode - = ppr_mono_lty ty1 unicode <+> ppr_op_prom <+> ppr_mono_lty ty2 unicode +ppr_mono_ty (HsAppTy _ fun_ty arg_ty) unicode = + hsep [ppr_mono_lty fun_ty unicode, ppr_mono_lty arg_ty unicode] +ppr_mono_ty (HsAppKindTy _ fun_ty arg_ki) unicode = + hsep [ppr_mono_lty fun_ty unicode, atSign <> ppr_mono_lty arg_ki unicode] +ppr_mono_ty (HsOpTy _ prom ty1 op ty2) unicode = + ppr_mono_lty ty1 unicode <+> ppr_op_prom <+> ppr_mono_lty ty2 unicode where - ppr_op_prom | isPromoted prom - = char '\'' <> ppr_op - | otherwise - = ppr_op - ppr_op | isSymOcc (getOccName op) = ppLDocName op - | otherwise = char '`' <> ppLDocName op <> char '`' - -ppr_mono_ty (HsParTy _ ty) unicode - = parens (ppr_mono_lty ty unicode) + ppr_op_prom + | isPromoted prom = + char '\'' <> ppr_op + | otherwise = + ppr_op + ppr_op + | isSymOcc (getOccName op) = ppLDocName op + | otherwise = char '`' <> ppLDocName op <> char '`' +ppr_mono_ty (HsParTy _ ty) unicode = + parens (ppr_mono_lty ty unicode) -- = ppr_mono_lty ty unicode -ppr_mono_ty (HsDocTy _ ty _) unicode - = ppr_mono_lty ty unicode - +ppr_mono_ty (HsDocTy _ ty _) unicode = + ppr_mono_lty ty unicode ppr_mono_ty (HsWildCardTy _) _ = char '_' - ppr_mono_ty (HsTyLit _ t) u = ppr_tylit t u ppr_mono_ty (HsStarTy _ isUni) unicode = starSymbol (isUni || unicode) - ppr_tylit :: HsTyLit DocNameI -> Bool -> LaTeX ppr_tylit (HsNumTy _ n) _ = integer n ppr_tylit (HsStrTy _ s) _ = text (show s) ppr_tylit (HsCharTy _ c) _ = text (show c) - -- XXX: Ok in verbatim, but not otherwise - -- XXX: Do something with Unicode parameter? +-- XXX: Ok in verbatim, but not otherwise +-- XXX: Do something with Unicode parameter? ------------------------------------------------------------------------------- + -- * Names -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- ppBinder :: OccName -> LaTeX ppBinder n | isSymOcc n = parens $ ppOccName n - | otherwise = ppOccName n + | otherwise = ppOccName n ppBinderInfix :: OccName -> LaTeX ppBinderInfix n | isSymOcc n = ppOccName n - | otherwise = cat [ char '`', ppOccName n, char '`' ] + | otherwise = cat [char '`', ppOccName n, char '`'] ppSymName :: Name -> LaTeX ppSymName name | isNameSym name = parens $ ppName name | otherwise = ppName name - ppIPName :: HsIPName -> LaTeX -ppIPName = text . ('?':) . unpackFS . hsIPNameFS +ppIPName = text . ('?' :) . unpackFS . hsIPNameFS ppOccName :: OccName -> LaTeX ppOccName = text . occNameString - ppDocName :: DocName -> LaTeX ppDocName = ppOccName . nameOccName . getName ppLDocName :: GenLocated l DocName -> LaTeX ppLDocName (L _ d) = ppDocName d - ppDocBinder :: DocName -> LaTeX ppDocBinder = ppBinder . nameOccName . getName - ppName :: Name -> LaTeX ppName = ppOccName . nameOccName - latexFilter :: String -> String latexFilter = foldr latexMunge "" - latexMonoFilter :: String -> String latexMonoFilter = foldr latexMonoMunge "" - latexMunge :: Char -> String -> String -latexMunge '#' s = "{\\char '43}" ++ s -latexMunge '$' s = "{\\char '44}" ++ s -latexMunge '%' s = "{\\char '45}" ++ s -latexMunge '&' s = "{\\char '46}" ++ s -latexMunge '~' s = "{\\char '176}" ++ s -latexMunge '_' s = "{\\char '137}" ++ s -latexMunge '^' s = "{\\char '136}" ++ s +latexMunge '#' s = "{\\char '43}" ++ s +latexMunge '$' s = "{\\char '44}" ++ s +latexMunge '%' s = "{\\char '45}" ++ s +latexMunge '&' s = "{\\char '46}" ++ s +latexMunge '~' s = "{\\char '176}" ++ s +latexMunge '_' s = "{\\char '137}" ++ s +latexMunge '^' s = "{\\char '136}" ++ s latexMunge '\\' s = "{\\char '134}" ++ s -latexMunge '{' s = "{\\char '173}" ++ s -latexMunge '}' s = "{\\char '175}" ++ s -latexMunge '[' s = "{\\char 91}" ++ s -latexMunge ']' s = "{\\char 93}" ++ s -latexMunge c s = c : s - +latexMunge '{' s = "{\\char '173}" ++ s +latexMunge '}' s = "{\\char '175}" ++ s +latexMunge '[' s = "{\\char 91}" ++ s +latexMunge ']' s = "{\\char 93}" ++ s +latexMunge c s = c : s latexMonoMunge :: Char -> String -> String -latexMonoMunge ' ' (' ':s) = "\\ \\ " ++ s -latexMonoMunge ' ' ('\\':' ':s) = "\\ \\ " ++ s +latexMonoMunge ' ' (' ' : s) = "\\ \\ " ++ s +latexMonoMunge ' ' ('\\' : ' ' : s) = "\\ \\ " ++ s latexMonoMunge '\n' s = '\\' : '\\' : s latexMonoMunge c s = latexMunge c s - ------------------------------------------------------------------------------- + -- * Doc Markup -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- latexMarkup :: HasOccName a => DocMarkup (Wrap a) (StringContext -> LaTeX -> LaTeX) -latexMarkup = Markup - { markupParagraph = \p v -> blockElem (p v (text "\\par")) - , markupEmpty = \_ -> id - , markupString = \s v -> inlineElem (text (fixString v s)) - , markupAppend = \l r v -> l v . r v - , markupIdentifier = \i v -> inlineElem (markupId v (fmap occName i)) - , markupIdentifierUnchecked = \i v -> inlineElem (markupId v (fmap snd i)) - , markupModule = - \(ModLink m mLabel) v -> - case mLabel of - Just lbl -> inlineElem . tt $ lbl v empty - Nothing -> inlineElem (let (mdl,_ref) = break (=='#') m - in (tt (text mdl))) - , markupWarning = \p v -> p v - , markupEmphasis = \p v -> inlineElem (emph (p v empty)) - , markupBold = \p v -> inlineElem (bold (p v empty)) - , markupMonospaced = \p v -> inlineElem (markupMonospace p v) - , markupUnorderedList = \p v -> blockElem (itemizedList (map (\p' -> p' v empty) p)) - , markupPic = \p _ -> inlineElem (markupPic p) - , markupMathInline = \p _ -> inlineElem (markupMathInline p) - , markupMathDisplay = \p _ -> blockElem (markupMathDisplay p) - , markupOrderedList = \p v -> blockElem (enumeratedList (map (\(_, p') -> p' v empty) p)) - , markupDefList = \l v -> blockElem (descriptionList (map (\(a,b) -> (a v empty, b v empty)) l)) - , markupCodeBlock = \p _ -> blockElem (quote (verb (p Verb empty))) - , markupHyperlink = \(Hyperlink u l) v -> inlineElem (markupLink u (fmap (\x -> x v empty) l)) - , markupAName = \_ _ -> id -- TODO - , markupProperty = \p _ -> blockElem (quote (verb (text p))) - , markupExample = \e _ -> blockElem (quote (verb (text $ unlines $ map exampleToString e))) - , markupHeader = \(Header l h) p -> blockElem (header l (h p empty)) - , markupTable = \(Table h b) p -> blockElem (table h b p) - } +latexMarkup = + Markup + { markupParagraph = \p v -> blockElem (p v (text "\\par")) + , markupEmpty = \_ -> id + , markupString = \s v -> inlineElem (text (fixString v s)) + , markupAppend = \l r v -> l v . r v + , markupIdentifier = \i v -> inlineElem (markupId v (fmap occName i)) + , markupIdentifierUnchecked = \i v -> inlineElem (markupId v (fmap snd i)) + , markupModule = + \(ModLink m mLabel) v -> + case mLabel of + Just lbl -> inlineElem . tt $ lbl v empty + Nothing -> + inlineElem + ( let (mdl, _ref) = break (== '#') m + in (tt (text mdl)) + ) + , markupWarning = \p v -> p v + , markupEmphasis = \p v -> inlineElem (emph (p v empty)) + , markupBold = \p v -> inlineElem (bold (p v empty)) + , markupMonospaced = \p v -> inlineElem (markupMonospace p v) + , markupUnorderedList = \p v -> blockElem (itemizedList (map (\p' -> p' v empty) p)) + , markupPic = \p _ -> inlineElem (markupPic p) + , markupMathInline = \p _ -> inlineElem (markupMathInline p) + , markupMathDisplay = \p _ -> blockElem (markupMathDisplay p) + , markupOrderedList = \p v -> blockElem (enumeratedList (map (\(_, p') -> p' v empty) p)) + , markupDefList = \l v -> blockElem (descriptionList (map (\(a, b) -> (a v empty, b v empty)) l)) + , markupCodeBlock = \p _ -> blockElem (quote (verb (p Verb empty))) + , markupHyperlink = \(Hyperlink u l) v -> inlineElem (markupLink u (fmap (\x -> x v empty) l)) + , markupAName = \_ _ -> id -- TODO + , markupProperty = \p _ -> blockElem (quote (verb (text p))) + , markupExample = \e _ -> blockElem (quote (verb (text $ unlines $ map exampleToString e))) + , markupHeader = \(Header l h) p -> blockElem (header l (h p empty)) + , markupTable = \(Table h b) p -> blockElem (table h b p) + } where blockElem :: LaTeX -> LaTeX -> LaTeX blockElem = ($$) @@ -1328,15 +1460,15 @@ latexMarkup = Markup table _ _ _ = text "{TODO: Table}" fixString Plain s = latexFilter s - fixString Verb s = s - fixString Mono s = latexMonoFilter s + fixString Verb s = s + fixString Mono s = latexMonoFilter s markupMonospace p Verb = p Verb empty markupMonospace p _ = tt (p Mono empty) markupLink url mLabel = case mLabel of Just label -> text "\\href" <> braces (text url) <> braces label - Nothing -> text "\\url" <> braces (text url) + Nothing -> text "\\url" <> braces (text url) -- Is there a better way of doing this? Just a space is an arbitrary choice. markupPic (Picture uri title) = parens (imageText title) @@ -1352,10 +1484,11 @@ latexMarkup = Markup markupId v wrappedOcc = case v of - Verb -> text i - Mono -> text "\\haddockid" <> braces (text . latexMonoFilter $ i) + Verb -> text i + Mono -> text "\\haddockid" <> braces (text . latexMonoFilter $ i) Plain -> text "\\haddockid" <> braces (text . latexFilter $ i) - where i = showWrapped occNameString wrappedOcc + where + i = showWrapped occNameString wrappedOcc docToLaTeX :: Doc DocName -> LaTeX docToLaTeX doc = markup latexMarkup doc Plain empty @@ -1363,65 +1496,63 @@ docToLaTeX doc = markup latexMarkup doc Plain empty documentationToLaTeX :: Documentation DocName -> Maybe LaTeX documentationToLaTeX = fmap docToLaTeX . fmap _doc . combineDocumentation - rdrDocToLaTeX :: Doc RdrName -> LaTeX rdrDocToLaTeX doc = markup latexMarkup doc Plain empty - data StringContext - = Plain -- ^ all special characters have to be escape - | Mono -- ^ on top of special characters, escape space characters - | Verb -- ^ don't escape anything - + = -- | all special characters have to be escape + Plain + | -- | on top of special characters, escape space characters + Mono + | -- | don't escape anything + Verb latexStripTrailingWhitespace :: Doc a -> Doc a latexStripTrailingWhitespace (DocString s) - | null s' = DocEmpty + | null s' = DocEmpty | otherwise = DocString s - where s' = reverse (dropWhile isSpace (reverse s)) + where + s' = reverse (dropWhile isSpace (reverse s)) latexStripTrailingWhitespace (DocAppend l r) | DocEmpty <- r' = latexStripTrailingWhitespace l - | otherwise = DocAppend l r' + | otherwise = DocAppend l r' where r' = latexStripTrailingWhitespace r latexStripTrailingWhitespace (DocParagraph p) = latexStripTrailingWhitespace p latexStripTrailingWhitespace other = other - ------------------------------------------------------------------------------- + -- * LaTeX utils -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- itemizedList :: [LaTeX] -> LaTeX itemizedList items = - text "\\vbox{\\begin{itemize}" $$ - vcat (map (text "\\item" $$) items) $$ - text "\\end{itemize}}" - + text "\\vbox{\\begin{itemize}" + $$ vcat (map (text "\\item" $$) items) + $$ text "\\end{itemize}}" enumeratedList :: [LaTeX] -> LaTeX enumeratedList items = - text "\\vbox{\\begin{enumerate}" $$ - vcat (map (text "\\item " $$) items) $$ - text "\\end{enumerate}}" - + text "\\vbox{\\begin{enumerate}" + $$ vcat (map (text "\\item " $$) items) + $$ text "\\end{enumerate}}" -descriptionList :: [(LaTeX,LaTeX)] -> LaTeX +descriptionList :: [(LaTeX, LaTeX)] -> LaTeX descriptionList items = - text "\\vbox{\\begin{description}" $$ - vcat (map (\(a,b) -> text "\\item" <> brackets a <> text "\\hfill \\par" $$ b) items) $$ - text "\\end{description}}" - + text "\\vbox{\\begin{description}" + $$ vcat (map (\(a, b) -> text "\\item" <> brackets a <> text "\\hfill \\par" $$ b) items) + $$ text "\\end{description}}" tt :: LaTeX -> LaTeX tt ltx = text "\\haddocktt" <> braces ltx - decltt :: LaTeX -> LaTeX decltt ltx = text "\\haddockdecltt" <> braces (text filtered) - where filtered = latexMonoFilter (latex2String ltx) + where + filtered = latexMonoFilter (latex2String ltx) emph :: LaTeX -> LaTeX emph ltx = text "\\emph" <> braces ltx @@ -1437,18 +1568,17 @@ bold ltx = text "\\textbf" <> braces ltx -- inside a @tabulary@ environment) verb :: LaTeX -> LaTeX verb doc = text "{\\haddockverb\\begin{verbatim}" $$ doc <> text "\\end{verbatim}}" - -- NB. swallow a trailing \n in the verbatim text by appending the - -- \end{verbatim} directly, otherwise we get spurious blank lines at the - -- end of code blocks. +-- NB. swallow a trailing \n in the verbatim text by appending the +-- \end{verbatim} directly, otherwise we get spurious blank lines at the +-- end of code blocks. quote :: LaTeX -> LaTeX quote doc = text "\\begin{quote}" $$ doc $$ text "\\end{quote}" - dcolon, arrow, lollipop, darrow, forallSymbol, starSymbol :: Bool -> LaTeX dcolon unicode = text (if unicode then "∷" else "::") -arrow unicode = text (if unicode then "→" else "->") +arrow unicode = text (if unicode then "→" else "->") lollipop unicode = text (if unicode then "⊸" else "%1 ->") darrow unicode = text (if unicode then "⇒" else "=>") forallSymbol unicode = text (if unicode then "∀" else "forall") @@ -1466,23 +1596,18 @@ dot = char '.' parenList :: [LaTeX] -> LaTeX parenList = parens . hsep . punctuate comma - ubxParenList :: [LaTeX] -> LaTeX ubxParenList = ubxparens . hsep . punctuate comma - ubxparens :: LaTeX -> LaTeX ubxparens h = text "(#" <+> h <+> text "#)" - nl :: LaTeX nl = text "\\\\" - keyword :: String -> LaTeX keyword = text - -infixr 4 <-> -- combining table cells +infixr 4 <-> -- combining table cells (<->) :: LaTeX -> LaTeX -> LaTeX a <-> b = a <+> char '&' <+> b diff --git a/haddock-api/src/Haddock/Backends/Xhtml.hs b/haddock-api/src/Haddock/Backends/Xhtml.hs index 9619caff97..1814e7d28e 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml.hs @@ -1,4 +1,12 @@ +{-# LANGUAGE BangPatterns #-} ----------------------------------------------------------------------------- +----------------------------------------------------------------------------- +{-# LANGUAGE CPP #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} + -- | -- Module : Haddock.Backends.Html -- Copyright : (c) Simon Marlow 2003-2006, @@ -10,20 +18,13 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------ -{-# LANGUAGE CPP #-} -{-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE TupleSections #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE BangPatterns #-} - -module Haddock.Backends.Xhtml ( - ppHtml, copyHtmlBits, - ppHtmlIndex, ppHtmlContents, - ppJsonIndex -) where - +module Haddock.Backends.Xhtml + ( ppHtml + , copyHtmlBits + , ppHtmlIndex + , ppHtmlContents + , ppJsonIndex + ) where import Prelude hiding (div) @@ -34,101 +35,179 @@ import Haddock.Backends.Xhtml.Names import Haddock.Backends.Xhtml.Themes import Haddock.Backends.Xhtml.Types import Haddock.Backends.Xhtml.Utils +import Haddock.GhcUtils import Haddock.InterfaceFile (PackageInfo (..), PackageInterfaces (..), ppPackageInfo) import Haddock.ModuleTree import Haddock.Options (Visibility (..)) import Haddock.Types -import Haddock.Version import Haddock.Utils import Haddock.Utils.Json -import Text.XHtml hiding ( name, title, p, quote ) +import Haddock.Version +import Text.XHtml hiding (name, p, quote, title) import qualified Text.XHtml as XHtml -import Haddock.GhcUtils -import Control.Monad ( when, unless ) +import Control.DeepSeq (force) +import Control.Monad (unless, when) +import Data.Bifunctor (bimap) import qualified Data.ByteString.Builder as Builder -import Control.DeepSeq (force) -import Data.Bifunctor ( bimap ) -import Data.Char ( toUpper, isSpace ) -import Data.Either ( partitionEithers ) -import Data.Foldable ( traverse_, foldl') -import Data.List ( sortBy, isPrefixOf, intersperse ) +import Data.Char (isSpace, toUpper) +import Data.Either (partitionEithers) +import Data.Foldable (foldl', traverse_) +import Data.List (intersperse, isPrefixOf, sortBy) +import Data.Map.Strict (Map) +import qualified Data.Map.Strict as Map import Data.Maybe +import Data.Ord (comparing) +import qualified Data.Set as Set hiding (Set) import System.Directory -import System.FilePath hiding ( () ) -import qualified System.IO as IO +import System.FilePath hiding (()) import qualified System.FilePath as FilePath -import Data.Map.Strict (Map) -import qualified Data.Map.Strict as Map -import qualified Data.Set as Set hiding ( Set ) -import Data.Ord ( comparing ) +import qualified System.IO as IO -import GHC hiding ( NoLink, moduleInfo,LexicalFixity(..), anchor ) +import GHC hiding (LexicalFixity (..), NoLink, anchor, moduleInfo) import GHC.Types.Name import GHC.Unit.State -------------------------------------------------------------------------------- + -- * Generating HTML documentation --------------------------------------------------------------------------------- -ppHtml :: UnitState - -> String -- ^ Title - -> Maybe String -- ^ Package - -> [Interface] - -> [InstalledInterface] -- ^ Reexported interfaces - -> FilePath -- ^ Destination directory - -> Maybe (MDoc GHC.RdrName) -- ^ Prologue text, maybe - -> Themes -- ^ Themes - -> Maybe String -- ^ The mathjax URL (--mathjax) - -> SourceURLs -- ^ The source URL (--source) - -> WikiURLs -- ^ The wiki URL (--wiki) - -> BaseURL -- ^ The base URL (--base-url) - -> Maybe String -- ^ The contents URL (--use-contents) - -> Maybe String -- ^ The index URL (--use-index) - -> Bool -- ^ Whether to use unicode in output (--use-unicode) - -> Maybe String -- ^ Package name - -> PackageInfo -- ^ Package info - -> QualOption -- ^ How to qualify names - -> Bool -- ^ Output pretty html (newlines and indenting) - -> Bool -- ^ Also write Quickjump index - -> IO () - -ppHtml state doctitle maybe_package ifaces reexported_ifaces odir prologue - themes maybe_mathjax_url maybe_source_url maybe_wiki_url - maybe_base_url maybe_contents_url maybe_index_url unicode - pkg packageInfo qual debug withQuickjump = do - let - visible_ifaces = filter visible ifaces - visible i = OptHide `notElem` ifaceOptions i +-------------------------------------------------------------------------------- - when (isNothing maybe_contents_url) $ - ppHtmlContents state odir doctitle maybe_package - themes maybe_mathjax_url maybe_index_url maybe_source_url maybe_wiki_url +ppHtml + :: UnitState + -> String + -- ^ Title + -> Maybe String + -- ^ Package + -> [Interface] + -> [InstalledInterface] + -- ^ Reexported interfaces + -> FilePath + -- ^ Destination directory + -> Maybe (MDoc GHC.RdrName) + -- ^ Prologue text, maybe + -> Themes + -- ^ Themes + -> Maybe String + -- ^ The mathjax URL (--mathjax) + -> SourceURLs + -- ^ The source URL (--source) + -> WikiURLs + -- ^ The wiki URL (--wiki) + -> BaseURL + -- ^ The base URL (--base-url) + -> Maybe String + -- ^ The contents URL (--use-contents) + -> Maybe String + -- ^ The index URL (--use-index) + -> Bool + -- ^ Whether to use unicode in output (--use-unicode) + -> Maybe String + -- ^ Package name + -> PackageInfo + -- ^ Package info + -> QualOption + -- ^ How to qualify names + -> Bool + -- ^ Output pretty html (newlines and indenting) + -> Bool + -- ^ Also write Quickjump index + -> IO () +ppHtml + state + doctitle + maybe_package + ifaces + reexported_ifaces + odir + prologue + themes + maybe_mathjax_url + maybe_source_url + maybe_wiki_url + maybe_base_url + maybe_contents_url + maybe_index_url + unicode + pkg + packageInfo + qual + debug + withQuickjump = do + let + visible_ifaces = filter visible ifaces + visible i = OptHide `notElem` ifaceOptions i + + when (isNothing maybe_contents_url) $ + ppHtmlContents + state + odir + doctitle + maybe_package + themes + maybe_mathjax_url + maybe_index_url + maybe_source_url + maybe_wiki_url withQuickjump - [PackageInterfaces - { piPackageInfo = packageInfo - , piVisibility = Visible - , piInstalledInterfaces = map toInstalledIface visible_ifaces - ++ reexported_ifaces - }] + [ PackageInterfaces + { piPackageInfo = packageInfo + , piVisibility = Visible + , piInstalledInterfaces = + map toInstalledIface visible_ifaces + ++ reexported_ifaces + } + ] False -- we don't want to display the packages in a single-package contents - prologue debug pkg (makeContentsQual qual) - - when (isNothing maybe_index_url) $ do - ppHtmlIndex odir doctitle maybe_package - themes maybe_mathjax_url maybe_contents_url maybe_source_url maybe_wiki_url - withQuickjump - (map toInstalledIface visible_ifaces ++ reexported_ifaces) debug - - when withQuickjump $ - ppJsonIndex odir maybe_source_url maybe_wiki_url unicode pkg qual - visible_ifaces [] - - mapM_ (ppHtmlModule odir doctitle themes - maybe_mathjax_url maybe_source_url maybe_wiki_url maybe_base_url - maybe_contents_url maybe_index_url withQuickjump - unicode pkg qual debug) visible_ifaces - + prologue + debug + pkg + (makeContentsQual qual) + + when (isNothing maybe_index_url) $ do + ppHtmlIndex + odir + doctitle + maybe_package + themes + maybe_mathjax_url + maybe_contents_url + maybe_source_url + maybe_wiki_url + withQuickjump + (map toInstalledIface visible_ifaces ++ reexported_ifaces) + debug + + when withQuickjump $ + ppJsonIndex + odir + maybe_source_url + maybe_wiki_url + unicode + pkg + qual + visible_ifaces + [] + + mapM_ + ( ppHtmlModule + odir + doctitle + themes + maybe_mathjax_url + maybe_source_url + maybe_wiki_url + maybe_base_url + maybe_contents_url + maybe_index_url + withQuickjump + unicode + pkg + qual + debug + ) + visible_ifaces copyHtmlBits :: FilePath -> FilePath -> Themes -> Bool -> IO () copyHtmlBits odir libdir themes withQuickjump = do @@ -142,44 +221,56 @@ copyHtmlBits odir libdir themes withQuickjump = do when withQuickjump (copyLibFile jsQuickJumpFile) return () - headHtml :: String -> Themes -> Maybe String -> Maybe String -> Html headHtml docTitle themes mathjax_url base_url = - header ! (maybe [] (\url -> [identifier "head", strAttr "data-base-url" url ]) base_url) - << - [ meta ! [ httpequiv "Content-Type", content "text/html; charset=UTF-8"] - , meta ! [ XHtml.name "viewport", content "width=device-width, initial-scale=1"] - , thetitle << docTitle - , styleSheet base_url themes - , thelink ! [ rel "stylesheet" - , thetype "text/css" - , href (withBaseURL base_url quickJumpCssFile) ] - << noHtml - , thelink ! [ rel "stylesheet", thetype "text/css", href fontUrl] << noHtml - , script ! [ src (withBaseURL base_url haddockJsFile) - , emptyAttr "async" - , thetype "text/javascript" ] - << noHtml - , script ! [thetype "text/x-mathjax-config"] << primHtml mjConf - , script ! [src mjUrl, thetype "text/javascript"] << noHtml - ] + header + ! (maybe [] (\url -> [identifier "head", strAttr "data-base-url" url]) base_url) + << [ meta ! [httpequiv "Content-Type", content "text/html; charset=UTF-8"] + , meta ! [XHtml.name "viewport", content "width=device-width, initial-scale=1"] + , thetitle << docTitle + , styleSheet base_url themes + , thelink + ! [ rel "stylesheet" + , thetype "text/css" + , href (withBaseURL base_url quickJumpCssFile) + ] + << noHtml + , thelink ! [rel "stylesheet", thetype "text/css", href fontUrl] << noHtml + , script + ! [ src (withBaseURL base_url haddockJsFile) + , emptyAttr "async" + , thetype "text/javascript" + ] + << noHtml + , script ! [thetype "text/x-mathjax-config"] << primHtml mjConf + , script ! [src mjUrl, thetype "text/javascript"] << noHtml + ] where fontUrl = "https://fonts.googleapis.com/css?family=PT+Sans:400,400i,700" mjUrl = fromMaybe "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML" mathjax_url - mjConf = unwords [ "MathJax.Hub.Config({" - , "tex2jax: {" - , "processClass: \"mathjax\"," - , "ignoreClass: \".*\"" - , "}" - , "});" ] - -quickJumpButtonLi :: Bool -- ^ With Quick Jump? - -> Maybe Html + mjConf = + unwords + [ "MathJax.Hub.Config({" + , "tex2jax: {" + , "processClass: \"mathjax\"," + , "ignoreClass: \".*\"" + , "}" + , "});" + ] + +quickJumpButtonLi + :: Bool + -- ^ With Quick Jump? + -> Maybe Html -- The TypeScript should replace this
  • element, given its id. However, in -- case it does not, the element is given content here too. -quickJumpButtonLi True = Just $ li ! [identifier "quick-jump-button"] - << anchor ! [href "#"] << "Quick Jump" - +quickJumpButtonLi True = + Just $ + li + ! [identifier "quick-jump-button"] + << anchor + ! [href "#"] + << "Quick Jump" quickJumpButtonLi False = Nothing srcButton :: SourceURLs -> Maybe Interface -> Maybe Html @@ -191,169 +282,211 @@ srcButton (_, Just src_module_url, _, _) (Just iface) = srcButton _ _ = Nothing - wikiButton :: WikiURLs -> Maybe Module -> Maybe Html wikiButton (Just wiki_base_url, _, _) Nothing = Just (anchor ! [href wiki_base_url] << "User Comments") - wikiButton (_, Just wiki_module_url, _) (Just mdl) = let url = spliceURL (Just mdl) Nothing Nothing wiki_module_url in Just (anchor ! [href url] << "User Comments") - wikiButton _ _ = Nothing - contentsButton :: Maybe String -> Maybe Html -contentsButton maybe_contents_url - = Just (anchor ! [href url] << "Contents") - where url = fromMaybe contentsHtmlFile maybe_contents_url - +contentsButton maybe_contents_url = + Just (anchor ! [href url] << "Contents") + where + url = fromMaybe contentsHtmlFile maybe_contents_url indexButton :: Maybe String -> Maybe Html -indexButton maybe_index_url - = Just (anchor ! [href url] << "Index") - where url = fromMaybe indexHtmlFile maybe_index_url - - -bodyHtml :: String -> Maybe Interface - -> SourceURLs -> WikiURLs - -> Maybe String -> Maybe String - -> Bool -- ^ With Quick Jump? - -> Html -> Html -bodyHtml doctitle iface - maybe_source_url maybe_wiki_url - maybe_contents_url maybe_index_url - withQuickjump - pageContent = - body << [ - divPackageHeader << [ - nonEmptySectionName << doctitle, - ulist ! [theclass "links", identifier "page-menu"] - << catMaybes (quickJumpButtonLi withQuickjump : otherButtonLis) - ], - divContent << pageContent, - divFooter << paragraph << ( - "Produced by " +++ - (anchor ! [href projectUrl] << toHtml projectName) +++ - (" version " ++ projectVersion) - ) - ] - where - otherButtonLis = (fmap . fmap) (li <<) - [ srcButton maybe_source_url iface - , wikiButton maybe_wiki_url (ifaceMod <$> iface) - , contentsButton maybe_contents_url - , indexButton maybe_index_url - ] +indexButton maybe_index_url = + Just (anchor ! [href url] << "Index") + where + url = fromMaybe indexHtmlFile maybe_index_url + +bodyHtml + :: String + -> Maybe Interface + -> SourceURLs + -> WikiURLs + -> Maybe String + -> Maybe String + -> Bool + -- ^ With Quick Jump? + -> Html + -> Html +bodyHtml + doctitle + iface + maybe_source_url + maybe_wiki_url + maybe_contents_url + maybe_index_url + withQuickjump + pageContent = + body + << [ divPackageHeader + << [ nonEmptySectionName << doctitle + , ulist + ! [theclass "links", identifier "page-menu"] + << catMaybes (quickJumpButtonLi withQuickjump : otherButtonLis) + ] + , divContent << pageContent + , divFooter + << paragraph + << ( "Produced by " + +++ (anchor ! [href projectUrl] << toHtml projectName) + +++ (" version " ++ projectVersion) + ) + ] + where + otherButtonLis = + (fmap . fmap) + (li <<) + [ srcButton maybe_source_url iface + , wikiButton maybe_wiki_url (ifaceMod <$> iface) + , contentsButton maybe_contents_url + , indexButton maybe_index_url + ] moduleInfo :: Interface -> Html moduleInfo iface = - let - info = ifaceInfo iface - - doOneEntry :: (String, HaddockModInfo GHC.Name -> Maybe String) -> Maybe HtmlTable - doOneEntry (fldNm, fld) = - fld info >>= \a -> return (th << fldNm <-> td << a) - - entries :: [HtmlTable] - entries = maybeToList copyrightsTable ++ mapMaybe doOneEntry [ - ("License",hmi_license), - ("Maintainer",hmi_maintainer), - ("Stability",hmi_stability), - ("Portability",hmi_portability), - ("Safe Haskell",hmi_safety), - ("Language", lg) - ] ++ extsForm - where - lg inf = fmap show (hmi_language inf) + let + info = ifaceInfo iface + + doOneEntry :: (String, HaddockModInfo GHC.Name -> Maybe String) -> Maybe HtmlTable + doOneEntry (fldNm, fld) = + fld info >>= \a -> return (th << fldNm <-> td << a) + + entries :: [HtmlTable] + entries = + maybeToList copyrightsTable + ++ mapMaybe + doOneEntry + [ ("License", hmi_license) + , ("Maintainer", hmi_maintainer) + , ("Stability", hmi_stability) + , ("Portability", hmi_portability) + , ("Safe Haskell", hmi_safety) + , ("Language", lg) + ] + ++ extsForm + where + lg inf = fmap show (hmi_language inf) - multilineRow :: String -> [String] -> HtmlTable - multilineRow title xs = (th ! [valign "top"]) << title <-> td << (toLines xs) - where toLines = mconcat . intersperse br . map toHtml + multilineRow :: String -> [String] -> HtmlTable + multilineRow title xs = (th ! [valign "top"]) << title <-> td << (toLines xs) + where + toLines = mconcat . intersperse br . map toHtml - copyrightsTable :: Maybe HtmlTable - copyrightsTable = fmap (multilineRow "Copyright" . split) (hmi_copyright info) - where split = map (trim . filter (/= ',')) . lines + copyrightsTable :: Maybe HtmlTable + copyrightsTable = fmap (multilineRow "Copyright" . split) (hmi_copyright info) + where + split = map (trim . filter (/= ',')) . lines - extsForm - | OptShowExtensions `elem` ifaceOptions iface = + extsForm + | OptShowExtensions `elem` ifaceOptions iface = let fs = map (dropOpt . show) (hmi_extensions info) - in case map stringToHtml fs of - [] -> [] - [x] -> extField x -- don't use a list for a single extension - xs -> extField $ unordList xs ! [theclass "extension-list"] - | otherwise = [] - where - extField x = return $ th << "Extensions" <-> td << x - dropOpt x = if "Opt_" `isPrefixOf` x then drop 4 x else x + in case map stringToHtml fs of + [] -> [] + [x] -> extField x -- don't use a list for a single extension + xs -> extField $ unordList xs ! [theclass "extension-list"] + | otherwise = [] + where + extField x = return $ th << "Extensions" <-> td << x + dropOpt x = if "Opt_" `isPrefixOf` x then drop 4 x else x in - case entries of - [] -> noHtml - _ -> table ! [theclass "info"] << aboves entries - + case entries of + [] -> noHtml + _ -> table ! [theclass "info"] << aboves entries -------------------------------------------------------------------------------- + -- * Generate the module contents --------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- ppHtmlContents - :: UnitState - -> FilePath - -> String - -> Maybe String - -> Themes - -> Maybe String - -> Maybe String - -> SourceURLs - -> WikiURLs - -> Bool -- ^ With Quick Jump? - -> [PackageInterfaces] -> Bool -> Maybe (MDoc GHC.RdrName) - -> Bool - -> Maybe Package -- ^ Current package - -> Qualification -- ^ How to qualify names - -> IO () -ppHtmlContents state odir doctitle _maybe_package - themes mathjax_url maybe_index_url - maybe_source_url maybe_wiki_url withQuickjump - packages showPkgs prologue debug pkg qual = do - let trees = - [ ( piPackageInfo pinfo - , mkModuleTree state showPkgs - [(instMod iface, toInstalledDescription iface) - | iface <- piInstalledInterfaces pinfo - , not (instIsSig iface) - ] - ) - | pinfo <- packages - ] - sig_trees = - [ ( piPackageInfo pinfo - , mkModuleTree state showPkgs - [(instMod iface, toInstalledDescription iface) - | iface <- piInstalledInterfaces pinfo - , instIsSig iface - ] - ) - | pinfo <- packages - ] - html = - headHtml doctitle themes mathjax_url Nothing +++ - bodyHtml doctitle Nothing - maybe_source_url maybe_wiki_url - Nothing maybe_index_url withQuickjump << [ - ppPrologue pkg qual doctitle prologue, - ppSignatureTrees pkg qual sig_trees, - ppModuleTrees pkg qual trees + :: UnitState + -> FilePath + -> String + -> Maybe String + -> Themes + -> Maybe String + -> Maybe String + -> SourceURLs + -> WikiURLs + -> Bool + -- ^ With Quick Jump? + -> [PackageInterfaces] + -> Bool + -> Maybe (MDoc GHC.RdrName) + -> Bool + -> Maybe Package + -- ^ Current package + -> Qualification + -- ^ How to qualify names + -> IO () +ppHtmlContents + state + odir + doctitle + _maybe_package + themes + mathjax_url + maybe_index_url + maybe_source_url + maybe_wiki_url + withQuickjump + packages + showPkgs + prologue + debug + pkg + qual = do + let trees = + [ ( piPackageInfo pinfo + , mkModuleTree + state + showPkgs + [ (instMod iface, toInstalledDescription iface) + | iface <- piInstalledInterfaces pinfo + , not (instIsSig iface) + ] + ) + | pinfo <- packages ] - createDirectoryIfMissing True odir - writeUtf8File (joinPath [odir, contentsHtmlFile]) (renderToString debug html) - where - -- Extract a module's short description. - toInstalledDescription :: InstalledInterface -> Maybe (MDoc Name) - toInstalledDescription = fmap mkMeta . hmi_description . instInfo - + sig_trees = + [ ( piPackageInfo pinfo + , mkModuleTree + state + showPkgs + [ (instMod iface, toInstalledDescription iface) + | iface <- piInstalledInterfaces pinfo + , instIsSig iface + ] + ) + | pinfo <- packages + ] + html = + headHtml doctitle themes mathjax_url Nothing + +++ bodyHtml + doctitle + Nothing + maybe_source_url + maybe_wiki_url + Nothing + maybe_index_url + withQuickjump + << [ ppPrologue pkg qual doctitle prologue + , ppSignatureTrees pkg qual sig_trees + , ppModuleTrees pkg qual trees + ] + createDirectoryIfMissing True odir + writeUtf8File (joinPath [odir, contentsHtmlFile]) (renderToString debug html) + where + -- Extract a module's short description. + toInstalledDescription :: InstalledInterface -> Maybe (MDoc Name) + toInstalledDescription = fmap mkMeta . hmi_description . instInfo ppPrologue :: Maybe Package -> Qualification -> String -> Maybe (MDoc GHC.RdrName) -> Html ppPrologue _ _ _ Nothing = noHtml @@ -365,11 +498,14 @@ ppSignatureTrees _ _ tss | all (null . snd) tss = mempty ppSignatureTrees pkg qual [(info, ts)] = divPackageList << (sectionName << "Signatures" +++ ppSignatureTree pkg qual "n" info ts) ppSignatureTrees pkg qual tss = - divModuleList << - (sectionName << "Signatures" - +++ concatHtml [ ppSignatureTree pkg qual("n."++show i++".") info ts - | (i, (info, ts)) <- zip [(1::Int)..] tss - ]) + divModuleList + << ( sectionName + << "Signatures" + +++ concatHtml + [ ppSignatureTree pkg qual ("n." ++ show i ++ ".") info ts + | (i, (info, ts)) <- zip [(1 :: Int) ..] tss + ] + ) ppSignatureTree :: Maybe Package -> Qualification -> String -> PackageInfo -> [ModuleTree] -> Html ppSignatureTree _ _ _ _ [] = mempty @@ -381,156 +517,179 @@ ppModuleTrees _ _ tss | all (null . snd) tss = mempty ppModuleTrees pkg qual [(info, ts)] = divModuleList << (sectionName << "Modules" +++ ppModuleTree pkg qual "n" info ts) ppModuleTrees pkg qual tss = - divPackageList << - (sectionName << "Packages" - +++ concatHtml [ppModuleTree pkg qual ("n."++show i++".") info ts - | (i, (info, ts)) <- zip [(1::Int)..] tss - ]) + divPackageList + << ( sectionName + << "Packages" + +++ concatHtml + [ ppModuleTree pkg qual ("n." ++ show i ++ ".") info ts + | (i, (info, ts)) <- zip [(1 :: Int) ..] tss + ] + ) ppModuleTree :: Maybe Package -> Qualification -> String -> PackageInfo -> [ModuleTree] -> Html ppModuleTree _ _ _ _ [] = mempty ppModuleTree pkg qual p info ts = divModuleList << (sectionName << ppPackageInfo info +++ mkNodeList pkg qual [] p ts) - mkNodeList :: Maybe Package -> Qualification -> [String] -> String -> [ModuleTree] -> Html mkNodeList pkg qual ss p ts = case ts of [] -> noHtml _ -> unordList (zipWith (mkNode pkg qual ss) ps ts) where - ps = [ p ++ '.' : show i | i <- [(1::Int)..]] - + ps = [p ++ '.' : show i | i <- [(1 :: Int) ..]] mkNode :: Maybe Package -> Qualification -> [String] -> String -> ModuleTree -> Html mkNode pkg qual ss p (Node s leaf _pkg srcPkg short ts) = htmlModule <+> shortDescr +++ htmlPkg +++ subtree where modAttrs = case (ts, leaf) of - (_:_, Nothing) -> collapseControl p "module" - (_, _ ) -> [theclass "module"] + (_ : _, Nothing) -> collapseControl p "module" + (_, _) -> [theclass "module"] cBtn = case (ts, leaf) of - (_:_, Just _) -> thespan ! collapseControl p "" << spaceHtml - ([] , Just _) -> thespan ! [theclass "noexpander"] << spaceHtml - (_, _ ) -> noHtml - -- We only need an explicit collapser button when the module name - -- is also a leaf, and so is a link to a module page. Indeed, the - -- spaceHtml is a minor hack and does upset the layout a fraction. - - htmlModule = thespan ! modAttrs << (cBtn +++ - case leaf of - Just m -> ppModule m - Nothing -> toHtml s - ) + (_ : _, Just _) -> thespan ! collapseControl p "" << spaceHtml + ([], Just _) -> thespan ! [theclass "noexpander"] << spaceHtml + (_, _) -> noHtml + -- We only need an explicit collapser button when the module name + -- is also a leaf, and so is a link to a module page. Indeed, the + -- spaceHtml is a minor hack and does upset the layout a fraction. + + htmlModule = + thespan + ! modAttrs + << ( cBtn + +++ case leaf of + Just m -> ppModule m + Nothing -> toHtml s + ) shortDescr = maybe noHtml (origDocToHtml pkg qual) short htmlPkg = maybe noHtml (thespan ! [theclass "package"] <<) srcPkg subtree = - if null ts then noHtml else - collapseDetails p DetailsOpen ( - thesummary ! [ theclass "hide-when-js-enabled" ] << "Submodules" +++ - mkNodeList pkg qual (s:ss) p ts - ) + if null ts + then noHtml + else + collapseDetails + p + DetailsOpen + ( thesummary + ! [theclass "hide-when-js-enabled"] + << "Submodules" + +++ mkNodeList pkg qual (s : ss) p ts + ) -------------------------------------------------------------------------------- + -- * Generate the index + -------------------------------------------------------------------------------- -data JsonIndexEntry = JsonIndexEntry { - jieHtmlFragment :: String, - jieName :: String, - jieModule :: String, - jieLink :: String - } - deriving Show +data JsonIndexEntry = JsonIndexEntry + { jieHtmlFragment :: String + , jieName :: String + , jieModule :: String + , jieLink :: String + } + deriving (Show) instance ToJSON JsonIndexEntry where - toJSON JsonIndexEntry - { jieHtmlFragment - , jieName - , jieModule - , jieLink } = + toJSON + JsonIndexEntry + { jieHtmlFragment + , jieName + , jieModule + , jieLink + } = Object [ "display_html" .= String jieHtmlFragment - , "name" .= String jieName - , "module" .= String jieModule - , "link" .= String jieLink + , "name" .= String jieName + , "module" .= String jieModule + , "link" .= String jieLink ] instance FromJSON JsonIndexEntry where - parseJSON = withObject "JsonIndexEntry" $ \v -> - JsonIndexEntry - <$> v .: "display_html" - <*> v .: "name" - <*> v .: "module" - <*> v .: "link" - -ppJsonIndex :: FilePath - -> SourceURLs -- ^ The source URL (--source) - -> WikiURLs -- ^ The wiki URL (--wiki) - -> Bool - -> Maybe Package - -> QualOption - -> [Interface] - -> [FilePath] -- ^ file paths to interface files - -- (--read-interface) - -> IO () + parseJSON = withObject "JsonIndexEntry" $ \v -> + JsonIndexEntry + <$> v .: "display_html" + <*> v .: "name" + <*> v .: "module" + <*> v .: "link" + +ppJsonIndex + :: FilePath + -> SourceURLs + -- ^ The source URL (--source) + -> WikiURLs + -- ^ The wiki URL (--wiki) + -> Bool + -> Maybe Package + -> QualOption + -> [Interface] + -> [FilePath] + -- ^ file paths to interface files + -- (--read-interface) + -> IO () ppJsonIndex odir maybe_source_url maybe_wiki_url unicode pkg qual_opt ifaces installedIfacesPaths = do createDirectoryIfMissing True odir (errors, installedIndexes) <- partitionEithers <$> traverse - (\ifaceFile -> do - let indexFile = takeDirectory ifaceFile + ( \ifaceFile -> do + let indexFile = + takeDirectory ifaceFile FilePath. "doc-index.json" - a <- doesFileExist indexFile - if a then - bimap (indexFile,) (map (fixLink ifaceFile)) - <$> eitherDecodeFile @[JsonIndexEntry] indexFile - else - return (Right []) - ) - installedIfacesPaths - traverse_ (\(indexFile, err) -> putStrLn $ "haddock: Coudn't parse " ++ indexFile ++ ": " ++ err) - errors + a <- doesFileExist indexFile + if a + then + bimap (indexFile,) (map (fixLink ifaceFile)) + <$> eitherDecodeFile @[JsonIndexEntry] indexFile + else return (Right []) + ) + installedIfacesPaths + traverse_ + (\(indexFile, err) -> putStrLn $ "haddock: Coudn't parse " ++ indexFile ++ ": " ++ err) + errors IO.withBinaryFile (joinPath [odir, indexJsonFile]) IO.WriteMode $ \h -> - Builder.hPutBuilder - h (encodeToBuilder (encodeIndexes (concat installedIndexes))) + Builder.hPutBuilder + h + (encodeToBuilder (encodeIndexes (concat installedIndexes))) where encodeIndexes :: [JsonIndexEntry] -> Value encodeIndexes installedIndexes = toJSON - (concatMap fromInterface ifaces - ++ installedIndexes) + ( concatMap fromInterface ifaces + ++ installedIndexes + ) fromInterface :: Interface -> [JsonIndexEntry] fromInterface iface = - mkIndex mdl qual `mapMaybe` ifaceRnExportItems iface + mkIndex mdl qual `mapMaybe` ifaceRnExportItems iface where - qual = makeModuleQual qual_opt mdl - mdl = ifaceMod iface + qual = makeModuleQual qual_opt mdl + mdl = ifaceMod iface mkIndex :: Module -> Qualification -> ExportItem DocNameI -> Maybe JsonIndexEntry mkIndex mdl qual item - | Just item_html <- processExport True links_info unicode pkg qual item - = Just JsonIndexEntry - { jieHtmlFragment = showHtmlFragment item_html - , jieName = unwords (map getOccString names) - , jieModule = moduleString mdl - , jieLink = fromMaybe "" (listToMaybe (map (nameLink mdl) names)) - } + | Just item_html <- processExport True links_info unicode pkg qual item = + Just + JsonIndexEntry + { jieHtmlFragment = showHtmlFragment item_html + , jieName = unwords (map getOccString names) + , jieModule = moduleString mdl + , jieLink = fromMaybe "" (listToMaybe (map (nameLink mdl) names)) + } | otherwise = Nothing where names = exportName item ++ exportSubs item exportSubs :: ExportItem DocNameI -> [IdP DocNameI] - exportSubs (ExportDecl (RnExportD { rnExpDExpD = ExportD { expDSubDocs } })) = map fst expDSubDocs + exportSubs (ExportDecl (RnExportD{rnExpDExpD = ExportD{expDSubDocs}})) = map fst expDSubDocs exportSubs _ = [] exportName :: ExportItem DocNameI -> [IdP DocNameI] - exportName (ExportDecl (RnExportD { rnExpDExpD = ExportD { expDDecl } })) = getMainDeclBinderI (unLoc expDDecl) - exportName ExportNoDecl { expItemName } = [expItemName] + exportName (ExportDecl (RnExportD{rnExpDExpD = ExportD{expDDecl}})) = getMainDeclBinderI (unLoc expDDecl) + exportName ExportNoDecl{expItemName} = [expItemName] exportName _ = [] nameLink :: NamedThing name => Module -> name -> String @@ -539,206 +698,277 @@ ppJsonIndex odir maybe_source_url maybe_wiki_url unicode pkg qual_opt ifaces ins links_info = (maybe_source_url, maybe_wiki_url) -- update link using relative path to output directory - fixLink :: FilePath - -> JsonIndexEntry -> JsonIndexEntry + fixLink + :: FilePath + -> JsonIndexEntry + -> JsonIndexEntry fixLink ifaceFile jie = - jie { jieLink = makeRelative odir (takeDirectory ifaceFile) - FilePath. jieLink jie } - -ppHtmlIndex :: FilePath - -> String - -> Maybe String - -> Themes - -> Maybe String - -> Maybe String - -> SourceURLs - -> WikiURLs - -> Bool -- ^ With Quick Jump? - -> [InstalledInterface] - -> Bool - -> IO () -ppHtmlIndex odir doctitle _maybe_package themes - maybe_mathjax_url maybe_contents_url maybe_source_url maybe_wiki_url withQuickjump ifaces debug = do - let html = indexPage split_indices Nothing - (if split_indices then [] else index) - - createDirectoryIfMissing True odir + jie + { jieLink = + makeRelative odir (takeDirectory ifaceFile) + FilePath. jieLink jie + } - when split_indices $ do - mapM_ (do_sub_index index) initialChars - -- Let's add a single large index as well for those who don't know exactly what they're looking for: - let mergedhtml = indexPage False Nothing index - writeUtf8File (joinPath [odir, subIndexHtmlFile merged_name]) (renderToString debug mergedhtml) +ppHtmlIndex + :: FilePath + -> String + -> Maybe String + -> Themes + -> Maybe String + -> Maybe String + -> SourceURLs + -> WikiURLs + -> Bool + -- ^ With Quick Jump? + -> [InstalledInterface] + -> Bool + -> IO () +ppHtmlIndex + odir + doctitle + _maybe_package + themes + maybe_mathjax_url + maybe_contents_url + maybe_source_url + maybe_wiki_url + withQuickjump + ifaces + debug = do + let html = + indexPage + split_indices + Nothing + (if split_indices then [] else index) + + createDirectoryIfMissing True odir + + when split_indices $ do + mapM_ (do_sub_index index) initialChars + -- Let's add a single large index as well for those who don't know exactly what they're looking for: + let mergedhtml = indexPage False Nothing index + writeUtf8File (joinPath [odir, subIndexHtmlFile merged_name]) (renderToString debug mergedhtml) + + writeUtf8File (joinPath [odir, indexHtmlFile]) (renderToString debug html) + where + indexPage showLetters ch items = + headHtml (doctitle ++ " (" ++ indexName ch ++ ")") themes maybe_mathjax_url Nothing + +++ bodyHtml + doctitle + Nothing + maybe_source_url + maybe_wiki_url + maybe_contents_url + Nothing + withQuickjump + << [ if showLetters then indexInitialLetterLinks else noHtml + , if null items + then noHtml + else divIndex << [sectionName << indexName ch, buildIndex items] + ] + + indexName ch = "Index" ++ maybe "" (\c -> " - " ++ [c]) ch + merged_name = "All" + + buildIndex items = table << aboves (map indexElt items) + + -- an arbitrary heuristic: + -- too large, and a single-page will be slow to load + -- too small, and we'll have lots of letter-indexes with only one + -- or two members in them, which seems inefficient or + -- unnecessarily hard to use. + split_indices = length index > 150 + + indexInitialLetterLinks = + divAlphabet + << unordList + ( map (\str -> anchor ! [href (subIndexHtmlFile str)] << str) $ + [ [c] | c <- initialChars, any ((== c) . toUpper . head . fst) index + ] + ++ [merged_name] + ) - writeUtf8File (joinPath [odir, indexHtmlFile]) (renderToString debug html) + -- todo: what about names/operators that start with Unicode + -- characters? + -- Exports beginning with '_' can be listed near the end, + -- presumably they're not as important... but would be listed + -- with non-split index! + initialChars = ['A' .. 'Z'] ++ ":!#$%&*+./<=>?@\\^|-~" ++ "_" - where - indexPage showLetters ch items = - headHtml (doctitle ++ " (" ++ indexName ch ++ ")") themes maybe_mathjax_url Nothing +++ - bodyHtml doctitle Nothing - maybe_source_url maybe_wiki_url - maybe_contents_url Nothing withQuickjump << [ - if showLetters then indexInitialLetterLinks else noHtml, - if null items then noHtml else - divIndex << [sectionName << indexName ch, buildIndex items] - ] - - indexName ch = "Index" ++ maybe "" (\c -> " - " ++ [c]) ch - merged_name = "All" - - buildIndex items = table << aboves (map indexElt items) - - -- an arbitrary heuristic: - -- too large, and a single-page will be slow to load - -- too small, and we'll have lots of letter-indexes with only one - -- or two members in them, which seems inefficient or - -- unnecessarily hard to use. - split_indices = length index > 150 - - indexInitialLetterLinks = - divAlphabet << - unordList (map (\str -> anchor ! [href (subIndexHtmlFile str)] << str) $ - [ [c] | c <- initialChars - , any ((==c) . toUpper . head . fst) index ] ++ - [merged_name]) - - -- todo: what about names/operators that start with Unicode - -- characters? - -- Exports beginning with '_' can be listed near the end, - -- presumably they're not as important... but would be listed - -- with non-split index! - initialChars = [ 'A'..'Z' ] ++ ":!#$%&*+./<=>?@\\^|-~" ++ "_" - - do_sub_index this_ix c - = unless (null index_part) $ + do_sub_index this_ix c = + unless (null index_part) $ writeUtf8File (joinPath [odir, subIndexHtmlFile [c]]) (renderToString debug html) - where - html = indexPage True (Just c) index_part - index_part = [(n,stuff) | (n,stuff) <- this_ix, toUpper (head n) == c] - - - index :: [(String, Map GHC.Name [(Module,Bool)])] - index = sortBy cmp (Map.toAscList full_index) - where cmp (n1,_) (n2,_) = comparing (map toUpper) n1 n2 + where + html = indexPage True (Just c) index_part + index_part = [(n, stuff) | (n, stuff) <- this_ix, toUpper (head n) == c] - -- for each name (a plain string), we have a number of original HsNames that - -- it can refer to, and for each of those we have a list of modules - -- that export that entity. Each of the modules exports the entity - -- in a visible or invisible way (hence the Bool). - full_index :: Map String (Map GHC.Name [(Module,Bool)]) - full_index = foldl' f Map.empty ifaces - where - f :: Map String (Map Name [(Module, Bool)]) - -> InstalledInterface - -> Map String (Map Name [(Module, Bool)]) - f !idx iface = - Map.unionWith - (Map.unionWith (\a b -> let !x = force $ a ++ b in x)) - idx - (getIfaceIndex iface) - - - getIfaceIndex :: InstalledInterface -> Map String (Map Name [(Module, Bool)]) - getIfaceIndex iface = - foldl' f Map.empty (instExports iface) - where - f :: Map String (Map Name [(Module, Bool)]) - -> Name - -> Map String (Map Name [(Module, Bool)]) - f !idx name = - let !vis = name `Set.member` visible - in - Map.insertWith - (Map.unionWith (++)) - (getOccString name) - (Map.singleton name [(mdl, vis)]) + index :: [(String, Map GHC.Name [(Module, Bool)])] + index = sortBy cmp (Map.toAscList full_index) + where + cmp (n1, _) (n2, _) = comparing (map toUpper) n1 n2 + + -- for each name (a plain string), we have a number of original HsNames that + -- it can refer to, and for each of those we have a list of modules + -- that export that entity. Each of the modules exports the entity + -- in a visible or invisible way (hence the Bool). + full_index :: Map String (Map GHC.Name [(Module, Bool)]) + full_index = foldl' f Map.empty ifaces + where + f + :: Map String (Map Name [(Module, Bool)]) + -> InstalledInterface + -> Map String (Map Name [(Module, Bool)]) + f !idx iface = + Map.unionWith + (Map.unionWith (\a b -> let !x = force $ a ++ b in x)) idx + (getIfaceIndex iface) - mdl = instMod iface - visible = Set.fromList (instVisibleExports iface) - - indexElt :: (String, Map GHC.Name [(Module,Bool)]) -> HtmlTable - indexElt (str, entities) = - case Map.toAscList entities of - [(nm,entries)] -> - td ! [ theclass "src" ] << toHtml str <-> - indexLinks nm entries + getIfaceIndex :: InstalledInterface -> Map String (Map Name [(Module, Bool)]) + getIfaceIndex iface = + foldl' f Map.empty (instExports iface) + where + f + :: Map String (Map Name [(Module, Bool)]) + -> Name + -> Map String (Map Name [(Module, Bool)]) + f !idx name = + let !vis = name `Set.member` visible + in Map.insertWith + (Map.unionWith (++)) + (getOccString name) + (Map.singleton name [(mdl, vis)]) + idx + + mdl = instMod iface + visible = Set.fromList (instVisibleExports iface) + + indexElt :: (String, Map GHC.Name [(Module, Bool)]) -> HtmlTable + indexElt (str, entities) = + case Map.toAscList entities of + [(nm, entries)] -> + td + ! [theclass "src"] + << toHtml str + <-> indexLinks nm entries many_entities -> - td ! [ theclass "src" ] << toHtml str <-> td << spaceHtml - aboves (zipWith (curry doAnnotatedEntity) [1..] many_entities) - - doAnnotatedEntity :: (Integer, (Name, [(Module, Bool)])) -> HtmlTable - doAnnotatedEntity (j,(nm,entries)) - = td ! [ theclass "alt" ] << - toHtml (show j) <+> parens (ppAnnot (nameOccName nm)) <-> - indexLinks nm entries - - ppAnnot n | not (isValOcc n) = toHtml "Type/Class" - | isDataOcc n = toHtml "Data Constructor" - | otherwise = toHtml "Function" - - indexLinks nm entries = - td ! [ theclass "module" ] << - hsep (punctuate comma - [ if visible then - linkId mdl (Just nm) << toHtml (moduleString mdl) - else - toHtml (moduleString mdl) - | (mdl, visible) <- entries ]) - + td + ! [theclass "src"] + << toHtml str + <-> td + << spaceHtml + aboves (zipWith (curry doAnnotatedEntity) [1 ..] many_entities) + + doAnnotatedEntity :: (Integer, (Name, [(Module, Bool)])) -> HtmlTable + doAnnotatedEntity (j, (nm, entries)) = + td + ! [theclass "alt"] + << toHtml (show j) + <+> parens (ppAnnot (nameOccName nm)) + <-> indexLinks nm entries + + ppAnnot n + | not (isValOcc n) = toHtml "Type/Class" + | isDataOcc n = toHtml "Data Constructor" + | otherwise = toHtml "Function" + + indexLinks nm entries = + td + ! [theclass "module"] + << hsep + ( punctuate + comma + [ if visible + then linkId mdl (Just nm) << toHtml (moduleString mdl) + else toHtml (moduleString mdl) + | (mdl, visible) <- entries + ] + ) -------------------------------------------------------------------------------- + -- * Generate the HTML page for a module --------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- ppHtmlModule - :: FilePath -> String -> Themes - -> Maybe String -> SourceURLs -> WikiURLs -> BaseURL - -> Maybe String -> Maybe String - -> Bool -- ^ With Quick Jump? - -> Bool -> Maybe Package -> QualOption - -> Bool -> Interface -> IO () -ppHtmlModule odir doctitle themes - maybe_mathjax_url maybe_source_url maybe_wiki_url maybe_base_url - maybe_contents_url maybe_index_url withQuickjump - unicode pkg qual debug iface = do - let + :: FilePath + -> String + -> Themes + -> Maybe String + -> SourceURLs + -> WikiURLs + -> BaseURL + -> Maybe String + -> Maybe String + -> Bool + -- ^ With Quick Jump? + -> Bool + -> Maybe Package + -> QualOption + -> Bool + -> Interface + -> IO () +ppHtmlModule + odir + doctitle + themes + maybe_mathjax_url + maybe_source_url + maybe_wiki_url + maybe_base_url + maybe_contents_url + maybe_index_url + withQuickjump + unicode + pkg + qual + debug + iface = do + let mdl = ifaceMod iface mdl_str = moduleString mdl - mdl_str_annot = mdl_str ++ if ifaceIsSig iface - then " (signature)" - else "" + mdl_str_annot = + mdl_str + ++ if ifaceIsSig iface + then " (signature)" + else "" mdl_str_linked - | ifaceIsSig iface - = mdl_str +++ " (signature" +++ - sup << ("[" +++ anchor ! [href signatureDocURL] << "?" +++ "]" ) +++ - ")" - | otherwise - = toHtml mdl_str + | ifaceIsSig iface = + mdl_str + +++ " (signature" + +++ sup + << ("[" +++ anchor ! [href signatureDocURL] << "?" +++ "]") + +++ ")" + | otherwise = + toHtml mdl_str real_qual = makeModuleQual qual mdl html = - headHtml mdl_str_annot themes maybe_mathjax_url maybe_base_url +++ - bodyHtml doctitle (Just iface) - maybe_source_url maybe_wiki_url - maybe_contents_url maybe_index_url withQuickjump << [ - divModuleHeader << (moduleInfo iface +++ (sectionName << mdl_str_linked)), - ifaceToHtml maybe_source_url maybe_wiki_url iface unicode pkg real_qual - ] - - createDirectoryIfMissing True odir - writeUtf8File (joinPath [odir, moduleHtmlFile mdl]) (renderToString debug html) + headHtml mdl_str_annot themes maybe_mathjax_url maybe_base_url + +++ bodyHtml + doctitle + (Just iface) + maybe_source_url + maybe_wiki_url + maybe_contents_url + maybe_index_url + withQuickjump + << [ divModuleHeader << (moduleInfo iface +++ (sectionName << mdl_str_linked)) + , ifaceToHtml maybe_source_url maybe_wiki_url iface unicode pkg real_qual + ] + + createDirectoryIfMissing True odir + writeUtf8File (joinPath [odir, moduleHtmlFile mdl]) (renderToString debug html) signatureDocURL :: String signatureDocURL = "https://wiki.haskell.org/Module_signature" - ifaceToHtml :: SourceURLs -> WikiURLs -> Interface -> Bool -> Maybe Package -> Qualification -> Html -ifaceToHtml maybe_source_url maybe_wiki_url iface unicode pkg qual - = ppModuleContents pkg qual exports (not . null $ ifaceRnOrphanInstances iface) +++ - description +++ - synopsis +++ - divInterface (maybe_doc_hdr +++ bdy +++ orphans) +ifaceToHtml maybe_source_url maybe_wiki_url iface unicode pkg qual = + ppModuleContents pkg qual exports (not . null $ ifaceRnOrphanInstances iface) + +++ description + +++ synopsis + +++ divInterface (maybe_doc_hdr +++ bdy +++ orphans) where exports = numberSectionHeadings (ifaceRnExportItems iface) @@ -746,44 +976,50 @@ ifaceToHtml maybe_source_url maybe_wiki_url iface unicode pkg qual -- it be measured here and thus prevent omitting the synopsis? has_doc ( ExportDecl - ( RnExportD - { rnExpDExpD = - ExportD - { expDMbDoc = - ( Documentation mDoc mWarn, _ ) - } - } - ) - ) = isJust mDoc || isJust mWarn + ( RnExportD + { rnExpDExpD = + ExportD + { expDMbDoc = + (Documentation mDoc mWarn, _) + } + } + ) + ) = isJust mDoc || isJust mWarn has_doc (ExportNoDecl _ _) = False has_doc (ExportModule _) = False has_doc _ = True no_doc_at_all = not (any has_doc exports) - description | isNoHtml doc = doc - | otherwise = divDescription $ sectionName << "Description" +++ doc - where doc = docSection Nothing pkg qual (ifaceRnDoc iface) + description + | isNoHtml doc = doc + | otherwise = divDescription $ sectionName << "Description" +++ doc + where + doc = docSection Nothing pkg qual (ifaceRnDoc iface) - -- omit the synopsis if there are no documentation annotations at all + -- omit the synopsis if there are no documentation annotations at all synopsis | no_doc_at_all = noHtml - | otherwise - = divSynopsis $ - collapseDetails "syn" DetailsClosed ( - thesummary << "Synopsis" +++ - shortDeclList ( - mapMaybe (processExport True linksInfo unicode pkg qual) exports - ) ! collapseToggle "syn" "" - ) - - -- if the documentation doesn't begin with a section header, then - -- add one ("Documentation"). - maybe_doc_hdr - = case exports of - [] -> noHtml - ExportGroup {} : _ -> noHtml - _ -> h1 << "Documentation" + | otherwise = + divSynopsis $ + collapseDetails + "syn" + DetailsClosed + ( thesummary + << "Synopsis" + +++ shortDeclList + ( mapMaybe (processExport True linksInfo unicode pkg qual) exports + ) + ! collapseToggle "syn" "" + ) + + -- if the documentation doesn't begin with a section header, then + -- add one ("Documentation"). + maybe_doc_hdr = + case exports of + [] -> noHtml + ExportGroup{} : _ -> noHtml + _ -> h1 << "Documentation" bdy = foldr (+++) noHtml $ @@ -794,106 +1030,131 @@ ifaceToHtml maybe_source_url maybe_wiki_url iface unicode pkg qual linksInfo = (maybe_source_url, maybe_wiki_url) - -ppModuleContents :: Maybe Package -- ^ This package - -> Qualification - -> [ExportItem DocNameI] - -> Bool -- ^ Orphans sections - -> Html +ppModuleContents + :: Maybe Package + -- ^ This package + -> Qualification + -> [ExportItem DocNameI] + -> Bool + -- ^ Orphans sections + -> Html ppModuleContents pkg qual exports orphan - | null sections && not orphan = noHtml - | otherwise = contentsDiv - where - contentsDiv = divTableOfContents << (divContentsList << ( - (sectionName << "Contents") ! [ strAttr "onclick" "window.scrollTo(0,0)" ] +++ - unordList (sections ++ orphanSection))) - - (sections, _leftovers{-should be []-}) = process 0 exports - orphanSection - | orphan = [ linkedAnchor "section.orphans" << "Orphan instances" ] - | otherwise = [] - - process :: Int -> [ExportItem DocNameI] -> ([Html],[ExportItem DocNameI]) - process _ [] = ([], []) - process n items@(ExportGroup lev id0 doc : rest) - | lev <= n = ( [], items ) - | otherwise = ( html:secs, rest2 ) - where - html = linkedAnchor (groupId id0) - << docToHtmlNoAnchors (Just id0) pkg qual (mkMeta doc) +++ mk_subsections ssecs - (ssecs, rest1) = process lev rest - (secs, rest2) = process n rest1 - process n (_ : rest) = process n rest + | null sections && not orphan = noHtml + | otherwise = contentsDiv + where + contentsDiv = + divTableOfContents + << ( divContentsList + << ( (sectionName << "Contents") + ! [strAttr "onclick" "window.scrollTo(0,0)"] + +++ unordList (sections ++ orphanSection) + ) + ) + + (sections, _leftovers {-should be []-}) = process 0 exports + orphanSection + | orphan = [linkedAnchor "section.orphans" << "Orphan instances"] + | otherwise = [] + + process :: Int -> [ExportItem DocNameI] -> ([Html], [ExportItem DocNameI]) + process _ [] = ([], []) + process n items@(ExportGroup lev id0 doc : rest) + | lev <= n = ([], items) + | otherwise = (html : secs, rest2) + where + html = + linkedAnchor (groupId id0) + << docToHtmlNoAnchors (Just id0) pkg qual (mkMeta doc) + +++ mk_subsections ssecs + (ssecs, rest1) = process lev rest + (secs, rest2) = process n rest1 + process n (_ : rest) = process n rest - mk_subsections [] = noHtml - mk_subsections ss = unordList ss + mk_subsections [] = noHtml + mk_subsections ss = unordList ss -- we need to assign a unique id to each section heading so we can hyperlink -- them from the contents: numberSectionHeadings :: [ExportItem DocNameI] -> [ExportItem DocNameI] numberSectionHeadings = go 1 - where go :: Int -> [ExportItem DocNameI] -> [ExportItem DocNameI] - go _ [] = [] - go n (ExportGroup lev _ doc : es) - = case collectAnchors doc of - [] -> ExportGroup lev (show n) doc : go (n+1) es - (a:_) -> ExportGroup lev a doc : go (n+1) es - go n (other:es) - = other : go n es - - collectAnchors :: DocH (Wrap (ModuleName, OccName)) (Wrap DocName) -> [String] - collectAnchors (DocAppend a b) = collectAnchors a ++ collectAnchors b - collectAnchors (DocAName a) = [a] - collectAnchors _ = [] - -processExport :: Bool -> LinksInfo -> Bool -> Maybe Package -> Qualification - -> ExportItem DocNameI -> Maybe Html -processExport _ _ _ _ _ - ( ExportDecl + where + go :: Int -> [ExportItem DocNameI] -> [ExportItem DocNameI] + go _ [] = [] + go n (ExportGroup lev _ doc : es) = + case collectAnchors doc of + [] -> ExportGroup lev (show n) doc : go (n + 1) es + (a : _) -> ExportGroup lev a doc : go (n + 1) es + go n (other : es) = + other : go n es + + collectAnchors :: DocH (Wrap (ModuleName, OccName)) (Wrap DocName) -> [String] + collectAnchors (DocAppend a b) = collectAnchors a ++ collectAnchors b + collectAnchors (DocAName a) = [a] + collectAnchors _ = [] + +processExport + :: Bool + -> LinksInfo + -> Bool + -> Maybe Package + -> Qualification + -> ExportItem DocNameI + -> Maybe Html +processExport + _ + _ + _ + _ + _ + ( ExportDecl ( RnExportD - { rnExpDExpD = + { rnExpDExpD = ExportD - { expDDecl = L _ (InstD {}) - } - } - ) - ) - = Nothing -- Hide empty instances -processExport summary links unicode pkg qual - ( ExportDecl + { expDDecl = L _ (InstD{}) + } + } + ) + ) = + Nothing -- Hide empty instances +processExport + summary + links + unicode + pkg + qual + ( ExportDecl ( RnExportD - { rnExpDExpD = + { rnExpDExpD = ExportD decl pats doc subdocs insts fixities splice - } - ) - ) - = processDecl summary $ ppDecl summary links decl pats doc insts fixities subdocs splice unicode pkg qual -processExport summary _ _ pkg qual (ExportGroup lev id0 doc) - = nothingIf summary $ groupHeading lev id0 << docToHtmlNoAnchors (Just id0) pkg qual (mkMeta doc) -processExport summary _ _ _ qual (ExportNoDecl y []) - = processDeclOneLiner summary $ ppDocName qual Prefix True y -processExport summary _ _ _ qual (ExportNoDecl y subs) - = processDeclOneLiner summary $ - ppDocName qual Prefix True y + } + ) + ) = + processDecl summary $ ppDecl summary links decl pats doc insts fixities subdocs splice unicode pkg qual +processExport summary _ _ pkg qual (ExportGroup lev id0 doc) = + nothingIf summary $ groupHeading lev id0 << docToHtmlNoAnchors (Just id0) pkg qual (mkMeta doc) +processExport summary _ _ _ qual (ExportNoDecl y []) = + processDeclOneLiner summary $ ppDocName qual Prefix True y +processExport summary _ _ _ qual (ExportNoDecl y subs) = + processDeclOneLiner summary $ + ppDocName qual Prefix True y +++ parenList (map (ppDocName qual Prefix True) subs) -processExport summary _ _ pkg qual (ExportDoc doc) - = nothingIf summary $ docSection_ Nothing pkg qual doc -processExport summary _ _ _ _ (ExportModule mdl) - = processDeclOneLiner summary $ toHtml "module" <+> ppModule mdl - +processExport summary _ _ pkg qual (ExportDoc doc) = + nothingIf summary $ docSection_ Nothing pkg qual doc +processExport summary _ _ _ _ (ExportModule mdl) = + processDeclOneLiner summary $ toHtml "module" <+> ppModule mdl nothingIf :: Bool -> a -> Maybe a nothingIf True _ = Nothing nothingIf False a = Just a - processDecl :: Bool -> Html -> Maybe Html processDecl True = Just processDecl False = Just . divTopDecl trim :: String -> String trim = f . f - where f = reverse . dropWhile isSpace + where + f = reverse . dropWhile isSpace processDeclOneLiner :: Bool -> Html -> Maybe Html processDeclOneLiner True = Just @@ -901,11 +1162,12 @@ processDeclOneLiner False = Just . divTopDecl . declElem groupHeading :: Int -> String -> Html -> Html groupHeading lev id0 = linkedAnchor grpId . groupTag lev ! [identifier grpId] - where grpId = groupId id0 + where + grpId = groupId id0 groupTag :: Int -> Html -> Html groupTag lev - | lev == 1 = h1 - | lev == 2 = h2 - | lev == 3 = h3 + | lev == 1 = h1 + | lev == 2 = h2 + | lev == 3 = h3 | otherwise = h4 diff --git a/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs b/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs index 30ec50fdcb..81f9f1e587 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs @@ -1,11 +1,14 @@ -{-# LANGUAGE TransformListComp #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE Rank2Types #-} -{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE LambdaCase #-} +{-# LANGUAGE Rank2Types #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE TransformListComp #-} +{-# LANGUAGE TypeFamilies #-} + +----------------------------------------------------------------------------- ----------------------------------------------------------------------------- + -- | -- Module : Haddock.Backends.Html.Decl -- Copyright : (c) Simon Marlow 2003-2006, @@ -16,144 +19,300 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------ -module Haddock.Backends.Xhtml.Decl ( - ppDecl, - ppOrphanInstances, -) where +module Haddock.Backends.Xhtml.Decl + ( ppDecl + , ppOrphanInstances + ) where import Haddock.Backends.Xhtml.DocMarkup import Haddock.Backends.Xhtml.Layout import Haddock.Backends.Xhtml.Names import Haddock.Backends.Xhtml.Types import Haddock.Backends.Xhtml.Utils +import Haddock.Doc (combineDocumentation) import Haddock.GhcUtils import Haddock.Types -import Haddock.Doc (combineDocumentation) -import Data.Foldable ( toList ) -import Data.List ( intersperse, sort ) -import Data.List.NonEmpty ( NonEmpty (..) ) +import Data.Foldable (toList) +import Data.List (intersperse, sort) +import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.Map as Map -import Data.Maybe -import Text.XHtml hiding ( name, title, p, quote ) +import Data.Maybe +import Text.XHtml hiding (name, p, quote, title) -import GHC.Core.Type ( Specificity(..) ) -import GHC hiding (LexicalFixity(..), fromMaybeContext) +import GHC hiding (LexicalFixity (..), fromMaybeContext) +import GHC.Core.Type (Specificity (..)) +import GHC.Data.BooleanFormula import GHC.Exts hiding (toList) import GHC.Types.Name -import GHC.Data.BooleanFormula -import GHC.Types.Name.Reader ( rdrNameOcc ) +import GHC.Types.Name.Reader (rdrNameOcc) -- | Pretty print a declaration -ppDecl :: Bool -- ^ print summary info only - -> LinksInfo -- ^ link information - -> LHsDecl DocNameI -- ^ declaration to print - -> [(HsDecl DocNameI, DocForDecl DocName)] -- ^ relevant pattern synonyms - -> DocForDecl DocName -- ^ documentation for this decl - -> [DocInstance DocNameI] -- ^ relevant instances - -> [(DocName, Fixity)] -- ^ relevant fixities - -> [(DocName, DocForDecl DocName)] -- ^ documentation for all decls - -> Splice - -> Unicode -- ^ unicode output - -> Maybe Package - -> Qualification - -> Html +ppDecl + :: Bool + -- ^ print summary info only + -> LinksInfo + -- ^ link information + -> LHsDecl DocNameI + -- ^ declaration to print + -> [(HsDecl DocNameI, DocForDecl DocName)] + -- ^ relevant pattern synonyms + -> DocForDecl DocName + -- ^ documentation for this decl + -> [DocInstance DocNameI] + -- ^ relevant instances + -> [(DocName, Fixity)] + -- ^ relevant fixities + -> [(DocName, DocForDecl DocName)] + -- ^ documentation for all decls + -> Splice + -> Unicode + -- ^ unicode output + -> Maybe Package + -> Qualification + -> Html ppDecl summ links (L loc decl) pats (mbDoc, fnArgsDoc) instances fixities subdocs splice unicode pkg qual = case decl of - TyClD _ (FamDecl _ d) -> ppFamDecl summ False links instances fixities (locA loc) mbDoc d splice unicode pkg qual - TyClD _ d@(DataDecl {}) -> ppDataDecl summ links instances fixities subdocs (locA loc) mbDoc d pats splice unicode pkg qual - TyClD _ d@(SynDecl {}) -> ppTySyn summ links fixities (locA loc) (mbDoc, fnArgsDoc) d splice unicode pkg qual - TyClD _ d@(ClassDecl {}) -> ppClassDecl summ links instances fixities (locA loc) mbDoc subdocs d splice unicode pkg qual - SigD _ (TypeSig _ lnames lty) -> ppLFunSig summ links (locA loc) (mbDoc, fnArgsDoc) lnames - (dropWildCards lty) fixities splice unicode pkg qual - SigD _ (PatSynSig _ lnames lty) -> ppLPatSig summ links (locA loc) (mbDoc, fnArgsDoc) lnames - lty fixities splice unicode pkg qual - ForD _ d -> ppFor summ links (locA loc) (mbDoc, fnArgsDoc) d fixities splice unicode pkg qual - InstD _ _ -> noHtml - DerivD _ _ -> noHtml - _ -> error "declaration not supported by ppDecl" - - -ppLFunSig :: Bool -> LinksInfo -> SrcSpan -> DocForDecl DocName -> - [LocatedN DocName] -> LHsSigType DocNameI -> [(DocName, Fixity)] -> - Splice -> Unicode -> Maybe Package -> Qualification -> Html + TyClD _ (FamDecl _ d) -> ppFamDecl summ False links instances fixities (locA loc) mbDoc d splice unicode pkg qual + TyClD _ d@(DataDecl{}) -> ppDataDecl summ links instances fixities subdocs (locA loc) mbDoc d pats splice unicode pkg qual + TyClD _ d@(SynDecl{}) -> ppTySyn summ links fixities (locA loc) (mbDoc, fnArgsDoc) d splice unicode pkg qual + TyClD _ d@(ClassDecl{}) -> ppClassDecl summ links instances fixities (locA loc) mbDoc subdocs d splice unicode pkg qual + SigD _ (TypeSig _ lnames lty) -> + ppLFunSig + summ + links + (locA loc) + (mbDoc, fnArgsDoc) + lnames + (dropWildCards lty) + fixities + splice + unicode + pkg + qual + SigD _ (PatSynSig _ lnames lty) -> + ppLPatSig + summ + links + (locA loc) + (mbDoc, fnArgsDoc) + lnames + lty + fixities + splice + unicode + pkg + qual + ForD _ d -> ppFor summ links (locA loc) (mbDoc, fnArgsDoc) d fixities splice unicode pkg qual + InstD _ _ -> noHtml + DerivD _ _ -> noHtml + _ -> error "declaration not supported by ppDecl" + +ppLFunSig + :: Bool + -> LinksInfo + -> SrcSpan + -> DocForDecl DocName + -> [LocatedN DocName] + -> LHsSigType DocNameI + -> [(DocName, Fixity)] + -> Splice + -> Unicode + -> Maybe Package + -> Qualification + -> Html ppLFunSig summary links loc doc lnames lty fixities splice unicode pkg qual = - ppFunSig summary links loc noHtml doc (map unLoc lnames) lty fixities - splice unicode pkg qual - -ppFunSig :: Bool -> LinksInfo -> SrcSpan -> Html -> DocForDecl DocName -> - [DocName] -> LHsSigType DocNameI -> [(DocName, Fixity)] -> - Splice -> Unicode -> Maybe Package -> Qualification -> Html + ppFunSig + summary + links + loc + noHtml + doc + (map unLoc lnames) + lty + fixities + splice + unicode + pkg + qual + +ppFunSig + :: Bool + -> LinksInfo + -> SrcSpan + -> Html + -> DocForDecl DocName + -> [DocName] + -> LHsSigType DocNameI + -> [(DocName, Fixity)] + -> Splice + -> Unicode + -> Maybe Package + -> Qualification + -> Html ppFunSig summary links loc leader doc docnames typ fixities splice unicode pkg qual = - ppSigLike summary links loc leader doc docnames fixities (unLoc typ, pp_typ) - splice unicode pkg qual HideEmptyContexts + ppSigLike + summary + links + loc + leader + doc + docnames + fixities + (unLoc typ, pp_typ) + splice + unicode + pkg + qual + HideEmptyContexts where pp_typ = ppLSigType unicode qual HideEmptyContexts typ -- | Pretty print a pattern synonym -ppLPatSig :: Bool -> LinksInfo -> SrcSpan -> DocForDecl DocName - -> [LocatedN DocName] -- ^ names of patterns in declaration - -> LHsSigType DocNameI -- ^ type of patterns in declaration - -> [(DocName, Fixity)] - -> Splice -> Unicode -> Maybe Package -> Qualification -> Html +ppLPatSig + :: Bool + -> LinksInfo + -> SrcSpan + -> DocForDecl DocName + -> [LocatedN DocName] + -- ^ names of patterns in declaration + -> LHsSigType DocNameI + -- ^ type of patterns in declaration + -> [(DocName, Fixity)] + -> Splice + -> Unicode + -> Maybe Package + -> Qualification + -> Html ppLPatSig summary links loc doc lnames typ fixities splice unicode pkg qual = - ppSigLike summary links loc (keyword "pattern") doc (map unLoc lnames) fixities - (unLoc typ, pp_typ) splice unicode pkg qual (patSigContext typ) + ppSigLike + summary + links + loc + (keyword "pattern") + doc + (map unLoc lnames) + fixities + (unLoc typ, pp_typ) + splice + unicode + pkg + qual + (patSigContext typ) where pp_typ = ppPatSigType unicode qual typ - -ppSigLike :: Bool -> LinksInfo -> SrcSpan -> Html -> DocForDecl DocName -> - [DocName] -> [(DocName, Fixity)] -> (HsSigType DocNameI, Html) -> - Splice -> Unicode -> Maybe Package -> Qualification -> HideEmptyContexts -> Html -ppSigLike summary links loc leader doc docnames fixities (typ, pp_typ) - splice unicode pkg qual emptyCtxts = - ppTypeOrFunSig summary links loc docnames typ doc - ( addFixities $ leader <+> ppTypeSig summary occnames pp_typ unicode - , (leader <+>) . addFixities . concatHtml . punctuate comma $ map (ppBinder False) occnames - , dcolon unicode - ) - splice unicode pkg qual emptyCtxts - where - occnames = map (nameOccName . getName) docnames - addFixities html - | summary = html - | otherwise = html <+> ppFixities fixities qual - - -ppTypeOrFunSig :: Bool -> LinksInfo -> SrcSpan -> [DocName] -> HsSigType DocNameI - -> DocForDecl DocName -> (Html, Html, Html) - -> Splice -> Unicode -> Maybe Package -> Qualification - -> HideEmptyContexts -> Html -ppTypeOrFunSig summary links loc docnames typ (doc, argDocs) (pref1, pref2, sep) - splice unicode pkg qual emptyCtxts - | summary = pref1 - | Map.null argDocs = topDeclElem links loc splice docnames pref1 +++ docSection curname pkg qual doc - | otherwise = topDeclElem links loc splice docnames pref2 - +++ subArguments pkg qual (ppSubSigLike unicode qual typ argDocs [] sep emptyCtxts) - +++ docSection curname pkg qual doc - where - curname = getName <$> listToMaybe docnames - +ppSigLike + :: Bool + -> LinksInfo + -> SrcSpan + -> Html + -> DocForDecl DocName + -> [DocName] + -> [(DocName, Fixity)] + -> (HsSigType DocNameI, Html) + -> Splice + -> Unicode + -> Maybe Package + -> Qualification + -> HideEmptyContexts + -> Html +ppSigLike + summary + links + loc + leader + doc + docnames + fixities + (typ, pp_typ) + splice + unicode + pkg + qual + emptyCtxts = + ppTypeOrFunSig + summary + links + loc + docnames + typ + doc + ( addFixities $ leader <+> ppTypeSig summary occnames pp_typ unicode + , (leader <+>) . addFixities . concatHtml . punctuate comma $ map (ppBinder False) occnames + , dcolon unicode + ) + splice + unicode + pkg + qual + emptyCtxts + where + occnames = map (nameOccName . getName) docnames + addFixities html + | summary = html + | otherwise = html <+> ppFixities fixities qual + +ppTypeOrFunSig + :: Bool + -> LinksInfo + -> SrcSpan + -> [DocName] + -> HsSigType DocNameI + -> DocForDecl DocName + -> (Html, Html, Html) + -> Splice + -> Unicode + -> Maybe Package + -> Qualification + -> HideEmptyContexts + -> Html +ppTypeOrFunSig + summary + links + loc + docnames + typ + (doc, argDocs) + (pref1, pref2, sep) + splice + unicode + pkg + qual + emptyCtxts + | summary = pref1 + | Map.null argDocs = topDeclElem links loc splice docnames pref1 +++ docSection curname pkg qual doc + | otherwise = + topDeclElem links loc splice docnames pref2 + +++ subArguments pkg qual (ppSubSigLike unicode qual typ argDocs [] sep emptyCtxts) + +++ docSection curname pkg qual doc + where + curname = getName <$> listToMaybe docnames -- | This splits up a type signature along @->@ and adds docs (when they exist) -- to the arguments. -- -- If one passes in a list of the available subdocs, any top-level `HsRecTy` -- found will be expanded out into their fields. -ppSubSigLike :: Unicode -> Qualification - -> HsSigType DocNameI -- ^ type signature - -> FnArgsDoc DocName -- ^ docs to add - -> [(DocName, DocForDecl DocName)] -- ^ all subdocs (useful when - -- we expand an `HsRecTy`) - -> Html -> HideEmptyContexts -> [SubDecl] +ppSubSigLike + :: Unicode + -> Qualification + -> HsSigType DocNameI + -- ^ type signature + -> FnArgsDoc DocName + -- ^ docs to add + -> [(DocName, DocForDecl DocName)] + -- ^ all subdocs (useful when + -- we expand an `HsRecTy`) + -> Html + -> HideEmptyContexts + -> [SubDecl] ppSubSigLike unicode qual typ argDocs subdocs sep emptyCtxts = do_sig_args 0 sep typ where do_sig_args :: Int -> Html -> HsSigType DocNameI -> [SubDecl] - do_sig_args n leader (HsSig { sig_bndrs = outer_bndrs, sig_body = ltype }) = + do_sig_args n leader (HsSig{sig_bndrs = outer_bndrs, sig_body = ltype}) = case outer_bndrs of HsOuterExplicit{hso_bndrs = bndrs} -> do_largs n (leader' bndrs) ltype - HsOuterImplicit{} -> do_largs n leader ltype + HsOuterImplicit{} -> do_largs n leader ltype where leader' bndrs = leader <+> ppForAllPart unicode qual (mkHsForAllInvisTeleI bndrs) @@ -163,32 +322,27 @@ ppSubSigLike unicode qual typ argDocs subdocs sep emptyCtxts = do_sig_args 0 sep do_largs n leader (L _ t) = do_args n leader t do_args :: Int -> Html -> HsType DocNameI -> [SubDecl] - do_args n leader (HsForAllTy _ tele ltype) - = do_largs n leader' ltype + do_args n leader (HsForAllTy _ tele ltype) = + do_largs n leader' ltype where leader' = leader <+> ppForAllPart unicode qual tele - do_args n leader (HsQualTy _ lctxt ltype) - | null (unLoc lctxt) - = do_largs n leader ltype - | otherwise - = (leader <+> ppLContextNoArrow lctxt unicode qual emptyCtxts, Nothing, []) - : do_largs n (darrow unicode) ltype - - do_args n leader (HsFunTy _ _w (L _ (HsRecTy _ fields)) r) - = [ (ldr <+> html, mdoc, subs) - | (L _ field, ldr) <- zip fields (leader <+> gadtOpen : repeat gadtComma) - , let (html, mdoc, subs) = ppSideBySideField subdocs unicode qual field - ] - ++ do_largs (n+1) (gadtEnd <+> arrow unicode) r - - do_args n leader (HsFunTy _ _w lt r) - = (leader <+> ppLFunLhType unicode qual emptyCtxts lt, argDoc n, []) - : do_largs (n+1) (arrow unicode) r - - do_args n leader t - = [(leader <+> ppType unicode qual emptyCtxts t, argDoc n, [])] - + | null (unLoc lctxt) = + do_largs n leader ltype + | otherwise = + (leader <+> ppLContextNoArrow lctxt unicode qual emptyCtxts, Nothing, []) + : do_largs n (darrow unicode) ltype + do_args n leader (HsFunTy _ _w (L _ (HsRecTy _ fields)) r) = + [ (ldr <+> html, mdoc, subs) + | (L _ field, ldr) <- zip fields (leader <+> gadtOpen : repeat gadtComma) + , let (html, mdoc, subs) = ppSideBySideField subdocs unicode qual field + ] + ++ do_largs (n + 1) (gadtEnd <+> arrow unicode) r + do_args n leader (HsFunTy _ _w lt r) = + (leader <+> ppLFunLhType unicode qual emptyCtxts lt, argDoc n, []) + : do_largs (n + 1) (arrow unicode) r + do_args n leader t = + [(leader <+> ppType unicode qual emptyCtxts t, argDoc n, [])] -- FIXME: this should be done more elegantly -- @@ -199,195 +353,309 @@ ppSubSigLike unicode qual typ argDocs subdocs sep emptyCtxts = do_sig_args 0 sep gadtEnd = concatHtml (replicate (if unicode then 2 else 3) spaceHtml) <> toHtml "}" gadtOpen = toHtml "{" - ppFixities :: [(DocName, Fixity)] -> Qualification -> Html ppFixities [] _ = noHtml ppFixities fs qual = foldr1 (+++) (map ppFix uniq_fs) +++ rightEdge where - ppFix (ns, p, d) = thespan ! [theclass "fixity"] << - (toHtml d <+> toHtml (show p) <+> ppNames ns) + ppFix (ns, p, d) = + thespan + ! [theclass "fixity"] + << (toHtml d <+> toHtml (show p) <+> ppNames ns) ppDir InfixR = "infixr" ppDir InfixL = "infixl" ppDir InfixN = "infix" ppNames = case fs of - _:[] -> const noHtml -- Don't display names for fixities on single names - _ -> concatHtml . intersperse (stringToHtml ", ") . map (ppDocName qual Infix False) - - uniq_fs = [ (n, the p, the d') | (n, Fixity _ p d) <- fs - , let d' = ppDir d - , then group by Down (p,d') using groupWith ] + _ : [] -> const noHtml -- Don't display names for fixities on single names + _ -> concatHtml . intersperse (stringToHtml ", ") . map (ppDocName qual Infix False) + + uniq_fs = + [ (n, the p, the d') + | (n, Fixity _ p d) <- fs + , let d' = ppDir d + , then group by + Down (p, d') + using + groupWith + ] rightEdge = thespan ! [theclass "rightedge"] << noHtml - -- | Pretty-print type variables. -ppTyVars :: RenderableBndrFlag flag => - Unicode -> Qualification -> [LHsTyVarBndr flag DocNameI] -> [Html] +ppTyVars + :: RenderableBndrFlag flag + => Unicode + -> Qualification + -> [LHsTyVarBndr flag DocNameI] + -> [Html] ppTyVars unicode qual tvs = map (ppHsTyVarBndr unicode qual . unLoc) tvs - -ppFor :: Bool -> LinksInfo -> SrcSpan -> DocForDecl DocName - -> ForeignDecl DocNameI -> [(DocName, Fixity)] - -> Splice -> Unicode -> Maybe Package -> Qualification -> Html -ppFor summary links loc doc (ForeignImport _ (L _ name) typ _) fixities - splice unicode pkg qual - = ppFunSig summary links loc noHtml doc [name] typ fixities splice unicode pkg qual +ppFor + :: Bool + -> LinksInfo + -> SrcSpan + -> DocForDecl DocName + -> ForeignDecl DocNameI + -> [(DocName, Fixity)] + -> Splice + -> Unicode + -> Maybe Package + -> Qualification + -> Html +ppFor + summary + links + loc + doc + (ForeignImport _ (L _ name) typ _) + fixities + splice + unicode + pkg + qual = + ppFunSig summary links loc noHtml doc [name] typ fixities splice unicode pkg qual ppFor _ _ _ _ _ _ _ _ _ _ = error "ppFor" - -- we skip type patterns for now -ppTySyn :: Bool -> LinksInfo -> [(DocName, Fixity)] -> SrcSpan - -> DocForDecl DocName -> TyClDecl DocNameI - -> Splice -> Unicode -> Maybe Package -> Qualification -> Html -ppTySyn summary links fixities loc doc (SynDecl { tcdLName = L _ name, tcdTyVars = ltyvars - , tcdRhs = ltype }) - splice unicode pkg qual - = ppTypeOrFunSig summary links loc [name] sig_type doc - (full <+> fixs, hdr <+> fixs, spaceHtml +++ equals) - splice unicode pkg qual ShowEmptyToplevelContexts - where - sig_type = mkHsImplicitSigTypeI ltype - hdr = hsep ([keyword "type", ppBinder summary occ] - ++ ppTyVars unicode qual (hsQTvExplicit ltyvars)) - full = hdr <+> equals <+> ppPatSigType unicode qual (noLocA sig_type) - occ = nameOccName . getName $ name - fixs - | summary = noHtml - | otherwise = ppFixities fixities qual +ppTySyn + :: Bool + -> LinksInfo + -> [(DocName, Fixity)] + -> SrcSpan + -> DocForDecl DocName + -> TyClDecl DocNameI + -> Splice + -> Unicode + -> Maybe Package + -> Qualification + -> Html +ppTySyn + summary + links + fixities + loc + doc + ( SynDecl + { tcdLName = L _ name + , tcdTyVars = ltyvars + , tcdRhs = ltype + } + ) + splice + unicode + pkg + qual = + ppTypeOrFunSig + summary + links + loc + [name] + sig_type + doc + (full <+> fixs, hdr <+> fixs, spaceHtml +++ equals) + splice + unicode + pkg + qual + ShowEmptyToplevelContexts + where + sig_type = mkHsImplicitSigTypeI ltype + hdr = + hsep + ( [keyword "type", ppBinder summary occ] + ++ ppTyVars unicode qual (hsQTvExplicit ltyvars) + ) + full = hdr <+> equals <+> ppPatSigType unicode qual (noLocA sig_type) + occ = nameOccName . getName $ name + fixs + | summary = noHtml + | otherwise = ppFixities fixities qual ppTySyn _ _ _ _ _ _ _ _ _ _ = error "declaration not supported by ppTySyn" - ppTypeSig :: Bool -> [OccName] -> Html -> Unicode -> Html ppTypeSig summary nms pp_ty unicode = concatHtml htmlNames <+> dcolon unicode <+> pp_ty where htmlNames = intersperse (stringToHtml ", ") $ map (ppBinder summary) nms -ppSimpleSig :: LinksInfo -> Splice -> Unicode -> Qualification -> HideEmptyContexts -> SrcSpan - -> [DocName] -> HsSigType DocNameI - -> Html +ppSimpleSig + :: LinksInfo + -> Splice + -> Unicode + -> Qualification + -> HideEmptyContexts + -> SrcSpan + -> [DocName] + -> HsSigType DocNameI + -> Html ppSimpleSig links splice unicode qual emptyCtxts loc names typ = - topDeclElem' names $ ppTypeSig True occNames ppTyp unicode + topDeclElem' names $ ppTypeSig True occNames ppTyp unicode where topDeclElem' = topDeclElem links loc splice ppTyp = ppSigType unicode qual emptyCtxts typ occNames = map getOccName names - -------------------------------------------------------------------------------- + -- * Type families --------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- -- | Print a data\/type family declaration -ppFamDecl :: Bool -- ^ is a summary - -> Bool -- ^ is an associated type - -> LinksInfo - -> [DocInstance DocNameI] -- ^ relevant instances - -> [(DocName, Fixity)] -- ^ relevant fixities - -> SrcSpan - -> Documentation DocName -- ^ this decl's documentation - -> FamilyDecl DocNameI -- ^ this decl - -> Splice -> Unicode -> Maybe Package -> Qualification -> Html +ppFamDecl + :: Bool + -- ^ is a summary + -> Bool + -- ^ is an associated type + -> LinksInfo + -> [DocInstance DocNameI] + -- ^ relevant instances + -> [(DocName, Fixity)] + -- ^ relevant fixities + -> SrcSpan + -> Documentation DocName + -- ^ this decl's documentation + -> FamilyDecl DocNameI + -- ^ this decl + -> Splice + -> Unicode + -> Maybe Package + -> Qualification + -> Html ppFamDecl summary associated links instances fixities loc doc decl splice unicode pkg qual - | summary = ppFamHeader True associated decl unicode qual + | summary = ppFamHeader True associated decl unicode qual | otherwise = header_ +++ docSection curname pkg qual doc +++ instancesBit - where docname = unLoc $ fdLName decl curname = Just $ getName docname - header_ = topDeclElem links loc splice [docname] $ - ppFamHeader summary associated decl unicode qual <+> ppFixities fixities qual + header_ = + topDeclElem links loc splice [docname] $ + ppFamHeader summary associated decl unicode qual <+> ppFixities fixities qual instancesBit - | FamilyDecl { fdInfo = ClosedTypeFamily mb_eqns } <- decl - , not summary - = subEquations pkg qual $ map (ppFamDeclEqn . unLoc) $ fromMaybe [] mb_eqns - - | otherwise - = ppInstances links (OriginFamily docname) instances splice unicode pkg qual + | FamilyDecl{fdInfo = ClosedTypeFamily mb_eqns} <- decl + , not summary = + subEquations pkg qual $ map (ppFamDeclEqn . unLoc) $ fromMaybe [] mb_eqns + | otherwise = + ppInstances links (OriginFamily docname) instances splice unicode pkg qual -- Individual equation of a closed type family ppFamDeclEqn :: TyFamInstEqn DocNameI -> SubDecl - ppFamDeclEqn (FamEqn { feqn_tycon = L _ n - , feqn_rhs = rhs - , feqn_pats = ts }) - = ( ppAppNameTypeArgs n ts unicode qual - <+> equals <+> ppType unicode qual HideEmptyContexts (unLoc rhs) + ppFamDeclEqn + ( FamEqn + { feqn_tycon = L _ n + , feqn_rhs = rhs + , feqn_pats = ts + } + ) = + ( ppAppNameTypeArgs n ts unicode qual + <+> equals + <+> ppType unicode qual HideEmptyContexts (unLoc rhs) , Nothing , [] ) -- | Print the LHS of a type\/data family declaration -ppFamHeader :: Bool -- ^ is a summary - -> Bool -- ^ is an associated type - -> FamilyDecl DocNameI -- ^ family declaration - -> Unicode -> Qualification -> Html -ppFamHeader summary associated (FamilyDecl { fdInfo = info - , fdResultSig = L _ result - , fdInjectivityAnn = injectivity - , fdLName = L _ name - , fdTyVars = tvs }) - unicode qual = - hsep [ ppFamilyLeader associated info - , ppAppDocNameTyVarBndrs summary unicode qual name (hsq_explicit tvs) - , ppResultSig result unicode qual - , injAnn - , whereBit - ] - where - whereBit = case info of - ClosedTypeFamily _ -> keyword "where ..." - _ -> noHtml - - injAnn = case injectivity of - Nothing -> noHtml - Just (L _ (InjectivityAnn _ lhs rhs)) -> hsep ( keyword "|" - : ppLDocName qual Raw lhs - : arrow unicode - : map (ppLDocName qual Raw) rhs) - Just _ -> error "ppFamHeader:XInjectivityAnn" +ppFamHeader + :: Bool + -- ^ is a summary + -> Bool + -- ^ is an associated type + -> FamilyDecl DocNameI + -- ^ family declaration + -> Unicode + -> Qualification + -> Html +ppFamHeader + summary + associated + ( FamilyDecl + { fdInfo = info + , fdResultSig = L _ result + , fdInjectivityAnn = injectivity + , fdLName = L _ name + , fdTyVars = tvs + } + ) + unicode + qual = + hsep + [ ppFamilyLeader associated info + , ppAppDocNameTyVarBndrs summary unicode qual name (hsq_explicit tvs) + , ppResultSig result unicode qual + , injAnn + , whereBit + ] + where + whereBit = case info of + ClosedTypeFamily _ -> keyword "where ..." + _ -> noHtml + + injAnn = case injectivity of + Nothing -> noHtml + Just (L _ (InjectivityAnn _ lhs rhs)) -> + hsep + ( keyword "|" + : ppLDocName qual Raw lhs + : arrow unicode + : map (ppLDocName qual Raw) rhs + ) + Just _ -> error "ppFamHeader:XInjectivityAnn" -- | Print the keywords that begin the family declaration ppFamilyLeader :: Bool -> FamilyInfo DocNameI -> Html ppFamilyLeader assoc info = keyword (typ ++ if assoc then "" else " family") where typ = case info of - OpenTypeFamily -> "type" - ClosedTypeFamily _ -> "type" - DataFamily -> "data" + OpenTypeFamily -> "type" + ClosedTypeFamily _ -> "type" + DataFamily -> "data" -- | Print the signature attached to a family ppResultSig :: FamilyResultSig DocNameI -> Unicode -> Qualification -> Html ppResultSig result unicode qual = case result of - NoSig _ -> noHtml - KindSig _ kind -> dcolon unicode <+> ppLKind unicode qual kind - TyVarSig _ (L _ bndr) -> equals <+> ppHsTyVarBndr unicode qual bndr - + NoSig _ -> noHtml + KindSig _ kind -> dcolon unicode <+> ppLKind unicode qual kind + TyVarSig _ (L _ bndr) -> equals <+> ppHsTyVarBndr unicode qual bndr -------------------------------------------------------------------------------- + -- * Associated Types --------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- -ppAssocType :: Bool -> LinksInfo -> DocForDecl DocName -> LFamilyDecl DocNameI - -> [(DocName, Fixity)] -> Splice -> Unicode -> Maybe Package - -> Qualification -> Html +ppAssocType + :: Bool + -> LinksInfo + -> DocForDecl DocName + -> LFamilyDecl DocNameI + -> [(DocName, Fixity)] + -> Splice + -> Unicode + -> Maybe Package + -> Qualification + -> Html ppAssocType summ links doc (L loc decl) fixities splice unicode pkg qual = - ppFamDecl summ True links [] fixities loc (fst doc) decl splice unicode pkg qual - + ppFamDecl summ True links [] fixities loc (fst doc) decl splice unicode pkg qual -------------------------------------------------------------------------------- + -- * Type applications + -------------------------------------------------------------------------------- -ppAppDocNameTyVarBndrs :: RenderableBndrFlag flag => - Bool -> Unicode -> Qualification -> DocName -> [LHsTyVarBndr flag DocNameI] -> Html +ppAppDocNameTyVarBndrs + :: RenderableBndrFlag flag + => Bool + -> Unicode + -> Qualification + -> DocName + -> [LHsTyVarBndr flag DocNameI] + -> Html ppAppDocNameTyVarBndrs summ unicode qual n vs = - ppTypeApp n vs ppDN (ppHsTyVarBndr unicode qual . unLoc) + ppTypeApp n vs ppDN (ppHsTyVarBndr unicode qual . unLoc) where ppDN notation = ppBinderFixity notation summ . nameOccName . getName ppBinderFixity Infix = ppBinderInfix @@ -396,48 +664,56 @@ ppAppDocNameTyVarBndrs summ unicode qual n vs = -- | Print an application of a 'DocName' to its list of 'HsType's ppAppNameTypes :: DocName -> [HsType DocNameI] -> Unicode -> Qualification -> Html ppAppNameTypes n ts unicode qual = - ppTypeApp n ts (\p -> ppDocName qual p True) (ppParendType unicode qual HideEmptyContexts) + ppTypeApp n ts (\p -> ppDocName qual p True) (ppParendType unicode qual HideEmptyContexts) ppAppNameTypeArgs :: DocName -> [LHsTypeArg DocNameI] -> Unicode -> Qualification -> Html -ppAppNameTypeArgs n args@(HsValArg _ _:HsValArg _ _:_) u q - = ppTypeApp n args (\p -> ppDocName q p True) (ppLHsTypeArg u q HideEmptyContexts) -ppAppNameTypeArgs n args u q - = (ppDocName q Prefix True n) <+> hsep (map (ppLHsTypeArg u q HideEmptyContexts) args) +ppAppNameTypeArgs n args@(HsValArg _ _ : HsValArg _ _ : _) u q = + ppTypeApp n args (\p -> ppDocName q p True) (ppLHsTypeArg u q HideEmptyContexts) +ppAppNameTypeArgs n args u q = + (ppDocName q Prefix True n) <+> hsep (map (ppLHsTypeArg u q HideEmptyContexts) args) -- | General printing of type applications ppTypeApp :: DocName -> [a] -> (Notation -> DocName -> Html) -> (a -> Html) -> Html -ppTypeApp n (t1:t2:rest) ppDN ppT +ppTypeApp n (t1 : t2 : rest) ppDN ppT | operator, not . null $ rest = parens opApp <+> hsep (map ppT rest) - | operator = opApp + | operator = opApp where operator = isNameSym . getName $ n opApp = ppT t1 <+> ppDN Infix n <+> ppT t2 - ppTypeApp n ts ppDN ppT = ppDN Prefix n <+> hsep (map ppT ts) ------------------------------------------------------------------------------- --- * Contexts -------------------------------------------------------------------------------- +-- * Contexts -ppLContext :: Maybe (LHsContext DocNameI) -> Unicode - -> Qualification -> HideEmptyContexts -> Html -ppLContext Nothing u q h = ppContext [] u q h -ppLContext (Just c) u q h = ppContext (unLoc c) u q h +------------------------------------------------------------------------------- -ppLContextNoArrow :: LHsContext DocNameI -> Unicode - -> Qualification -> HideEmptyContexts -> Html +ppLContext + :: Maybe (LHsContext DocNameI) + -> Unicode + -> Qualification + -> HideEmptyContexts + -> Html +ppLContext Nothing u q h = ppContext [] u q h +ppLContext (Just c) u q h = ppContext (unLoc c) u q h + +ppLContextNoArrow + :: LHsContext DocNameI + -> Unicode + -> Qualification + -> HideEmptyContexts + -> Html ppLContextNoArrow c u q h = ppContextNoArrow (unLoc c) u q h ppContextNoArrow :: HsContext DocNameI -> Unicode -> Qualification -> HideEmptyContexts -> Html -ppContextNoArrow cxt unicode qual emptyCtxts = fromMaybe noHtml $ - ppContextNoLocsMaybe (map unLoc cxt) unicode qual emptyCtxts - +ppContextNoArrow cxt unicode qual emptyCtxts = + fromMaybe noHtml $ + ppContextNoLocsMaybe (map unLoc cxt) unicode qual emptyCtxts ppContextNoLocs :: [HsType DocNameI] -> Unicode -> Qualification -> HideEmptyContexts -> Html -ppContextNoLocs cxt unicode qual emptyCtxts = maybe noHtml (<+> darrow unicode) $ - ppContextNoLocsMaybe cxt unicode qual emptyCtxts - +ppContextNoLocs cxt unicode qual emptyCtxts = + maybe noHtml (<+> darrow unicode) $ + ppContextNoLocsMaybe cxt unicode qual emptyCtxts ppContextNoLocsMaybe :: [HsType DocNameI] -> Unicode -> Qualification -> HideEmptyContexts -> Maybe Html ppContextNoLocsMaybe [] _ _ emptyCtxts = @@ -449,473 +725,672 @@ ppContextNoLocsMaybe cxt unicode qual _ = Just $ ppHsContext cxt unicode qual ppContext :: HsContext DocNameI -> Unicode -> Qualification -> HideEmptyContexts -> Html ppContext cxt unicode qual emptyCtxts = ppContextNoLocs (map unLoc cxt) unicode qual emptyCtxts - ppHsContext :: [HsType DocNameI] -> Unicode -> Qualification -> Html -ppHsContext [] _ _ = noHtml +ppHsContext [] _ _ = noHtml ppHsContext [p] unicode qual = ppCtxType unicode qual p ppHsContext cxt unicode qual = parenList (map (ppType unicode qual HideEmptyContexts) cxt) - ------------------------------------------------------------------------------- + -- * Class declarations -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- -ppClassHdr :: Bool -> Maybe (LocatedC [LHsType DocNameI]) -> DocName - -> LHsQTyVars DocNameI -> [LHsFunDep DocNameI] - -> Unicode -> Qualification -> Html +ppClassHdr + :: Bool + -> Maybe (LocatedC [LHsType DocNameI]) + -> DocName + -> LHsQTyVars DocNameI + -> [LHsFunDep DocNameI] + -> Unicode + -> Qualification + -> Html ppClassHdr summ lctxt n tvs fds unicode qual = keyword "class" - <+> (if not (null $ fromMaybeContext lctxt) then ppLContext lctxt unicode qual HideEmptyContexts else noHtml) - <+> ppAppDocNameTyVarBndrs summ unicode qual n (hsQTvExplicit tvs) - <+> ppFds fds unicode qual - + <+> (if not (null $ fromMaybeContext lctxt) then ppLContext lctxt unicode qual HideEmptyContexts else noHtml) + <+> ppAppDocNameTyVarBndrs summ unicode qual n (hsQTvExplicit tvs) + <+> ppFds fds unicode qual ppFds :: [LHsFunDep DocNameI] -> Unicode -> Qualification -> Html ppFds fds unicode qual = - if null fds then noHtml else - char '|' <+> hsep (punctuate comma (map (fundep . unLoc) fds)) + if null fds + then noHtml + else char '|' <+> hsep (punctuate comma (map (fundep . unLoc) fds)) where - fundep (FunDep _ vars1 vars2) = ppVars vars1 <+> arrow unicode <+> ppVars vars2 - fundep (XFunDep _) = error "ppFds" - ppVars = hsep . map ((ppDocName qual Prefix True) . unLoc) - -ppShortClassDecl :: Bool -> LinksInfo -> TyClDecl DocNameI -> SrcSpan - -> [(DocName, DocForDecl DocName)] - -> Splice -> Unicode -> Maybe Package -> Qualification -> Html -ppShortClassDecl summary links (ClassDecl { tcdCtxt = lctxt, tcdLName = lname, tcdTyVars = tvs - , tcdFDs = fds, tcdSigs = sigs, tcdATs = ats }) loc - subdocs splice unicode pkg qual = - if not (any isUserLSig sigs) && null ats - then (if summary then id else topDeclElem links loc splice [nm]) hdr - else (if summary then id else topDeclElem links loc splice [nm]) (hdr <+> keyword "where") - +++ shortSubDecls False - ( - [ ppAssocType summary links doc at [] splice unicode pkg qual | at <- ats - , let doc = lookupAnySubdoc (unL $ fdLName $ unL at) subdocs ] ++ - + fundep (FunDep _ vars1 vars2) = ppVars vars1 <+> arrow unicode <+> ppVars vars2 + fundep (XFunDep _) = error "ppFds" + ppVars = hsep . map ((ppDocName qual Prefix True) . unLoc) + +ppShortClassDecl + :: Bool + -> LinksInfo + -> TyClDecl DocNameI + -> SrcSpan + -> [(DocName, DocForDecl DocName)] + -> Splice + -> Unicode + -> Maybe Package + -> Qualification + -> Html +ppShortClassDecl + summary + links + ( ClassDecl + { tcdCtxt = lctxt + , tcdLName = lname + , tcdTyVars = tvs + , tcdFDs = fds + , tcdSigs = sigs + , tcdATs = ats + } + ) + loc + subdocs + splice + unicode + pkg + qual = + if not (any isUserLSig sigs) && null ats + then (if summary then id else topDeclElem links loc splice [nm]) hdr + else + (if summary then id else topDeclElem links loc splice [nm]) (hdr <+> keyword "where") + +++ shortSubDecls + False + ( [ ppAssocType summary links doc at [] splice unicode pkg qual | at <- ats, let doc = lookupAnySubdoc (unL $ fdLName $ unL at) subdocs + ] + ++ -- ToDo: add associated type defaults - [ ppFunSig summary links loc noHtml doc names typ - [] splice unicode pkg qual - | L _ (ClassOpSig _ False lnames typ) <- sigs - , let doc = lookupAnySubdoc (head names) subdocs - names = map unLoc lnames ] - -- FIXME: is taking just the first name ok? Is it possible that - -- there are different subdocs for different names in a single - -- type signature? - ) - where - hdr = ppClassHdr summary lctxt (unLoc lname) tvs fds unicode qual - nm = unLoc lname + [ ppFunSig + summary + links + loc + noHtml + doc + names + typ + [] + splice + unicode + pkg + qual + | L _ (ClassOpSig _ False lnames typ) <- sigs + , let doc = lookupAnySubdoc (head names) subdocs + names = map unLoc lnames + ] + -- FIXME: is taking just the first name ok? Is it possible that + -- there are different subdocs for different names in a single + -- type signature? + ) + where + hdr = ppClassHdr summary lctxt (unLoc lname) tvs fds unicode qual + nm = unLoc lname ppShortClassDecl _ _ _ _ _ _ _ _ _ = error "declaration type not supported by ppShortClassDecl" - - -ppClassDecl :: Bool -> LinksInfo -> [DocInstance DocNameI] -> [(DocName, Fixity)] - -> SrcSpan -> Documentation DocName - -> [(DocName, DocForDecl DocName)] -> TyClDecl DocNameI - -> Splice -> Unicode -> Maybe Package -> Qualification -> Html -ppClassDecl summary links instances fixities loc d subdocs - decl@(ClassDecl { tcdCtxt = lctxt, tcdLName = lname, tcdTyVars = ltyvars - , tcdFDs = lfds, tcdSigs = lsigs, tcdATs = ats, tcdATDefs = atsDefs }) - splice unicode pkg qual - | summary = ppShortClassDecl summary links decl loc subdocs splice unicode pkg qual - | otherwise = classheader +++ docSection curname pkg qual d - +++ minimalBit +++ atBit +++ methodBit +++ instancesBit - where - curname = Just $ getName nm - - sigs = map unLoc lsigs - - classheader - | any isUserLSig lsigs = topDeclElem links loc splice [nm] (hdr unicode qual <+> keyword "where" <+> fixs) - | otherwise = topDeclElem links loc splice [nm] (hdr unicode qual <+> fixs) - - -- Only the fixity relevant to the class header - fixs = ppFixities [ f | f@(n,_) <- fixities, n == unLoc lname ] qual - - nm = tcdNameI decl - - hdr = ppClassHdr summary lctxt (unLoc lname) ltyvars lfds - - -- Associated types - atBit = subAssociatedTypes - [ ppAssocType summary links doc at subfixs splice unicode pkg qual - <+> - subDefaults (maybeToList defTys) - | at <- ats - , let name = unLoc . fdLName $ unLoc at - doc = lookupAnySubdoc name subdocs - subfixs = filter ((== name) . fst) fixities - defTys = (declElem . ppDefaultAssocTy name) <$> lookupDAT name - ] - - -- Default associated types - ppDefaultAssocTy n (vs,rhs) = hsep - [ keyword "type", ppAppNameTypeArgs n vs unicode qual, equals - , ppType unicode qual HideEmptyContexts (unLoc rhs) - ] - - lookupDAT name = Map.lookup (getName name) defaultAssocTys - defaultAssocTys = Map.fromList - [ (getName name, (vs, typ)) - | L _ (TyFamInstDecl _ (FamEqn { feqn_rhs = typ - , feqn_tycon = L _ name - , feqn_pats = vs })) <- atsDefs - ] - - -- Methods - methodBit = subMethods - [ ppFunSig summary links loc noHtml doc [name] typ - subfixs splice unicode pkg qual - <+> - subDefaults (maybeToList defSigs) - | ClassOpSig _ False lnames typ <- sigs - , name <- map unLoc lnames - , let doc = lookupAnySubdoc name subdocs - subfixs = filter ((== name) . fst) fixities - defSigs = ppDefaultFunSig name <$> lookupDM name - ] +ppClassDecl + :: Bool + -> LinksInfo + -> [DocInstance DocNameI] + -> [(DocName, Fixity)] + -> SrcSpan + -> Documentation DocName + -> [(DocName, DocForDecl DocName)] + -> TyClDecl DocNameI + -> Splice + -> Unicode + -> Maybe Package + -> Qualification + -> Html +ppClassDecl + summary + links + instances + fixities + loc + d + subdocs + decl@( ClassDecl + { tcdCtxt = lctxt + , tcdLName = lname + , tcdTyVars = ltyvars + , tcdFDs = lfds + , tcdSigs = lsigs + , tcdATs = ats + , tcdATDefs = atsDefs + } + ) + splice + unicode + pkg + qual + | summary = ppShortClassDecl summary links decl loc subdocs splice unicode pkg qual + | otherwise = + classheader + +++ docSection curname pkg qual d + +++ minimalBit + +++ atBit + +++ methodBit + +++ instancesBit + where + curname = Just $ getName nm + + sigs = map unLoc lsigs + + classheader + | any isUserLSig lsigs = topDeclElem links loc splice [nm] (hdr unicode qual <+> keyword "where" <+> fixs) + | otherwise = topDeclElem links loc splice [nm] (hdr unicode qual <+> fixs) + + -- Only the fixity relevant to the class header + fixs = ppFixities [f | f@(n, _) <- fixities, n == unLoc lname] qual + + nm = tcdNameI decl + + hdr = ppClassHdr summary lctxt (unLoc lname) ltyvars lfds + + -- Associated types + atBit = + subAssociatedTypes + [ ppAssocType summary links doc at subfixs splice unicode pkg qual + <+> subDefaults (maybeToList defTys) + | at <- ats + , let name = unLoc . fdLName $ unLoc at + doc = lookupAnySubdoc name subdocs + subfixs = filter ((== name) . fst) fixities + defTys = (declElem . ppDefaultAssocTy name) <$> lookupDAT name + ] + + -- Default associated types + ppDefaultAssocTy n (vs, rhs) = + hsep + [ keyword "type" + , ppAppNameTypeArgs n vs unicode qual + , equals + , ppType unicode qual HideEmptyContexts (unLoc rhs) + ] + + lookupDAT name = Map.lookup (getName name) defaultAssocTys + defaultAssocTys = + Map.fromList + [ (getName name, (vs, typ)) + | L + _ + ( TyFamInstDecl + _ + ( FamEqn + { feqn_rhs = typ + , feqn_tycon = L _ name + , feqn_pats = vs + } + ) + ) <- + atsDefs + ] + + -- Methods + methodBit = + subMethods + [ ppFunSig + summary + links + loc + noHtml + doc + [name] + typ + subfixs + splice + unicode + pkg + qual + <+> subDefaults (maybeToList defSigs) + | ClassOpSig _ False lnames typ <- sigs + , name <- map unLoc lnames + , let doc = lookupAnySubdoc name subdocs + subfixs = filter ((== name) . fst) fixities + defSigs = ppDefaultFunSig name <$> lookupDM name + ] -- N.B. taking just the first name is ok. Signatures with multiple names -- are expanded so that each name gets its own signature. - -- Default methods - ppDefaultFunSig n (t, d') = ppFunSig summary links loc (keyword "default") - d' [n] t [] splice unicode pkg qual - - lookupDM name = Map.lookup (occNameString $ mkDefaultMethodOcc $ getOccName name) defaultMethods - defaultMethods = Map.fromList - [ (nameStr, (typ, doc)) - | ClassOpSig _ True lnames typ <- sigs - , name <- map unLoc lnames - , let doc = lookupAnySubdoc name subdocs - nameStr = getOccString name - ] - - -- Minimal complete definition - minimalBit = case [ s | MinimalSig _ (L _ s) <- sigs ] of - -- Miminal complete definition = every shown method - And xs : _ | sort [getName n | L _ (Var (L _ n)) <- xs] == - sort [getName n | ClassOpSig _ _ ns _ <- sigs, L _ n <- ns] - -> noHtml - - -- Minimal complete definition = the only shown method - Var (L _ n) : _ | [getName n] == - [getName n' | ClassOpSig _ _ ns _ <- sigs, L _ n' <- ns] - - -> noHtml - - -- Minimal complete definition = nothing - And [] : _ -> subMinimal $ toHtml "Nothing" - - m : _ -> subMinimal $ ppMinimal False m - _ -> noHtml - - ppMinimal _ (Var (L _ n)) = ppDocName qual Prefix True n - ppMinimal _ (And fs) = foldr1 (\a b -> a+++", "+++b) $ map (ppMinimal True . unLoc) fs - ppMinimal p (Or fs) = wrap $ foldr1 (\a b -> a+++" | "+++b) $ map (ppMinimal False . unLoc) fs - where wrap | p = parens | otherwise = id - ppMinimal p (Parens x) = ppMinimal p (unLoc x) - - -- Instances - instancesBit = ppInstances links (OriginClass nm) instances - splice unicode pkg qual - + -- Default methods + ppDefaultFunSig n (t, d') = + ppFunSig + summary + links + loc + (keyword "default") + d' + [n] + t + [] + splice + unicode + pkg + qual + + lookupDM name = Map.lookup (occNameString $ mkDefaultMethodOcc $ getOccName name) defaultMethods + defaultMethods = + Map.fromList + [ (nameStr, (typ, doc)) + | ClassOpSig _ True lnames typ <- sigs + , name <- map unLoc lnames + , let doc = lookupAnySubdoc name subdocs + nameStr = getOccString name + ] + + -- Minimal complete definition + minimalBit = case [s | MinimalSig _ (L _ s) <- sigs] of + -- Miminal complete definition = every shown method + And xs : _ + | sort [getName n | L _ (Var (L _ n)) <- xs] + == sort [getName n | ClassOpSig _ _ ns _ <- sigs, L _ n <- ns] -> + noHtml + -- Minimal complete definition = the only shown method + Var (L _ n) : _ + | [getName n] + == [getName n' | ClassOpSig _ _ ns _ <- sigs, L _ n' <- ns] -> + noHtml + -- Minimal complete definition = nothing + And [] : _ -> subMinimal $ toHtml "Nothing" + m : _ -> subMinimal $ ppMinimal False m + _ -> noHtml + + ppMinimal _ (Var (L _ n)) = ppDocName qual Prefix True n + ppMinimal _ (And fs) = foldr1 (\a b -> a +++ ", " +++ b) $ map (ppMinimal True . unLoc) fs + ppMinimal p (Or fs) = wrap $ foldr1 (\a b -> a +++ " | " +++ b) $ map (ppMinimal False . unLoc) fs + where + wrap | p = parens | otherwise = id + ppMinimal p (Parens x) = ppMinimal p (unLoc x) + + -- Instances + instancesBit = + ppInstances + links + (OriginClass nm) + instances + splice + unicode + pkg + qual ppClassDecl _ _ _ _ _ _ _ _ _ _ _ _ = error "declaration type not supported by ppShortClassDecl" - -ppInstances :: LinksInfo - -> InstOrigin DocName -> [DocInstance DocNameI] - -> Splice -> Unicode -> Maybe Package -> Qualification - -> Html -ppInstances links origin instances splice unicode pkg qual - = subInstances pkg qual instName links True (zipWith instDecl [1..] instances) - -- force Splice = True to use line URLs +ppInstances + :: LinksInfo + -> InstOrigin DocName + -> [DocInstance DocNameI] + -> Splice + -> Unicode + -> Maybe Package + -> Qualification + -> Html +ppInstances links origin instances splice unicode pkg qual = + subInstances pkg qual instName links True (zipWith instDecl [1 ..] instances) where + -- force Splice = True to use line URLs + instName = getOccString origin instDecl :: Int -> DocInstance DocNameI -> (SubDecl, Maybe Module, Located DocName) instDecl no (inst, mdoc, loc, mdl) = - ((ppInstHead links splice unicode qual mdoc origin False no inst mdl), mdl, loc) - - -ppOrphanInstances :: LinksInfo - -> [DocInstance DocNameI] - -> Splice -> Unicode -> Maybe Package -> Qualification - -> Html -ppOrphanInstances links instances splice unicode pkg qual - = subOrphanInstances pkg qual links True (zipWith instDecl [1..] instances) + ((ppInstHead links splice unicode qual mdoc origin False no inst mdl), mdl, loc) + +ppOrphanInstances + :: LinksInfo + -> [DocInstance DocNameI] + -> Splice + -> Unicode + -> Maybe Package + -> Qualification + -> Html +ppOrphanInstances links instances splice unicode pkg qual = + subOrphanInstances pkg qual links True (zipWith instDecl [1 ..] instances) where instOrigin :: InstHead name -> InstOrigin (IdP name) instOrigin inst = OriginClass (ihdClsName inst) instDecl :: Int -> DocInstance DocNameI -> (SubDecl, Maybe Module, Located DocName) instDecl no (inst, mdoc, loc, mdl) = - ((ppInstHead links splice unicode qual mdoc (instOrigin inst) True no inst Nothing), mdl, loc) - - -ppInstHead :: LinksInfo -> Splice -> Unicode -> Qualification - -> Maybe (MDoc DocName) - -> InstOrigin DocName - -> Bool -- ^ Is instance orphan - -> Int -- ^ Normal - -> InstHead DocNameI - -> Maybe Module - -> SubDecl -ppInstHead links splice unicode qual mdoc origin orphan no ihd@(InstHead {..}) mdl = - case ihdInstType of - ClassInst { .. } -> - ( subInstHead iid $ ppContextNoLocs clsiCtx unicode qual HideEmptyContexts <+> typ - , mdoc - , [subInstDetails iid ats sigs mname] - ) - where - sigs = ppInstanceSigs links splice unicode qual clsiSigs - ats = ppInstanceAssocTys links splice unicode qual orphan clsiAssocTys - TypeInst rhs -> - ( subInstHead iid ptype - , mdoc - , [subFamInstDetails iid prhs mname] - ) - where - ptype = keyword "type" <+> typ - prhs = ptype <+> maybe noHtml - (\t -> equals <+> ppType unicode qual HideEmptyContexts t) rhs - DataInst dd -> - ( subInstHead iid pdata - , mdoc - , [subFamInstDetails iid pdecl mname]) - where - cons = dd_cons (tcdDataDefn dd) - pref = case cons of { NewTypeCon _ -> keyword "newtype"; DataTypeCons _ _ -> keyword "data" } - pdata = pref <+> typ - pdecl = pdata <+> ppShortDataDecl False True dd [] unicode qual + ((ppInstHead links splice unicode qual mdoc (instOrigin inst) True no inst Nothing), mdl, loc) + +ppInstHead + :: LinksInfo + -> Splice + -> Unicode + -> Qualification + -> Maybe (MDoc DocName) + -> InstOrigin DocName + -> Bool + -- ^ Is instance orphan + -> Int + -- ^ Normal + -> InstHead DocNameI + -> Maybe Module + -> SubDecl +ppInstHead links splice unicode qual mdoc origin orphan no ihd@(InstHead{..}) mdl = + case ihdInstType of + ClassInst{..} -> + ( subInstHead iid $ ppContextNoLocs clsiCtx unicode qual HideEmptyContexts <+> typ + , mdoc + , [subInstDetails iid ats sigs mname] + ) + where + sigs = ppInstanceSigs links splice unicode qual clsiSigs + ats = ppInstanceAssocTys links splice unicode qual orphan clsiAssocTys + TypeInst rhs -> + ( subInstHead iid ptype + , mdoc + , [subFamInstDetails iid prhs mname] + ) + where + ptype = keyword "type" <+> typ + prhs = + ptype + <+> maybe + noHtml + (\t -> equals <+> ppType unicode qual HideEmptyContexts t) + rhs + DataInst dd -> + ( subInstHead iid pdata + , mdoc + , [subFamInstDetails iid pdecl mname] + ) + where + cons = dd_cons (tcdDataDefn dd) + pref = case cons of NewTypeCon _ -> keyword "newtype"; DataTypeCons _ _ -> keyword "data" + pdata = pref <+> typ + pdecl = pdata <+> ppShortDataDecl False True dd [] unicode qual where mname = maybe noHtml (\m -> toHtml "Defined in" <+> ppModule m) mdl iid = instanceId origin no orphan ihd typ = ppAppNameTypes ihdClsName ihdTypes unicode qual - -ppInstanceAssocTys :: LinksInfo -> Splice -> Unicode -> Qualification -> Bool - -> [DocInstance DocNameI] - -> [Html] +ppInstanceAssocTys + :: LinksInfo + -> Splice + -> Unicode + -> Qualification + -> Bool + -> [DocInstance DocNameI] + -> [Html] ppInstanceAssocTys links splice unicode qual orphan insts = - maybeToList $ + maybeToList $ subTableSrc Nothing qual links True $ - zipWith mkInstHead - insts - [1..] - where - mkInstHead (inst, doc, name, mdl) no = - (ppInstHead links splice unicode qual doc (OriginFamily (unLoc name)) orphan no inst mdl - , mdl - , name) - - -ppInstanceSigs :: LinksInfo -> Splice -> Unicode -> Qualification - -> [Sig DocNameI] - -> [Html] + zipWith + mkInstHead + insts + [1 ..] + where + mkInstHead (inst, doc, name, mdl) no = + ( ppInstHead links splice unicode qual doc (OriginFamily (unLoc name)) orphan no inst mdl + , mdl + , name + ) + +ppInstanceSigs + :: LinksInfo + -> Splice + -> Unicode + -> Qualification + -> [Sig DocNameI] + -> [Html] ppInstanceSigs links splice unicode qual sigs = do - TypeSig _ lnames typ <- sigs - let names = map unLoc lnames - L _ rtyp = dropWildCards typ - -- Instance methods signatures are synified and thus don't have a useful - -- SrcSpan value. Use the methods name location instead. - return $ ppSimpleSig links splice unicode qual HideEmptyContexts (getLocA $ head lnames) names rtyp - + TypeSig _ lnames typ <- sigs + let names = map unLoc lnames + L _ rtyp = dropWildCards typ + -- Instance methods signatures are synified and thus don't have a useful + -- SrcSpan value. Use the methods name location instead. + return $ ppSimpleSig links splice unicode qual HideEmptyContexts (getLocA $ head lnames) names rtyp lookupAnySubdoc :: Eq id1 => id1 -> [(id1, DocForDecl id2)] -> DocForDecl id2 lookupAnySubdoc n = fromMaybe noDocForDecl . lookup n - instanceId :: InstOrigin DocName -> Int -> Bool -> InstHead DocNameI -> String -instanceId origin no orphan ihd = concat $ - [ "o:" | orphan ] ++ - [ qual origin - , ":" ++ getOccString origin - , ":" ++ getOccString (ihdClsName ihd) - , ":" ++ show no - ] +instanceId origin no orphan ihd = + concat $ + ["o:" | orphan] + ++ [ qual origin + , ":" ++ getOccString origin + , ":" ++ getOccString (ihdClsName ihd) + , ":" ++ show no + ] where qual (OriginClass _) = "ic" qual (OriginData _) = "id" qual (OriginFamily _) = "if" - ------------------------------------------------------------------------------- + -- * Data & newtype declarations -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- -- TODO: print contexts -ppShortDataDecl :: Bool -> Bool -> TyClDecl DocNameI - -> [(HsDecl DocNameI, DocForDecl DocName)] - -> Unicode -> Qualification -> Html +ppShortDataDecl + :: Bool + -> Bool + -> TyClDecl DocNameI + -> [(HsDecl DocNameI, DocForDecl DocName)] + -> Unicode + -> Qualification + -> Html ppShortDataDecl summary dataInst dataDecl pats unicode qual - | [] <- toList cons - , [] <- pats = dataHeader - - | [lcon] <- toList cons, [] <- pats, isH98, - (cHead,cBody,cFoot) <- ppShortConstrParts summary dataInst (unLoc lcon) unicode qual - = (dataHeader <+> equals <+> cHead) +++ cBody +++ cFoot - - | [] <- pats, isH98 = dataHeader - +++ shortSubDecls dataInst (zipWith doConstr ('=':repeat '|') (toList cons) ++ pats1) - - | otherwise = (dataHeader <+> keyword "where") - +++ shortSubDecls dataInst (map doGADTConstr (toList cons) ++ pats1) - + , [] <- pats = + dataHeader + | [lcon] <- toList cons + , [] <- pats + , isH98 + , (cHead, cBody, cFoot) <- ppShortConstrParts summary dataInst (unLoc lcon) unicode qual = + (dataHeader <+> equals <+> cHead) +++ cBody +++ cFoot + | [] <- pats + , isH98 = + dataHeader + +++ shortSubDecls dataInst (zipWith doConstr ('=' : repeat '|') (toList cons) ++ pats1) + | otherwise = + (dataHeader <+> keyword "where") + +++ shortSubDecls dataInst (map doGADTConstr (toList cons) ++ pats1) where dataHeader - | dataInst = noHtml + | dataInst = noHtml | otherwise = ppDataHeader summary dataDecl unicode qual doConstr c con = toHtml [c] <+> ppShortConstr summary (unLoc con) unicode qual doGADTConstr con = ppShortConstr summary (unLoc con) unicode qual - cons = dd_cons (tcdDataDefn dataDecl) - isH98 = flip any (unLoc <$> cons) $ \ case - ConDeclH98 {} -> True - ConDeclGADT{} -> False - - pats1 = [ hsep [ keyword "pattern" - , hsep $ punctuate comma $ map (ppBinder summary . getOccName) lnames - , dcolon unicode - , ppPatSigType unicode qual typ - ] - | (SigD _ (PatSynSig _ lnames typ),_) <- pats - ] - - --- | Pretty-print a data declaration -ppDataDecl :: Bool -> LinksInfo - -> [DocInstance DocNameI] -- ^ relevant instances - -> [(DocName, Fixity)] -- ^ relevant fixities - -> [(DocName, DocForDecl DocName)] -- ^ all decl documentation - -> SrcSpan - -> Documentation DocName -- ^ this decl's documentation - -> TyClDecl DocNameI -- ^ this decl - -> [(HsDecl DocNameI, DocForDecl DocName)] -- ^ relevant patterns - -> Splice -> Unicode -> Maybe Package -> Qualification -> Html -ppDataDecl summary links instances fixities subdocs loc doc dataDecl pats - splice unicode pkg qual - - | summary = ppShortDataDecl summary False dataDecl pats unicode qual - | otherwise = header_ +++ docSection curname pkg qual doc +++ constrBit +++ patternBit +++ instancesBit - - where - docname = tcdNameI dataDecl - curname = Just $ getName docname - cons = dd_cons (tcdDataDefn dataDecl) - isH98 = flip any (unLoc <$> cons) $ \ case - ConDeclH98 {} -> True - ConDeclGADT{} -> False - - header_ = topDeclElem links loc splice [docname] $ - ppDataHeader summary dataDecl unicode qual <+> whereBit <+> fix - - fix = ppFixities (filter (\(n,_) -> n == docname) fixities) qual - - whereBit - | null cons - , null pats = noHtml - | isH98 = noHtml - | otherwise = keyword "where" - - constrBit = subConstructors pkg qual - [ ppSideBySideConstr subdocs subfixs unicode pkg qual c - | c <- toList cons - , let subfixs = filter (\(n,_) -> any (\cn -> cn == n) - (unL <$> getConNamesI (unLoc c))) fixities - ] - - patternBit = subPatterns pkg qual - [ ppSideBySidePat subfixs unicode qual lnames typ d - | (SigD _ (PatSynSig _ lnames typ), d) <- pats - , let subfixs = filter (\(n,_) -> any (\cn -> cn == n) - (map unLoc lnames)) fixities + cons = dd_cons (tcdDataDefn dataDecl) + isH98 = flip any (unLoc <$> cons) $ \case + ConDeclH98{} -> True + ConDeclGADT{} -> False + + pats1 = + [ hsep + [ keyword "pattern" + , hsep $ punctuate comma $ map (ppBinder summary . getOccName) lnames + , dcolon unicode + , ppPatSigType unicode qual typ + ] + | (SigD _ (PatSynSig _ lnames typ), _) <- pats ] - instancesBit = ppInstances links (OriginData docname) instances - splice unicode pkg qual - +-- | Pretty-print a data declaration +ppDataDecl + :: Bool + -> LinksInfo + -> [DocInstance DocNameI] + -- ^ relevant instances + -> [(DocName, Fixity)] + -- ^ relevant fixities + -> [(DocName, DocForDecl DocName)] + -- ^ all decl documentation + -> SrcSpan + -> Documentation DocName + -- ^ this decl's documentation + -> TyClDecl DocNameI + -- ^ this decl + -> [(HsDecl DocNameI, DocForDecl DocName)] + -- ^ relevant patterns + -> Splice + -> Unicode + -> Maybe Package + -> Qualification + -> Html +ppDataDecl + summary + links + instances + fixities + subdocs + loc + doc + dataDecl + pats + splice + unicode + pkg + qual + | summary = ppShortDataDecl summary False dataDecl pats unicode qual + | otherwise = header_ +++ docSection curname pkg qual doc +++ constrBit +++ patternBit +++ instancesBit + where + docname = tcdNameI dataDecl + curname = Just $ getName docname + cons = dd_cons (tcdDataDefn dataDecl) + isH98 = flip any (unLoc <$> cons) $ \case + ConDeclH98{} -> True + ConDeclGADT{} -> False + + header_ = + topDeclElem links loc splice [docname] $ + ppDataHeader summary dataDecl unicode qual <+> whereBit <+> fix + + fix = ppFixities (filter (\(n, _) -> n == docname) fixities) qual + + whereBit + | null cons + , null pats = + noHtml + | isH98 = noHtml + | otherwise = keyword "where" + + constrBit = + subConstructors + pkg + qual + [ ppSideBySideConstr subdocs subfixs unicode pkg qual c + | c <- toList cons + , let subfixs = + filter + ( \(n, _) -> + any + (\cn -> cn == n) + (unL <$> getConNamesI (unLoc c)) + ) + fixities + ] + + patternBit = + subPatterns + pkg + qual + [ ppSideBySidePat subfixs unicode qual lnames typ d + | (SigD _ (PatSynSig _ lnames typ), d) <- pats + , let subfixs = + filter + ( \(n, _) -> + any + (\cn -> cn == n) + (map unLoc lnames) + ) + fixities + ] + + instancesBit = + ppInstances + links + (OriginData docname) + instances + splice + unicode + pkg + qual ppShortConstr :: Bool -> ConDecl DocNameI -> Unicode -> Qualification -> Html ppShortConstr summary con unicode qual = cHead <+> cBody <+> cFoot where - (cHead,cBody,cFoot) = ppShortConstrParts summary False con unicode qual - + (cHead, cBody, cFoot) = ppShortConstrParts summary False con unicode qual -- returns three pieces: header, body, footer so that header & footer can be -- incorporated into the declaration ppShortConstrParts :: Bool -> Bool -> ConDecl DocNameI -> Unicode -> Qualification -> (Html, Html, Html) -ppShortConstrParts summary dataInst con unicode qual - = case con of - ConDeclH98{ con_args = det - , con_ex_tvs = tyVars - , con_forall = forall_ - , con_mb_cxt = cxt - } -> let context = fromMaybeContext cxt - header_ = ppConstrHdr forall_ tyVars context unicode qual - in case det of - - -- Prefix constructor, e.g. 'Just a' - PrefixCon _ args -> - ( header_ <+> hsep (ppOcc : map (ppLParendType unicode qual HideEmptyContexts . hsScaledThing) args) - , noHtml - , noHtml - ) - - -- Record constructor, e.g. 'Identity { runIdentity :: a }' - RecCon (L _ fields) -> - ( header_ +++ ppOcc <+> char '{' - , shortSubDecls dataInst [ ppShortField summary unicode qual field - | L _ field <- fields - ] - , char '}' - ) - - -- Infix constructor, e.g. 'a :| [a]' - InfixCon arg1 arg2 -> - ( header_ <+> hsep [ ppLParendType unicode qual HideEmptyContexts (hsScaledThing arg1) - , ppOccInfix - , ppLParendType unicode qual HideEmptyContexts (hsScaledThing arg2) - ] - , noHtml - , noHtml - ) - - -- GADT constructor, e.g. 'Foo :: Int -> Foo' - ConDeclGADT {} -> - ( hsep [ ppOcc, dcolon unicode, ppLSigType unicode qual HideEmptyContexts (getGADTConType con) ] - , noHtml - , noHtml - ) - +ppShortConstrParts summary dataInst con unicode qual = + case con of + ConDeclH98 + { con_args = det + , con_ex_tvs = tyVars + , con_forall = forall_ + , con_mb_cxt = cxt + } -> + let context = fromMaybeContext cxt + header_ = ppConstrHdr forall_ tyVars context unicode qual + in case det of + -- Prefix constructor, e.g. 'Just a' + PrefixCon _ args -> + ( header_ <+> hsep (ppOcc : map (ppLParendType unicode qual HideEmptyContexts . hsScaledThing) args) + , noHtml + , noHtml + ) + -- Record constructor, e.g. 'Identity { runIdentity :: a }' + RecCon (L _ fields) -> + ( header_ +++ ppOcc <+> char '{' + , shortSubDecls + dataInst + [ ppShortField summary unicode qual field + | L _ field <- fields + ] + , char '}' + ) + -- Infix constructor, e.g. 'a :| [a]' + InfixCon arg1 arg2 -> + ( header_ + <+> hsep + [ ppLParendType unicode qual HideEmptyContexts (hsScaledThing arg1) + , ppOccInfix + , ppLParendType unicode qual HideEmptyContexts (hsScaledThing arg2) + ] + , noHtml + , noHtml + ) + -- GADT constructor, e.g. 'Foo :: Int -> Foo' + ConDeclGADT{} -> + ( hsep [ppOcc, dcolon unicode, ppLSigType unicode qual HideEmptyContexts (getGADTConType con)] + , noHtml + , noHtml + ) where - occ = toList $ nameOccName . getName . unL <$> getConNamesI con - ppOcc = hsep (punctuate comma (map (ppBinder summary) occ)) + occ = toList $ nameOccName . getName . unL <$> getConNamesI con + ppOcc = hsep (punctuate comma (map (ppBinder summary) occ)) ppOccInfix = hsep (punctuate comma (map (ppBinderInfix summary) occ)) - -- | Pretty print an expanded constructor -ppSideBySideConstr :: [(DocName, DocForDecl DocName)] -> [(DocName, Fixity)] - -> Unicode -> Maybe Package -> Qualification - -> LConDecl DocNameI -- ^ constructor declaration to print - -> SubDecl -ppSideBySideConstr subdocs fixities unicode pkg qual (L _ con) - = ( decl -- Constructor header (name, fixity) - , mbDoc -- Docs on the whole constructor - , fieldPart -- Information on the fields (or arguments, if they have docs) - ) - where +ppSideBySideConstr + :: [(DocName, DocForDecl DocName)] + -> [(DocName, Fixity)] + -> Unicode + -> Maybe Package + -> Qualification + -> LConDecl DocNameI + -- ^ constructor declaration to print + -> SubDecl +ppSideBySideConstr subdocs fixities unicode pkg qual (L _ con) = + ( decl -- Constructor header (name, fixity) + , mbDoc -- Docs on the whole constructor + , fieldPart -- Information on the fields (or arguments, if they have docs) + ) + where -- Find the name of a constructors in the decl (`getConName` always returns a non-empty list) L _ aConName :| _ = getConNamesI con - fixity = ppFixities fixities qual - occ = toList $ nameOccName . getName . unL <$> getConNamesI con + fixity = ppFixities fixities qual + occ = toList $ nameOccName . getName . unL <$> getConNamesI con - ppOcc = hsep (punctuate comma (map (ppBinder False) occ)) + ppOcc = hsep (punctuate comma (map (ppBinder False) occ)) ppOccInfix = hsep (punctuate comma (map (ppBinderInfix False) occ)) -- Extract out the map of of docs corresponding to the constructors arguments @@ -923,85 +1398,102 @@ ppSideBySideConstr subdocs fixities unicode pkg qual (L _ con) hasArgDocs = not $ Map.null argDocs decl = case con of - ConDeclH98{ con_args = det - , con_ex_tvs = tyVars - , con_forall = forall_ - , con_mb_cxt = cxt - } -> let context = fromMaybeContext cxt - header_ = ppConstrHdr forall_ tyVars context unicode qual - in case det of - -- Prefix constructor, e.g. 'Just a' - PrefixCon _ args - | hasArgDocs -> header_ <+> ppOcc <+> fixity - | otherwise -> hsep [ header_ <+> ppOcc - , hsep (map (ppLParendType unicode qual HideEmptyContexts . hsScaledThing) args) - , fixity - ] - - -- Record constructor, e.g. 'Identity { runIdentity :: a }' - RecCon _ -> header_ <+> ppOcc <+> fixity - - -- Infix constructor, e.g. 'a :| [a]' - InfixCon arg1 arg2 - | hasArgDocs -> header_ <+> ppOcc <+> fixity - | otherwise -> hsep [ header_ <+> ppLParendType unicode qual HideEmptyContexts (hsScaledThing arg1) - , ppOccInfix - , ppLParendType unicode qual HideEmptyContexts (hsScaledThing arg2) - , fixity - ] - + ConDeclH98 + { con_args = det + , con_ex_tvs = tyVars + , con_forall = forall_ + , con_mb_cxt = cxt + } -> + let context = fromMaybeContext cxt + header_ = ppConstrHdr forall_ tyVars context unicode qual + in case det of + -- Prefix constructor, e.g. 'Just a' + PrefixCon _ args + | hasArgDocs -> header_ <+> ppOcc <+> fixity + | otherwise -> + hsep + [ header_ <+> ppOcc + , hsep (map (ppLParendType unicode qual HideEmptyContexts . hsScaledThing) args) + , fixity + ] + -- Record constructor, e.g. 'Identity { runIdentity :: a }' + RecCon _ -> header_ <+> ppOcc <+> fixity + -- Infix constructor, e.g. 'a :| [a]' + InfixCon arg1 arg2 + | hasArgDocs -> header_ <+> ppOcc <+> fixity + | otherwise -> + hsep + [ header_ <+> ppLParendType unicode qual HideEmptyContexts (hsScaledThing arg1) + , ppOccInfix + , ppLParendType unicode qual HideEmptyContexts (hsScaledThing arg2) + , fixity + ] -- GADT constructor, e.g. 'Foo :: Int -> Foo' ConDeclGADT{} - | hasArgDocs || not (null fieldPart) -> ppOcc <+> fixity - | otherwise -> hsep [ ppOcc - , dcolon unicode - -- ++AZ++ make this prepend "{..}" when it is a record style GADT - , ppLSigType unicode qual HideEmptyContexts (getGADTConType con) - , fixity - ] + | hasArgDocs || not (null fieldPart) -> ppOcc <+> fixity + | otherwise -> + hsep + [ ppOcc + , dcolon unicode + , -- ++AZ++ make this prepend "{..}" when it is a record style GADT + ppLSigType unicode qual HideEmptyContexts (getGADTConType con) + , fixity + ] fieldPart = case con of - ConDeclGADT{con_g_args = con_args'} -> case con_args' of - -- GADT record declarations - RecConGADT _ _ -> [ doConstrArgsWithDocs [] ] - -- GADT prefix data constructors - PrefixConGADT _ args | hasArgDocs -> [ doConstrArgsWithDocs args ] - _ -> [] - - ConDeclH98{con_args = con_args'} -> case con_args' of - -- H98 record declarations - RecCon (L _ fields) -> [ doRecordFields fields ] - -- H98 prefix data constructors - PrefixCon _ args | hasArgDocs -> [ doConstrArgsWithDocs args ] - -- H98 infix data constructor - InfixCon arg1 arg2 | hasArgDocs -> [ doConstrArgsWithDocs [arg1,arg2] ] - _ -> [] - - doRecordFields fields = subFields pkg qual - (map (ppSideBySideField subdocs unicode qual) (map unLoc fields)) + ConDeclGADT{con_g_args = con_args'} -> case con_args' of + -- GADT record declarations + RecConGADT _ _ -> [doConstrArgsWithDocs []] + -- GADT prefix data constructors + PrefixConGADT _ args | hasArgDocs -> [doConstrArgsWithDocs args] + _ -> [] + ConDeclH98{con_args = con_args'} -> case con_args' of + -- H98 record declarations + RecCon (L _ fields) -> [doRecordFields fields] + -- H98 prefix data constructors + PrefixCon _ args | hasArgDocs -> [doConstrArgsWithDocs args] + -- H98 infix data constructor + InfixCon arg1 arg2 | hasArgDocs -> [doConstrArgsWithDocs [arg1, arg2]] + _ -> [] + + doRecordFields fields = + subFields + pkg + qual + (map (ppSideBySideField subdocs unicode qual) (map unLoc fields)) doConstrArgsWithDocs args = subFields pkg qual $ case con of ConDeclH98{} -> [ (ppLParendType unicode qual HideEmptyContexts arg, mdoc, []) - | (i, arg) <- zip [0..] (map hsScaledThing args) + | (i, arg) <- zip [0 ..] (map hsScaledThing args) , let mdoc = Map.lookup i argDocs ] ConDeclGADT{} -> - ppSubSigLike unicode qual (unLoc (getGADTConType con)) - argDocs subdocs (dcolon unicode) HideEmptyContexts + ppSubSigLike + unicode + qual + (unLoc (getGADTConType con)) + argDocs + subdocs + (dcolon unicode) + HideEmptyContexts -- don't use "con_doc con", in case it's reconstructed from a .hi file, -- or also because we want Haddock to do the doc-parsing, not GHC. - mbDoc = lookup aConName subdocs >>= - combineDocumentation . fst - + mbDoc = + lookup aConName subdocs + >>= combineDocumentation . fst -- ppConstrHdr is for (non-GADT) existentials constructors' syntax ppConstrHdr - :: Bool -- ^ print explicit foralls - -> [LHsTyVarBndr Specificity DocNameI] -- ^ type variables - -> HsContext DocNameI -- ^ context - -> Unicode -> Qualification + :: Bool + -- ^ print explicit foralls + -> [LHsTyVarBndr Specificity DocNameI] + -- ^ type variables + -> HsContext DocNameI + -- ^ context + -> Unicode + -> Qualification -> Html ppConstrHdr forall_ tvs ctxt unicode qual = ppForall +++ ppCtxt where @@ -1011,18 +1503,27 @@ ppConstrHdr forall_ tvs ctxt unicode qual = ppForall +++ ppCtxt ppCtxt | null ctxt = noHtml - | otherwise = ppContextNoArrow ctxt unicode qual HideEmptyContexts - <+> darrow unicode +++ toHtml " " - + | otherwise = + ppContextNoArrow ctxt unicode qual HideEmptyContexts + <+> darrow unicode + +++ toHtml " " -- | Pretty-print a record field -ppSideBySideField :: [(DocName, DocForDecl DocName)] -> Unicode -> Qualification - -> ConDeclField DocNameI -> SubDecl +ppSideBySideField + :: [(DocName, DocForDecl DocName)] + -> Unicode + -> Qualification + -> ConDeclField DocNameI + -> SubDecl ppSideBySideField subdocs unicode qual (ConDeclField _ names ltype _) = - ( hsep (punctuate comma [ ppBinder False (rdrNameOcc field) - | L _ name <- names - , let field = (unLoc . foLabel) name - ]) + ( hsep + ( punctuate + comma + [ ppBinder False (rdrNameOcc field) + | L _ name <- names + , let field = (unLoc . foLabel) name + ] + ) <+> dcolon unicode <+> ppLType unicode qual HideEmptyContexts ltype , mbDoc @@ -1033,19 +1534,24 @@ ppSideBySideField subdocs unicode qual (ConDeclField _ names ltype _) = -- Where there is more than one name, they all have the same documentation mbDoc = lookup (foExt $ unLoc $ head names) subdocs >>= combineDocumentation . fst - ppShortField :: Bool -> Unicode -> Qualification -> ConDeclField DocNameI -> Html -ppShortField summary unicode qual (ConDeclField _ names ltype _) - = hsep (punctuate comma (map ((ppBinder summary) . rdrNameOcc . unLoc . foLabel . unLoc) names)) - <+> dcolon unicode <+> ppLType unicode qual HideEmptyContexts ltype - +ppShortField summary unicode qual (ConDeclField _ names ltype _) = + hsep (punctuate comma (map ((ppBinder summary) . rdrNameOcc . unLoc . foLabel . unLoc) names)) + <+> dcolon unicode + <+> ppLType unicode qual HideEmptyContexts ltype -- | Pretty print an expanded pattern (for bundled patterns) -ppSideBySidePat :: [(DocName, Fixity)] -> Unicode -> Qualification - -> [LocatedN DocName] -- ^ pattern name(s) - -> LHsSigType DocNameI -- ^ type of pattern(s) - -> DocForDecl DocName -- ^ doc map - -> SubDecl +ppSideBySidePat + :: [(DocName, Fixity)] + -> Unicode + -> Qualification + -> [LocatedN DocName] + -- ^ pattern name(s) + -> LHsSigType DocNameI + -- ^ type of pattern(s) + -> DocForDecl DocName + -- ^ doc map + -> SubDecl ppSideBySidePat fixities unicode qual lnames typ (doc, argDocs) = ( decl , combineDocumentation doc @@ -1056,90 +1562,112 @@ ppSideBySidePat fixities unicode qual lnames typ (doc, argDocs) = fixity = ppFixities fixities qual ppOcc = hsep (punctuate comma (map (ppBinder False . getOccName) lnames)) - decl | hasArgDocs = keyword "pattern" <+> ppOcc <+> fixity - | otherwise = hsep [ keyword "pattern" - , ppOcc - , dcolon unicode - , ppPatSigType unicode qual typ - , fixity - ] + decl + | hasArgDocs = keyword "pattern" <+> ppOcc <+> fixity + | otherwise = + hsep + [ keyword "pattern" + , ppOcc + , dcolon unicode + , ppPatSigType unicode qual typ + , fixity + ] fieldPart | not hasArgDocs = [] - | otherwise = [ subFields Nothing qual (ppSubSigLike unicode qual (unLoc typ) - argDocs [] (dcolon unicode) - emptyCtxt) ] + | otherwise = + [ subFields + Nothing + qual + ( ppSubSigLike + unicode + qual + (unLoc typ) + argDocs + [] + (dcolon unicode) + emptyCtxt + ) + ] emptyCtxt = patSigContext typ - -- | Print the LHS of a data\/newtype declaration. -- Currently doesn't handle 'data instance' decls or kind signatures ppDataHeader :: Bool -> TyClDecl DocNameI -> Unicode -> Qualification -> Html -ppDataHeader summary (DataDecl { tcdDataDefn = - HsDataDefn { dd_cons = cons - , dd_ctxt = ctxt - , dd_kindSig = ks } - , tcdLName = L _ name - , tcdTyVars = tvs }) - unicode qual - = -- newtype or data - (case cons of - { NewTypeCon _ -> keyword "newtype" - ; DataTypeCons False _ -> keyword "data" - ; DataTypeCons True _ -> keyword "type" <+> keyword "data" - }) - <+> - -- context - ppLContext ctxt unicode qual HideEmptyContexts <+> - -- T a b c ..., or a :+: b - ppAppDocNameTyVarBndrs summary unicode qual name (hsQTvExplicit tvs) - <+> case ks of - Nothing -> mempty - Just (L _ x) -> dcolon unicode <+> ppKind unicode qual x - +ppDataHeader + summary + ( DataDecl + { tcdDataDefn = + HsDataDefn + { dd_cons = cons + , dd_ctxt = ctxt + , dd_kindSig = ks + } + , tcdLName = L _ name + , tcdTyVars = tvs + } + ) + unicode + qual = + -- newtype or data + ( case cons of + NewTypeCon _ -> keyword "newtype" + DataTypeCons False _ -> keyword "data" + DataTypeCons True _ -> keyword "type" <+> keyword "data" + ) + <+> + -- context + ppLContext ctxt unicode qual HideEmptyContexts + <+> + -- T a b c ..., or a :+: b + ppAppDocNameTyVarBndrs summary unicode qual name (hsQTvExplicit tvs) + <+> case ks of + Nothing -> mempty + Just (L _ x) -> dcolon unicode <+> ppKind unicode qual x ppDataHeader _ _ _ _ = error "ppDataHeader: illegal argument" -------------------------------------------------------------------------------- + -- * Types and contexts --------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- ppBang :: HsSrcBang -> Html ppBang (HsSrcBang _ _ SrcStrict) = toHtml "!" -ppBang (HsSrcBang _ _ SrcLazy) = toHtml "~" -ppBang _ = noHtml - +ppBang (HsSrcBang _ _ SrcLazy) = toHtml "~" +ppBang _ = noHtml tupleParens :: HsTupleSort -> [Html] -> Html tupleParens HsUnboxedTuple = ubxParenList -tupleParens _ = parenList - +tupleParens _ = parenList sumParens :: [Html] -> Html sumParens = ubxSumList -------------------------------------------------------------------------------- + -- * Rendering of HsType + -------------------------------------------------------------------------------- ppLType, ppLParendType, ppLFunLhType :: Unicode -> Qualification -> HideEmptyContexts -> LHsType DocNameI -> Html -ppLType unicode qual emptyCtxts y = ppType unicode qual emptyCtxts (unLoc y) +ppLType unicode qual emptyCtxts y = ppType unicode qual emptyCtxts (unLoc y) ppLParendType unicode qual emptyCtxts y = ppParendType unicode qual emptyCtxts (unLoc y) -ppLFunLhType unicode qual emptyCtxts y = ppFunLhType unicode qual emptyCtxts (unLoc y) +ppLFunLhType unicode qual emptyCtxts y = ppFunLhType unicode qual emptyCtxts (unLoc y) -ppLSigType :: Unicode -> Qualification -> HideEmptyContexts -> LHsSigType DocNameI -> Html +ppLSigType :: Unicode -> Qualification -> HideEmptyContexts -> LHsSigType DocNameI -> Html ppLSigType unicode qual emptyCtxts y = ppSigType unicode qual emptyCtxts (unLoc y) ppCtxType :: Unicode -> Qualification -> HsType DocNameI -> Html ppCtxType unicode qual ty = ppr_mono_ty (reparenTypePrec PREC_CTX ty) unicode qual HideEmptyContexts ppType, ppParendType, ppFunLhType :: Unicode -> Qualification -> HideEmptyContexts -> HsType DocNameI -> Html -ppType unicode qual emptyCtxts ty = ppr_mono_ty (reparenTypePrec PREC_TOP ty) unicode qual emptyCtxts +ppType unicode qual emptyCtxts ty = ppr_mono_ty (reparenTypePrec PREC_TOP ty) unicode qual emptyCtxts ppParendType unicode qual emptyCtxts ty = ppr_mono_ty (reparenTypePrec PREC_CON ty) unicode qual emptyCtxts -ppFunLhType unicode qual emptyCtxts ty = ppr_mono_ty (reparenTypePrec PREC_FUN ty) unicode qual emptyCtxts +ppFunLhType unicode qual emptyCtxts ty = ppr_mono_ty (reparenTypePrec PREC_FUN ty) unicode qual emptyCtxts -ppSigType :: Unicode -> Qualification -> HideEmptyContexts -> HsSigType DocNameI -> Html +ppSigType :: Unicode -> Qualification -> HideEmptyContexts -> HsSigType DocNameI -> Html ppSigType unicode qual emptyCtxts sig_ty = ppr_sig_ty (reparenSigType sig_ty) unicode qual emptyCtxts ppLHsTypeArg :: Unicode -> Qualification -> HideEmptyContexts -> LHsTypeArg DocNameI -> Html @@ -1151,32 +1679,44 @@ class RenderableBndrFlag flag where ppHsTyVarBndr :: Unicode -> Qualification -> HsTyVarBndr flag DocNameI -> Html instance RenderableBndrFlag () where - ppHsTyVarBndr _ qual (UserTyVar _ _ (L _ name)) = - ppDocName qual Raw False name + ppHsTyVarBndr _ qual (UserTyVar _ _ (L _ name)) = + ppDocName qual Raw False name ppHsTyVarBndr unicode qual (KindedTyVar _ _ name kind) = - parens (ppDocName qual Raw False (unL name) <+> dcolon unicode <+> - ppLKind unicode qual kind) + parens + ( ppDocName qual Raw False (unL name) + <+> dcolon unicode + <+> ppLKind unicode qual kind + ) instance RenderableBndrFlag Specificity where - ppHsTyVarBndr _ qual (UserTyVar _ SpecifiedSpec (L _ name)) = - ppDocName qual Raw False name - ppHsTyVarBndr _ qual (UserTyVar _ InferredSpec (L _ name)) = - braces $ ppDocName qual Raw False name + ppHsTyVarBndr _ qual (UserTyVar _ SpecifiedSpec (L _ name)) = + ppDocName qual Raw False name + ppHsTyVarBndr _ qual (UserTyVar _ InferredSpec (L _ name)) = + braces $ ppDocName qual Raw False name ppHsTyVarBndr unicode qual (KindedTyVar _ SpecifiedSpec name kind) = - parens (ppDocName qual Raw False (unL name) <+> dcolon unicode <+> - ppLKind unicode qual kind) + parens + ( ppDocName qual Raw False (unL name) + <+> dcolon unicode + <+> ppLKind unicode qual kind + ) ppHsTyVarBndr unicode qual (KindedTyVar _ InferredSpec name kind) = - braces (ppDocName qual Raw False (unL name) <+> dcolon unicode <+> - ppLKind unicode qual kind) + braces + ( ppDocName qual Raw False (unL name) + <+> dcolon unicode + <+> ppLKind unicode qual kind + ) instance RenderableBndrFlag (HsBndrVis DocNameI) where ppHsTyVarBndr _ qual (UserTyVar _ bvis (L _ name)) = - ppHsBndrVis bvis $ + ppHsBndrVis bvis $ ppDocName qual Raw False name ppHsTyVarBndr unicode qual (KindedTyVar _ bvis name kind) = - ppHsBndrVis bvis $ - parens (ppDocName qual Raw False (unL name) <+> dcolon unicode <+> - ppLKind unicode qual kind) + ppHsBndrVis bvis $ + parens + ( ppDocName qual Raw False (unL name) + <+> dcolon unicode + <+> ppLKind unicode qual kind + ) ppHsBndrVis :: HsBndrVis DocNameI -> Html -> Html ppHsBndrVis (HsBndrRequired _) d = d @@ -1189,8 +1729,9 @@ ppKind :: Unicode -> Qualification -> HsKind DocNameI -> Html ppKind unicode qual ki = ppr_mono_ty (reparenTypePrec PREC_TOP ki) unicode qual HideEmptyContexts patSigContext :: LHsSigType DocNameI -> HideEmptyContexts -patSigContext sig_typ | hasNonEmptyContext typ && isFirstContextEmpty typ = ShowEmptyToplevelContexts - | otherwise = HideEmptyContexts +patSigContext sig_typ + | hasNonEmptyContext typ && isFirstContextEmpty typ = ShowEmptyToplevelContexts + | otherwise = HideEmptyContexts where typ = sig_body (unLoc sig_typ) @@ -1198,24 +1739,27 @@ patSigContext sig_typ | hasNonEmptyContext typ && isFirstContextEmpty typ = Sho case unLoc t of HsForAllTy _ _ s -> hasNonEmptyContext s HsQualTy _ cxt s -> if null (unLoc cxt) then hasNonEmptyContext s else True - HsFunTy _ _ _ s -> hasNonEmptyContext s + HsFunTy _ _ _ s -> hasNonEmptyContext s _ -> False isFirstContextEmpty t = case unLoc t of HsForAllTy _ _ s -> isFirstContextEmpty s HsQualTy _ cxt _ -> null (unLoc cxt) - HsFunTy _ _ _ s -> isFirstContextEmpty s + HsFunTy _ _ _ s -> isFirstContextEmpty s _ -> False - -- | Pretty-print a pattern signature (all this does over 'ppLType' is slot in -- the right 'HideEmptyContext' value) ppPatSigType :: Unicode -> Qualification -> LHsSigType DocNameI -> Html ppPatSigType unicode qual typ = let emptyCtxts = patSigContext typ in ppLSigType unicode qual emptyCtxts typ -ppHsOuterTyVarBndrs :: RenderableBndrFlag flag - => Unicode -> Qualification -> HsOuterTyVarBndrs flag DocNameI -> Html +ppHsOuterTyVarBndrs + :: RenderableBndrFlag flag + => Unicode + -> Qualification + -> HsOuterTyVarBndrs flag DocNameI + -> Html ppHsOuterTyVarBndrs unicode qual outer_bndrs = case outer_bndrs of HsOuterImplicit{} -> noHtml HsOuterExplicit{hso_bndrs = bndrs} -> @@ -1223,31 +1767,28 @@ ppHsOuterTyVarBndrs unicode qual outer_bndrs = case outer_bndrs of ppForAllPart :: Unicode -> Qualification -> HsForAllTelescope DocNameI -> Html ppForAllPart unicode qual tele = case tele of - HsForAllVis { hsf_vis_bndrs = bndrs } -> - hsep (forallSymbol unicode : ppTyVars unicode qual bndrs) +++ - spaceHtml +++ arrow unicode - HsForAllInvis { hsf_invis_bndrs = bndrs } -> + HsForAllVis{hsf_vis_bndrs = bndrs} -> + hsep (forallSymbol unicode : ppTyVars unicode qual bndrs) + +++ spaceHtml + +++ arrow unicode + HsForAllInvis{hsf_invis_bndrs = bndrs} -> hsep (forallSymbol unicode : ppTyVars unicode qual bndrs) +++ dot ppr_sig_ty :: HsSigType DocNameI -> Unicode -> Qualification -> HideEmptyContexts -> Html -ppr_sig_ty (HsSig { sig_bndrs = outer_bndrs, sig_body = ltype }) unicode qual emptyCtxts - = ppHsOuterTyVarBndrs unicode qual outer_bndrs <+> ppr_mono_lty ltype unicode qual emptyCtxts +ppr_sig_ty (HsSig{sig_bndrs = outer_bndrs, sig_body = ltype}) unicode qual emptyCtxts = + ppHsOuterTyVarBndrs unicode qual outer_bndrs <+> ppr_mono_lty ltype unicode qual emptyCtxts ppr_mono_lty :: LHsType DocNameI -> Unicode -> Qualification -> HideEmptyContexts -> Html ppr_mono_lty ty = ppr_mono_ty (unLoc ty) - ppr_mono_ty :: HsType DocNameI -> Unicode -> Qualification -> HideEmptyContexts -> Html -ppr_mono_ty (HsForAllTy _ tele ty) unicode qual emptyCtxts - = ppForAllPart unicode qual tele <+> ppr_mono_lty ty unicode qual emptyCtxts - -ppr_mono_ty (HsQualTy _ ctxt ty) unicode qual emptyCtxts - = ppLContext (Just ctxt) unicode qual emptyCtxts <+> ppr_mono_lty ty unicode qual emptyCtxts - +ppr_mono_ty (HsForAllTy _ tele ty) unicode qual emptyCtxts = + ppForAllPart unicode qual tele <+> ppr_mono_lty ty unicode qual emptyCtxts +ppr_mono_ty (HsQualTy _ ctxt ty) unicode qual emptyCtxts = + ppLContext (Just ctxt) unicode qual emptyCtxts <+> ppr_mono_lty ty unicode qual emptyCtxts -- UnicodeSyntax alternatives ppr_mono_ty (HsTyVar _ _ (L _ name)) True _ _ | getOccString (getName name) == "(->)" = toHtml "(→)" - ppr_mono_ty (HsBangTy _ b ty) u q _ = ppBang b +++ ppLParendType u q HideEmptyContexts ty ppr_mono_ty (HsTyVar _ prom (L _ name)) _ q _ @@ -1256,58 +1797,58 @@ ppr_mono_ty (HsTyVar _ prom (L _ name)) _ q _ ppr_mono_ty (HsStarTy _ isUni) u _ _ = toHtml (if u || isUni then "★" else "*") ppr_mono_ty (HsFunTy _ mult ty1 ty2) u q e = - hsep [ ppr_mono_lty ty1 u q HideEmptyContexts - , arr <+> ppr_mono_lty ty2 u q e - ] - where arr = case mult of - HsLinearArrow _ -> lollipop u - HsUnrestrictedArrow _ -> arrow u - HsExplicitMult _ m -> multAnnotation <> ppr_mono_lty m u q e <+> arrow u - + hsep + [ ppr_mono_lty ty1 u q HideEmptyContexts + , arr <+> ppr_mono_lty ty2 u q e + ] + where + arr = case mult of + HsLinearArrow _ -> lollipop u + HsUnrestrictedArrow _ -> arrow u + HsExplicitMult _ m -> multAnnotation <> ppr_mono_lty m u q e <+> arrow u ppr_mono_ty (HsTupleTy _ con tys) u q _ = tupleParens con (map (ppLType u q HideEmptyContexts) tys) ppr_mono_ty (HsSumTy _ tys) u q _ = sumParens (map (ppLType u q HideEmptyContexts) tys) ppr_mono_ty (HsKindSig _ ty kind) u q e = ppr_mono_lty ty u q e <+> dcolon u <+> ppLKind u q kind -ppr_mono_ty (HsListTy _ ty) u q _ = brackets (ppr_mono_lty ty u q HideEmptyContexts) +ppr_mono_ty (HsListTy _ ty) u q _ = brackets (ppr_mono_lty ty u q HideEmptyContexts) ppr_mono_ty (HsIParamTy _ (L _ n) ty) u q _ = ppIPName n <+> dcolon u <+> ppr_mono_lty ty u q HideEmptyContexts ppr_mono_ty (HsSpliceTy v _) _ _ _ = dataConCantHappen v -ppr_mono_ty (HsRecTy {}) _ _ _ = toHtml "{..}" - -- Can now legally occur in ConDeclGADT, the output here is to provide a - -- placeholder in the signature, which is followed by the field - -- declarations. -ppr_mono_ty (XHsType {}) _ _ _ = error "ppr_mono_ty HsCoreTy" +ppr_mono_ty (HsRecTy{}) _ _ _ = toHtml "{..}" +-- Can now legally occur in ConDeclGADT, the output here is to provide a +-- placeholder in the signature, which is followed by the field +-- declarations. +ppr_mono_ty (XHsType{}) _ _ _ = error "ppr_mono_ty HsCoreTy" ppr_mono_ty (HsExplicitListTy _ IsPromoted tys) u q _ = promoQuote $ brackets $ hsep $ punctuate comma $ map (ppLType u q HideEmptyContexts) tys ppr_mono_ty (HsExplicitListTy _ NotPromoted tys) u q _ = brackets $ hsep $ punctuate comma $ map (ppLType u q HideEmptyContexts) tys ppr_mono_ty (HsExplicitTupleTy _ tys) u q _ = promoQuote $ parenList $ map (ppLType u q HideEmptyContexts) tys - -ppr_mono_ty (HsAppTy _ fun_ty arg_ty) unicode qual _ - = hsep [ ppr_mono_lty fun_ty unicode qual HideEmptyContexts - , ppr_mono_lty arg_ty unicode qual HideEmptyContexts ] - -ppr_mono_ty (HsAppKindTy _ fun_ty arg_ki) unicode qual _ - = hsep [ppr_mono_lty fun_ty unicode qual HideEmptyContexts - , atSign <> ppr_mono_lty arg_ki unicode qual HideEmptyContexts] - -ppr_mono_ty (HsOpTy _ prom ty1 op ty2) unicode qual _ - = ppr_mono_lty ty1 unicode qual HideEmptyContexts <+> ppr_op_prom <+> ppr_mono_lty ty2 unicode qual HideEmptyContexts +ppr_mono_ty (HsAppTy _ fun_ty arg_ty) unicode qual _ = + hsep + [ ppr_mono_lty fun_ty unicode qual HideEmptyContexts + , ppr_mono_lty arg_ty unicode qual HideEmptyContexts + ] +ppr_mono_ty (HsAppKindTy _ fun_ty arg_ki) unicode qual _ = + hsep + [ ppr_mono_lty fun_ty unicode qual HideEmptyContexts + , atSign <> ppr_mono_lty arg_ki unicode qual HideEmptyContexts + ] +ppr_mono_ty (HsOpTy _ prom ty1 op ty2) unicode qual _ = + ppr_mono_lty ty1 unicode qual HideEmptyContexts <+> ppr_op_prom <+> ppr_mono_lty ty2 unicode qual HideEmptyContexts where ppr_op_prom - | isPromoted prom - = promoQuote ppr_op - | otherwise - = ppr_op + | isPromoted prom = + promoQuote ppr_op + | otherwise = + ppr_op ppr_op = ppLDocName qual Infix op - -ppr_mono_ty (HsParTy _ ty) unicode qual emptyCtxts - = parens (ppr_mono_lty ty unicode qual emptyCtxts) +ppr_mono_ty (HsParTy _ ty) unicode qual emptyCtxts = + parens (ppr_mono_lty ty unicode qual emptyCtxts) -- = parens (ppr_mono_lty ctxt_prec ty unicode qual emptyCtxts) -ppr_mono_ty (HsDocTy _ ty _) unicode qual emptyCtxts - = ppr_mono_lty ty unicode qual emptyCtxts - +ppr_mono_ty (HsDocTy _ ty _) unicode qual emptyCtxts = + ppr_mono_lty ty unicode qual emptyCtxts ppr_mono_ty (HsWildCardTy _) _ _ _ = char '_' ppr_mono_ty (HsTyLit _ n) _ _ _ = ppr_tylit n diff --git a/haddock-api/src/Haddock/Backends/Xhtml/DocMarkup.hs b/haddock-api/src/Haddock/Backends/Xhtml/DocMarkup.hs index d3282ef69b..1445d09dca 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml/DocMarkup.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml/DocMarkup.hs @@ -1,4 +1,7 @@ ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.Backends.Html.DocMarkup -- Copyright : (c) Simon Marlow 2003-2006, @@ -9,74 +12,83 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------ -module Haddock.Backends.Xhtml.DocMarkup ( - docToHtml, - rdrDocToHtml, - origDocToHtml, - docToHtmlNoAnchors, - - docElement, docSection, docSection_, -) where +module Haddock.Backends.Xhtml.DocMarkup + ( docToHtml + , rdrDocToHtml + , origDocToHtml + , docToHtmlNoAnchors + , docElement + , docSection + , docSection_ + ) where import Data.List (intersperse) import Documentation.Haddock.Markup import Haddock.Backends.Xhtml.Names import Haddock.Backends.Xhtml.Utils +import Haddock.Doc + ( combineDocumentation + , emptyMetaDoc + , metaConcat + , metaDocAppend + ) import Haddock.Types import Haddock.Utils -import Haddock.Doc (combineDocumentation, emptyMetaDoc, - metaDocAppend, metaConcat) -import Text.XHtml hiding ( name, p, quote ) import Data.Maybe (fromMaybe) +import Text.XHtml hiding (name, p, quote) import GHC hiding (anchor) import GHC.Types.Name - -parHtmlMarkup :: Qualification -> Bool - -> (Bool -> a -> Html) -> DocMarkup a Html -parHtmlMarkup qual insertAnchors ppId = Markup { - markupEmpty = noHtml, - markupString = toHtml, - markupParagraph = paragraph, - markupAppend = (+++), - markupIdentifier = thecode . ppId insertAnchors, - markupIdentifierUnchecked = thecode . ppUncheckedLink qual, - markupModule = \(ModLink m lbl) -> - let (mdl,ref) = break (=='#') m - -- Accommodate for old style - -- foo\#bar anchors - mdl' = case reverse mdl of - '\\':_ -> init mdl - _ -> mdl - in ppModuleRef lbl (mkModuleName mdl') ref, - markupWarning = thediv ! [theclass "warning"], - markupEmphasis = emphasize, - markupBold = strong, - markupMonospaced = thecode, - markupUnorderedList = unordList, - markupOrderedList = makeOrdList, - markupDefList = defList, - markupCodeBlock = pre, - markupHyperlink = \(Hyperlink url mLabel) - -> if insertAnchors - then anchor ! [href url] - << fromMaybe (toHtml url) mLabel - else fromMaybe (toHtml url) mLabel, - markupAName = \aname - -> if insertAnchors - then namedAnchor aname << "" - else noHtml, - markupPic = \(Picture uri t) -> image ! ([src uri] ++ fromMaybe [] (return . title <$> t)), - markupMathInline = \mathjax -> thespan ! [theclass "mathjax"] << toHtml ("\\(" ++ mathjax ++ "\\)"), - markupMathDisplay = \mathjax -> thespan ! [theclass "mathjax"] << toHtml ("\\[" ++ mathjax ++ "\\]"), - markupProperty = pre . toHtml, - markupExample = examplesToHtml, - markupHeader = \(Header l t) -> makeHeader l t, - markupTable = \(Table h r) -> makeTable h r - } +parHtmlMarkup + :: Qualification + -> Bool + -> (Bool -> a -> Html) + -> DocMarkup a Html +parHtmlMarkup qual insertAnchors ppId = + Markup + { markupEmpty = noHtml + , markupString = toHtml + , markupParagraph = paragraph + , markupAppend = (+++) + , markupIdentifier = thecode . ppId insertAnchors + , markupIdentifierUnchecked = thecode . ppUncheckedLink qual + , markupModule = \(ModLink m lbl) -> + let (mdl, ref) = break (== '#') m + -- Accommodate for old style + -- foo\#bar anchors + mdl' = case reverse mdl of + '\\' : _ -> init mdl + _ -> mdl + in ppModuleRef lbl (mkModuleName mdl') ref + , markupWarning = thediv ! [theclass "warning"] + , markupEmphasis = emphasize + , markupBold = strong + , markupMonospaced = thecode + , markupUnorderedList = unordList + , markupOrderedList = makeOrdList + , markupDefList = defList + , markupCodeBlock = pre + , markupHyperlink = \(Hyperlink url mLabel) -> + if insertAnchors + then + anchor + ! [href url] + << fromMaybe (toHtml url) mLabel + else fromMaybe (toHtml url) mLabel + , markupAName = \aname -> + if insertAnchors + then namedAnchor aname << "" + else noHtml + , markupPic = \(Picture uri t) -> image ! ([src uri] ++ fromMaybe [] (return . title <$> t)) + , markupMathInline = \mathjax -> thespan ! [theclass "mathjax"] << toHtml ("\\(" ++ mathjax ++ "\\)") + , markupMathDisplay = \mathjax -> thespan ! [theclass "mathjax"] << toHtml ("\\[" ++ mathjax ++ "\\]") + , markupProperty = pre . toHtml + , markupExample = examplesToHtml + , markupHeader = \(Header l t) -> makeHeader l t + , markupTable = \(Table h r) -> makeTable h r + } where makeHeader :: Int -> Html -> Html makeHeader 1 mkup = h1 mkup @@ -90,8 +102,9 @@ parHtmlMarkup qual insertAnchors ppId = Markup { makeTable :: [TableRow Html] -> [TableRow Html] -> Html makeTable hs bs = table (concatHtml (hs' ++ bs')) where - hs' | null hs = [] - | otherwise = [thead (concatHtml (map (makeTableRow th) hs))] + hs' + | null hs = [] + | otherwise = [thead (concatHtml (map (makeTableRow th) hs))] bs' = [tbody (concatHtml (map (makeTableRow td) bs))] @@ -101,8 +114,8 @@ parHtmlMarkup qual insertAnchors ppId = Markup { makeTableCell :: (Html -> Html) -> TableCell Html -> Html makeTableCell thr (TableCell i j c) = thr c ! (i' ++ j') where - i' = if i == 1 then [] else [ colspan i ] - j' = if j == 1 then [] else [ rowspan j ] + i' = if i == 1 then [] else [colspan i] + j' = if j == 1 then [] else [rowspan j] examplesToHtml l = pre (concatHtml $ map exampleToHtml l) ! [theclass "screen"] @@ -120,54 +133,59 @@ parHtmlMarkup qual insertAnchors ppId = Markup { -- elements. This is effectively a hack to prevent the 'Doc' type -- from changing if it is possible to recover the layout information -- we won't need after the fact. -data Hack a id = - UntouchedDoc (MetaDoc a id) +data Hack a id + = UntouchedDoc (MetaDoc a id) | CollapsingHeader (Header (DocH a id)) (MetaDoc a id) Int (Maybe String) | HackAppend (Hack a id) (Hack a id) - deriving Eq + deriving (Eq) -- | Group things under bold 'DocHeader's together. -toHack :: Int -- ^ Counter for header IDs which serves to assign - -- unique identifiers within the comment scope - -> Maybe String - -- ^ It is not enough to have unique identifier within the - -- scope of the comment: if two different comments have the - -- same ID for headers, the collapse/expand behaviour will act - -- on them both. This serves to make each header a little bit - -- more unique. As we can't export things with the same names, - -- this should work more or less fine: it is in fact the - -- implicit assumption the collapse/expand mechanism makes for - -- things like ‘Instances’ boxes. - -> [MetaDoc a id] -> Hack a id +toHack + :: Int + -- ^ Counter for header IDs which serves to assign + -- unique identifiers within the comment scope + -> Maybe String + -- ^ It is not enough to have unique identifier within the + -- scope of the comment: if two different comments have the + -- same ID for headers, the collapse/expand behaviour will act + -- on them both. This serves to make each header a little bit + -- more unique. As we can't export things with the same names, + -- this should work more or less fine: it is in fact the + -- implicit assumption the collapse/expand mechanism makes for + -- things like ‘Instances’ boxes. + -> [MetaDoc a id] + -> Hack a id toHack _ _ [] = UntouchedDoc emptyMetaDoc toHack _ _ [x] = UntouchedDoc x -toHack n nm (MetaDoc { _doc = DocHeader (Header l (DocBold x)) }:xs) = - let -- Header with dropped bold - h = Header l x - -- Predicate for takeWhile, grab everything including ‘smaller’ - -- headers - p (MetaDoc { _doc = DocHeader (Header l' _) }) = l' > l - p _ = True - -- Stuff ‘under’ this header - r = takeWhile p xs - -- Everything else that didn't make it under - r' = drop (length r) xs - app y [] = y - app y ys = HackAppend y (toHack (n + 1) nm ys) - in case r of +toHack n nm (MetaDoc{_doc = DocHeader (Header l (DocBold x))} : xs) = + let + -- Header with dropped bold + h = Header l x + -- Predicate for takeWhile, grab everything including ‘smaller’ + -- headers + p (MetaDoc{_doc = DocHeader (Header l' _)}) = l' > l + p _ = True + -- Stuff ‘under’ this header + r = takeWhile p xs + -- Everything else that didn't make it under + r' = drop (length r) xs + app y [] = y + app y ys = HackAppend y (toHack (n + 1) nm ys) + in + case r of -- No content under this header [] -> CollapsingHeader h emptyMetaDoc n nm `app` r' -- We got something out, stitch it back together into one chunk - y:ys -> CollapsingHeader h (foldl metaDocAppend y ys) n nm `app` r' -toHack n nm (x:xs) = HackAppend (UntouchedDoc x) (toHack n nm xs) + y : ys -> CollapsingHeader h (foldl metaDocAppend y ys) n nm `app` r' +toHack n nm (x : xs) = HackAppend (UntouchedDoc x) (toHack n nm xs) -- | Remove ‘top-level’ 'DocAppend's turning them into a flat list. -- This lends itself much better to processing things in order user -- might look at them, such as in 'toHack'. flatten :: MetaDoc a id -> [MetaDoc a id] -flatten MetaDoc { _meta = m, _doc = DocAppend x y } = - let f z = MetaDoc { _meta = m, _doc = z } - in flatten (f x) ++ flatten (f y) +flatten MetaDoc{_meta = m, _doc = DocAppend x y} = + let f z = MetaDoc{_meta = m, _doc = z} + in flatten (f x) ++ flatten (f y) flatten x = [x] -- | Generate the markup needed for collapse to happen. For @@ -178,31 +196,34 @@ flatten x = [x] hackMarkup :: DocMarkup id Html -> Maybe Package -> Hack (Wrap (ModuleName, OccName)) id -> Html hackMarkup fmt' currPkg h' = let (html, ms) = hackMarkup' fmt' h' - in html +++ renderMeta fmt' currPkg (metaConcat ms) + in html +++ renderMeta fmt' currPkg (metaConcat ms) where - hackMarkup' :: DocMarkup id Html -> Hack (Wrap (ModuleName, OccName)) id - -> (Html, [Meta]) + hackMarkup' + :: DocMarkup id Html + -> Hack (Wrap (ModuleName, OccName)) id + -> (Html, [Meta]) hackMarkup' fmt h = case h of UntouchedDoc d -> (markup fmt $ _doc d, [_meta d]) CollapsingHeader (Header lvl titl) par n nm -> let id_ = makeAnchorId $ "ch:" ++ fromMaybe "noid:" nm ++ show n col' = collapseControl id_ "subheading" - summary = thesummary ! [ theclass "hide-when-js-enabled" ] << "Expand" + summary = thesummary ! [theclass "hide-when-js-enabled"] << "Expand" instTable contents = collapseDetails id_ DetailsClosed (summary +++ contents) - lvs = zip [1 .. ] [h1, h2, h3, h4, h5, h6] + lvs = zip [1 ..] [h1, h2, h3, h4, h5, h6] getHeader = fromMaybe caption (lookup lvl lvs) subCaption = getHeader ! col' << markup fmt titl - in ((subCaption +++) . instTable $ markup fmt (_doc par), [_meta par]) - HackAppend d d' -> let (x, m) = hackMarkup' fmt d - (y, m') = hackMarkup' fmt d' - in (markupAppend fmt x y, m ++ m') + in ((subCaption +++) . instTable $ markup fmt (_doc par), [_meta par]) + HackAppend d d' -> + let (x, m) = hackMarkup' fmt d + (y, m') = hackMarkup' fmt d' + in (markupAppend fmt x y, m ++ m') renderMeta :: DocMarkup id Html -> Maybe Package -> Meta -> Html renderMeta fmt currPkg m = maybe noHtml (renderMetaSince fmt currPkg) (_metaSince m) renderMetaSince :: DocMarkup id Html -> Maybe Package -> MetaSince -> Html -renderMetaSince fmt currPkg (MetaSince { sincePackage = pkg, sinceVersion = ver }) = +renderMetaSince fmt currPkg (MetaSince{sincePackage = pkg, sinceVersion = ver}) = markupParagraph fmt . markupEmphasis fmt . toHtml $ "Since: " ++ formatPkgMaybe pkg ++ formatVersion ver where @@ -213,39 +234,52 @@ renderMetaSince fmt currPkg (MetaSince { sincePackage = pkg, sinceVersion = ver -- | Goes through 'hackMarkup' to generate the 'Html' rather than -- skipping straight to 'markup': this allows us to employ XHtml -- specific hacks to the tree first. -markupHacked :: DocMarkup (Wrap id) Html - -> Maybe Package -- this package - -> Maybe String - -> MDoc id - -> Html +markupHacked + :: DocMarkup (Wrap id) Html + -> Maybe Package -- this package + -> Maybe String + -> MDoc id + -> Html markupHacked fmt currPkg n = hackMarkup fmt currPkg . toHack 0 n . flatten -- If the doc is a single paragraph, don't surround it with

    (this causes -- ugly extra whitespace with some browsers). FIXME: Does this still apply? -docToHtml :: Maybe String -- ^ Name of the thing this doc is for. See - -- comments on 'toHack' for details. - -> Maybe Package -- ^ Current package - -> Qualification -> MDoc DocName -> Html +docToHtml + :: Maybe String + -- ^ Name of the thing this doc is for. See + -- comments on 'toHack' for details. + -> Maybe Package + -- ^ Current package + -> Qualification + -> MDoc DocName + -> Html docToHtml n pkg qual = markupHacked fmt pkg n . cleanup - where fmt = parHtmlMarkup qual True (ppWrappedDocName qual Raw) + where + fmt = parHtmlMarkup qual True (ppWrappedDocName qual Raw) -- | Same as 'docToHtml' but it doesn't insert the 'anchor' element -- in links. This is used to generate the Contents box elements. -docToHtmlNoAnchors :: Maybe String -- ^ See 'toHack' - -> Maybe Package -- ^ Current package - -> Qualification -> MDoc DocName -> Html +docToHtmlNoAnchors + :: Maybe String + -- ^ See 'toHack' + -> Maybe Package + -- ^ Current package + -> Qualification + -> MDoc DocName + -> Html docToHtmlNoAnchors n pkg qual = markupHacked fmt pkg n . cleanup - where fmt = parHtmlMarkup qual False (ppWrappedDocName qual Raw) + where + fmt = parHtmlMarkup qual False (ppWrappedDocName qual Raw) origDocToHtml :: Maybe Package -> Qualification -> MDoc Name -> Html origDocToHtml pkg qual = markupHacked fmt pkg Nothing . cleanup - where fmt = parHtmlMarkup qual True (const (ppWrappedName Raw)) - + where + fmt = parHtmlMarkup qual True (const (ppWrappedName Raw)) rdrDocToHtml :: Maybe Package -> Qualification -> MDoc RdrName -> Html rdrDocToHtml pkg qual = markupHacked fmt pkg Nothing . cleanup - where fmt = parHtmlMarkup qual True (const (ppRdrName . unwrap)) - + where + fmt = parHtmlMarkup qual True (const (ppRdrName . unwrap)) docElement :: (Html -> Html) -> Html -> Html docElement el content_ = @@ -253,21 +287,28 @@ docElement el content_ = then el ! [theclass "doc empty"] << spaceHtml else el ! [theclass "doc"] << content_ - -docSection :: Maybe Name -- ^ Name of the thing this doc is for - -> Maybe Package -- ^ Current package - -> Qualification -> Documentation DocName -> Html +docSection + :: Maybe Name + -- ^ Name of the thing this doc is for + -> Maybe Package + -- ^ Current package + -> Qualification + -> Documentation DocName + -> Html docSection n pkg qual = maybe noHtml (docSection_ n pkg qual) . combineDocumentation - -docSection_ :: Maybe Name -- ^ Name of the thing this doc is for - -> Maybe Package -- ^ Current package - -> Qualification -> MDoc DocName -> Html +docSection_ + :: Maybe Name + -- ^ Name of the thing this doc is for + -> Maybe Package + -- ^ Current package + -> Qualification + -> MDoc DocName + -> Html docSection_ n pkg qual = (docElement thediv <<) . docToHtml (getOccString <$> n) pkg qual - cleanup :: MDoc a -> MDoc a cleanup = overDoc (markup fmtUnParagraphLists) where @@ -278,10 +319,11 @@ cleanup = overDoc (markup fmtUnParagraphLists) -- here. We don't do this in code blocks as it eliminates line breaks. unParagraph :: Doc a -> Doc a unParagraph (DocParagraph d) = d - unParagraph doc = doc + unParagraph doc = doc fmtUnParagraphLists :: DocMarkup (Wrap a) (Doc a) - fmtUnParagraphLists = idMarkup { - markupUnorderedList = DocUnorderedList . map unParagraph, - markupOrderedList = DocOrderedList . map (\(index, a) -> (index, unParagraph a)) - } + fmtUnParagraphLists = + idMarkup + { markupUnorderedList = DocUnorderedList . map unParagraph + , markupOrderedList = DocOrderedList . map (\(index, a) -> (index, unParagraph a)) + } diff --git a/haddock-api/src/Haddock/Backends/Xhtml/Layout.hs b/haddock-api/src/Haddock/Backends/Xhtml/Layout.hs index 41afe5a0d4..c141584a99 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml/Layout.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml/Layout.hs @@ -1,4 +1,7 @@ ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.Backends.Html.Layout -- Copyright : (c) Simon Marlow 2003-2006, @@ -9,163 +12,185 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------ -module Haddock.Backends.Xhtml.Layout ( - miniBody, - - divPackageHeader, divContent, divModuleHeader, divFooter, - divTableOfContents, divDescription, divSynopsis, divInterface, - divIndex, divAlphabet, divPackageList, divModuleList, divContentsList, - - sectionName, - nonEmptySectionName, - - shortDeclList, - shortSubDecls, - - divTopDecl, - - SubDecl, - subArguments, - subAssociatedTypes, - subConstructors, - subPatterns, - subEquations, - subFields, - subInstances, subOrphanInstances, - subInstHead, subInstDetails, subFamInstDetails, - subMethods, - subDefaults, - subMinimal, - subTableSrc, - - topDeclElem, declElem, -) where +module Haddock.Backends.Xhtml.Layout + ( miniBody + , divPackageHeader + , divContent + , divModuleHeader + , divFooter + , divTableOfContents + , divDescription + , divSynopsis + , divInterface + , divIndex + , divAlphabet + , divPackageList + , divModuleList + , divContentsList + , sectionName + , nonEmptySectionName + , shortDeclList + , shortSubDecls + , divTopDecl + , SubDecl + , subArguments + , subAssociatedTypes + , subConstructors + , subPatterns + , subEquations + , subFields + , subInstances + , subOrphanInstances + , subInstHead + , subInstDetails + , subFamInstDetails + , subMethods + , subDefaults + , subMinimal + , subTableSrc + , topDeclElem + , declElem + ) where +import qualified Data.Map as Map +import Data.Maybe (fromMaybe) import Haddock.Backends.Xhtml.DocMarkup import Haddock.Backends.Xhtml.Types import Haddock.Backends.Xhtml.Utils import Haddock.Types import Haddock.Utils (makeAnchorId, nameAnchorId) -import qualified Data.Map as Map -import Text.XHtml hiding ( name, title, quote ) -import Data.Maybe (fromMaybe) +import Text.XHtml hiding (name, quote, title) import GHC hiding (anchor) import GHC.Types.Name (nameOccName) -------------------------------------------------------------------------------- + -- * Sections of the document --------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- miniBody :: Html -> Html miniBody = body ! [identifier "mini"] - sectionDiv :: String -> Html -> Html sectionDiv i = thediv ! [identifier i] - sectionName :: Html -> Html sectionName = paragraph ! [theclass "caption"] - -- | Make an element that always has at least something (a non-breaking space). -- If it would have otherwise been empty, then give it the class ".empty". nonEmptySectionName :: Html -> Html nonEmptySectionName c | isNoHtml c = thespan ! [theclass "caption empty"] $ spaceHtml - | otherwise = thespan ! [theclass "caption"] $ c - - -divPackageHeader, divContent, divModuleHeader, divFooter, - divTableOfContents, divDescription, divSynopsis, divInterface, - divIndex, divAlphabet, divPackageList, divModuleList, divContentsList + | otherwise = thespan ! [theclass "caption"] $ c + +divPackageHeader + , divContent + , divModuleHeader + , divFooter + , divTableOfContents + , divDescription + , divSynopsis + , divInterface + , divIndex + , divAlphabet + , divPackageList + , divModuleList + , divContentsList :: Html -> Html - -divPackageHeader = sectionDiv "package-header" -divContent = sectionDiv "content" -divModuleHeader = sectionDiv "module-header" -divFooter = sectionDiv "footer" -divTableOfContents = sectionDiv "table-of-contents" -divContentsList = sectionDiv "contents-list" -divDescription = sectionDiv "description" -divSynopsis = sectionDiv "synopsis" -divInterface = sectionDiv "interface" -divIndex = sectionDiv "index" -divAlphabet = sectionDiv "alphabet" -divModuleList = sectionDiv "module-list" -divPackageList = sectionDiv "module-list" - +divPackageHeader = sectionDiv "package-header" +divContent = sectionDiv "content" +divModuleHeader = sectionDiv "module-header" +divFooter = sectionDiv "footer" +divTableOfContents = sectionDiv "table-of-contents" +divContentsList = sectionDiv "contents-list" +divDescription = sectionDiv "description" +divSynopsis = sectionDiv "synopsis" +divInterface = sectionDiv "interface" +divIndex = sectionDiv "index" +divAlphabet = sectionDiv "alphabet" +divModuleList = sectionDiv "module-list" +divPackageList = sectionDiv "module-list" -------------------------------------------------------------------------------- + -- * Declaration containers --------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- shortDeclList :: [Html] -> Html shortDeclList items = ulist << map (li ! [theclass "src short"] <<) items - shortSubDecls :: Bool -> [Html] -> Html shortSubDecls inst items = ulist ! [theclass c] << map (i <<) items - where i | inst = li ! [theclass "inst"] - | otherwise = li - c | inst = "inst" - | otherwise = "subs" - + where + i + | inst = li ! [theclass "inst"] + | otherwise = li + c + | inst = "inst" + | otherwise = "subs" divTopDecl :: Html -> Html divTopDecl = thediv ! [theclass "top"] - type SubDecl = (Html, Maybe (MDoc DocName), [Html]) - -divSubDecls :: (HTML a) => String -> a -> Maybe Html -> Html +divSubDecls :: HTML a => String -> a -> Maybe Html -> Html divSubDecls cssClass captionName = maybe noHtml wrap where wrap = (subSection <<) . (subCaption +++) subSection = thediv ! [theclass $ unwords ["subs", cssClass]] subCaption = paragraph ! [theclass "caption"] << captionName - subDlist :: Maybe Package -> Qualification -> [SubDecl] -> Maybe Html subDlist _ _ [] = Nothing subDlist pkg qual decls = Just $ ulist << map subEntry decls where subEntry (decl, mdoc, subs) = - li << - (define ! [theclass "src"] << decl +++ - docElement thediv << (fmap (docToHtml Nothing pkg qual) mdoc +++ subs)) - + li + << ( define + ! [theclass "src"] + << decl + +++ docElement thediv + << (fmap (docToHtml Nothing pkg qual) mdoc +++ subs) + ) subTable :: Maybe Package -> Qualification -> [SubDecl] -> Maybe Html subTable _ _ [] = Nothing subTable pkg qual decls = Just $ table << aboves (concatMap subRow decls) where subRow (decl, mdoc, subs) = - (td ! [theclass "src"] << decl - <-> - docElement td << fmap (docToHtml Nothing pkg qual) mdoc) - : map (cell . (td <<)) subs - + ( td + ! [theclass "src"] + << decl + <-> docElement td + << fmap (docToHtml Nothing pkg qual) mdoc + ) + : map (cell . (td <<)) subs -- | Sub table with source information (optional). -subTableSrc :: Maybe Package -> Qualification -> LinksInfo -> Bool - -> [(SubDecl, Maybe Module, Located DocName)] -> Maybe Html +subTableSrc + :: Maybe Package + -> Qualification + -> LinksInfo + -> Bool + -> [(SubDecl, Maybe Module, Located DocName)] + -> Maybe Html subTableSrc _ _ _ _ [] = Nothing subTableSrc pkg qual lnks splice decls = Just $ table << aboves (concatMap subRow decls) where subRow ((decl, mdoc, subs), mdl, L loc dn) = - (td ! [theclass "src clearfix"] << - (thespan ! [theclass "inst-left"] << decl) - <+> linkHtml loc mdl dn - <-> - docElement td << fmap (docToHtml Nothing pkg qual) mdoc + ( td + ! [theclass "src clearfix"] + << (thespan ! [theclass "inst-left"] << decl) + <+> linkHtml loc mdl dn + <-> docElement td + << fmap (docToHtml Nothing pkg qual) mdoc ) - : map (cell . (td <<)) subs + : map (cell . (td <<)) subs linkHtml :: SrcSpan -> Maybe Module -> DocName -> Html linkHtml loc@(RealSrcSpan _ _) mdl dn = links lnks loc splice mdl dn @@ -175,15 +200,12 @@ subBlock :: [Html] -> Maybe Html subBlock [] = Nothing subBlock hs = Just $ toHtml hs - subArguments :: Maybe Package -> Qualification -> [SubDecl] -> Html subArguments pkg qual = divSubDecls "arguments" "Arguments" . subTable pkg qual - subAssociatedTypes :: [Html] -> Html subAssociatedTypes = divSubDecls "associated-types" "Associated Types" . subBlock - subConstructors :: Maybe Package -> Qualification -> [SubDecl] -> Html subConstructors pkg qual = divSubDecls "constructors" "Constructors" . subTable pkg qual @@ -193,71 +215,88 @@ subPatterns pkg qual = divSubDecls "bundled-patterns" "Bundled Patterns" . subTa subFields :: Maybe Package -> Qualification -> [SubDecl] -> Html subFields pkg qual = divSubDecls "fields" "Fields" . subDlist pkg qual - subEquations :: Maybe Package -> Qualification -> [SubDecl] -> Html subEquations pkg qual = divSubDecls "equations" "Equations" . subTable pkg qual - -- | Generate collapsible sub table for instance declarations, with source -subInstances :: Maybe Package -> Qualification - -> String -- ^ Class name, used for anchor generation - -> LinksInfo -> Bool - -> [(SubDecl, Maybe Module, Located DocName)] -> Html +subInstances + :: Maybe Package + -> Qualification + -> String + -- ^ Class name, used for anchor generation + -> LinksInfo + -> Bool + -> [(SubDecl, Maybe Module, Located DocName)] + -> Html subInstances pkg qual nm lnks splice = maybe noHtml wrap . instTable where wrap contents = subSection (hdr +++ collapseDetails id_ DetailsOpen (summary +++ contents)) instTable = subTableSrc pkg qual lnks splice subSection = thediv ! [theclass "subs instances"] hdr = h4 ! collapseControl id_ "instances" << "Instances" - summary = thesummary ! [ theclass "hide-when-js-enabled" ] << "Instances details" + summary = thesummary ! [theclass "hide-when-js-enabled"] << "Instances details" id_ = makeAnchorId $ "i:" ++ nm - -subOrphanInstances :: Maybe Package -> Qualification - -> LinksInfo -> Bool - -> [(SubDecl, Maybe Module, Located DocName)] -> Html -subOrphanInstances pkg qual lnks splice = maybe noHtml wrap . instTable +subOrphanInstances + :: Maybe Package + -> Qualification + -> LinksInfo + -> Bool + -> [(SubDecl, Maybe Module, Located DocName)] + -> Html +subOrphanInstances pkg qual lnks splice = maybe noHtml wrap . instTable where wrap = ((h1 << "Orphan instances") +++) - instTable = fmap (thediv ! [ identifier ("section." ++ id_) ] <<) . subTableSrc pkg qual lnks splice + instTable = fmap (thediv ! [identifier ("section." ++ id_)] <<) . subTableSrc pkg qual lnks splice id_ = makeAnchorId "orphans" - -subInstHead :: String -- ^ Instance unique id (for anchor generation) - -> Html -- ^ Header content (instance name and type) - -> Html +subInstHead + :: String + -- ^ Instance unique id (for anchor generation) + -> Html + -- ^ Header content (instance name and type) + -> Html subInstHead iid hdr = - expander noHtml <+> hdr + expander noHtml <+> hdr where expander = thespan ! collapseControl (instAnchorId iid) "instance" - -subInstDetails :: String -- ^ Instance unique id (for anchor generation) - -> [Html] -- ^ Associated type contents - -> [Html] -- ^ Method contents (pretty-printed signatures) - -> Html -- ^ Source module - -> Html +subInstDetails + :: String + -- ^ Instance unique id (for anchor generation) + -> [Html] + -- ^ Associated type contents + -> [Html] + -- ^ Method contents (pretty-printed signatures) + -> Html + -- ^ Source module + -> Html subInstDetails iid ats mets mdl = - subInstSection iid << (p mdl <+> subAssociatedTypes ats <+> subMethods mets) - -subFamInstDetails :: String -- ^ Instance unique id (for anchor generation) - -> Html -- ^ Type or data family instance - -> Html -- ^ Source module TODO: use this - -> Html + subInstSection iid << (p mdl <+> subAssociatedTypes ats <+> subMethods mets) + +subFamInstDetails + :: String + -- ^ Instance unique id (for anchor generation) + -> Html + -- ^ Type or data family instance + -> Html + -- ^ Source module TODO: use this + -> Html subFamInstDetails iid fi mdl = - subInstSection iid << (p mdl <+> (thediv ! [theclass "src"] << fi)) + subInstSection iid << (p mdl <+> (thediv ! [theclass "src"] << fi)) -subInstSection :: String -- ^ Instance unique id (for anchor generation) - -> Html - -> Html +subInstSection + :: String + -- ^ Instance unique id (for anchor generation) + -> Html + -> Html subInstSection iid contents = collapseDetails (instAnchorId iid) DetailsClosed (summary +++ contents) where - summary = thesummary ! [ theclass "hide-when-js-enabled" ] << "Instance details" + summary = thesummary ! [theclass "hide-when-js-enabled"] << "Instance details" instAnchorId :: String -> String instAnchorId iid = makeAnchorId $ "i:" ++ iid - subMethods :: [Html] -> Html subMethods = divSubDecls "methods" "Methods" . subBlock @@ -267,48 +306,51 @@ subDefaults = divSubDecls "default" "" . subBlock subMinimal :: Html -> Html subMinimal = divSubDecls "minimal" "Minimal complete definition" . Just . declElem - -- a box for displaying code declElem :: Html -> Html declElem = paragraph ! [theclass "src"] - -- a box for top level documented names -- it adds a source and wiki link at the right hand side of the box topDeclElem :: LinksInfo -> SrcSpan -> Bool -> [DocName] -> Html -> Html topDeclElem lnks loc splice names html = - declElem << (html <+> (links lnks loc splice Nothing $ head names)) - -- FIXME: is it ok to simply take the first name? + declElem << (html <+> (links lnks loc splice Nothing $ head names)) + +-- FIXME: is it ok to simply take the first name? -- | Adds a source and wiki link at the right hand side of the box. -- Name must be documented, otherwise we wouldn't get here. links :: LinksInfo -> SrcSpan -> Bool -> Maybe Module -> DocName -> Html -links ((_,_,sourceMap,lineMap), (_,_,maybe_wiki_url)) loc splice mdl' docName@(Documented n mdl) = +links ((_, _, sourceMap, lineMap), (_, _, maybe_wiki_url)) loc splice mdl' docName@(Documented n mdl) = srcLink <+> wikiLink <+> (selfLink ! [theclass "selflink"] << "#") - where selfLink = linkedAnchor (nameAnchorId (nameOccName (getName docName))) - - srcLink = let nameUrl = Map.lookup origPkg sourceMap - lineUrl = Map.lookup origPkg lineMap - mUrl | splice = lineUrl - -- Use the lineUrl as a backup - | otherwise = maybe lineUrl Just nameUrl in - case mUrl of - Nothing -> noHtml - Just url -> let url' = spliceURL (Just origMod) (Just n) (Just loc) url - in anchor ! [href url', theclass "link"] << "Source" - - wikiLink = - case maybe_wiki_url of - Nothing -> noHtml - Just url -> let url' = spliceURL (Just mdl) (Just n) (Just loc) url - in anchor ! [href url', theclass "link"] << "Comments" - - -- For source links, we want to point to the original module, - -- because only that will have the source. - -- - -- 'mdl'' is a way of "overriding" the module. Without it, instances - -- will point to the module defining the class/family, which is wrong. - origMod = fromMaybe (nameModule n) mdl' - origPkg = moduleUnit origMod - + where + selfLink = linkedAnchor (nameAnchorId (nameOccName (getName docName))) + + srcLink = + let nameUrl = Map.lookup origPkg sourceMap + lineUrl = Map.lookup origPkg lineMap + mUrl + | splice = lineUrl + -- Use the lineUrl as a backup + | otherwise = maybe lineUrl Just nameUrl + in case mUrl of + Nothing -> noHtml + Just url -> + let url' = spliceURL (Just origMod) (Just n) (Just loc) url + in anchor ! [href url', theclass "link"] << "Source" + + wikiLink = + case maybe_wiki_url of + Nothing -> noHtml + Just url -> + let url' = spliceURL (Just mdl) (Just n) (Just loc) url + in anchor ! [href url', theclass "link"] << "Comments" + + -- For source links, we want to point to the original module, + -- because only that will have the source. + -- + -- 'mdl'' is a way of "overriding" the module. Without it, instances + -- will point to the module defining the class/family, which is wrong. + origMod = fromMaybe (nameModule n) mdl' + origPkg = moduleUnit origMod links _ _ _ _ _ = noHtml diff --git a/haddock-api/src/Haddock/Backends/Xhtml/Meta.hs b/haddock-api/src/Haddock/Backends/Xhtml/Meta.hs index 540885acea..548feb1b2b 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml/Meta.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml/Meta.hs @@ -5,7 +5,7 @@ import Haddock.Version import Data.ByteString.Builder (hPutBuilder) import System.FilePath (()) -import System.IO (withFile, IOMode (WriteMode)) +import System.IO (IOMode (WriteMode), withFile) -- | Everytime breaking changes to the Quckjump api -- happen this needs to be modified. @@ -19,10 +19,13 @@ writeHaddockMeta :: FilePath -> Bool -> IO () writeHaddockMeta odir withQuickjump = do let meta_json :: Value - meta_json = object (concat [ - [ "haddock_version" .= String projectVersion ] - , [ "quickjump_version" .= quickjumpVersion | withQuickjump ] - ]) + meta_json = + object + ( concat + [ ["haddock_version" .= String projectVersion] + , ["quickjump_version" .= quickjumpVersion | withQuickjump] + ] + ) withFile (odir "meta.json") WriteMode $ \h -> hPutBuilder h (encodeToBuilder meta_json) diff --git a/haddock-api/src/Haddock/Backends/Xhtml/Names.hs b/haddock-api/src/Haddock/Backends/Xhtml/Names.hs index f7bf18875f..093be648f1 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml/Names.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml/Names.hs @@ -1,4 +1,7 @@ ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.Backends.Html.Names -- Copyright : (c) Simon Marlow 2003-2006, @@ -9,45 +12,55 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------ -module Haddock.Backends.Xhtml.Names ( - ppName, ppDocName, ppLDocName, ppRdrName, ppUncheckedLink, - ppBinder, ppBinderInfix, ppBinder', - ppModule, ppModuleRef, ppIPName, linkId, Notation(..), - ppWrappedDocName, ppWrappedName, -) where - +module Haddock.Backends.Xhtml.Names + ( ppName + , ppDocName + , ppLDocName + , ppRdrName + , ppUncheckedLink + , ppBinder + , ppBinderInfix + , ppBinder' + , ppModule + , ppModuleRef + , ppIPName + , linkId + , Notation (..) + , ppWrappedDocName + , ppWrappedName + ) where import Haddock.Backends.Xhtml.Utils import Haddock.GhcUtils import Haddock.Types import Haddock.Utils -import Text.XHtml hiding ( name, p, quote ) -import Data.List ( stripPrefix ) +import Data.List (stripPrefix) +import Text.XHtml hiding (name, p, quote) -import GHC hiding (LexicalFixity(..), anchor) +import GHC hiding (LexicalFixity (..), anchor) +import GHC.Data.FastString (unpackFS) import GHC.Types.Name import GHC.Types.Name.Reader -import GHC.Data.FastString (unpackFS) - -- | Indicator of how to render a 'DocName' into 'Html' -data Notation = Raw -- ^ Render as-is. - | Infix -- ^ Render using infix notation. - | Prefix -- ^ Render using prefix notation. - deriving (Eq, Show) +data Notation + = -- | Render as-is. + Raw + | -- | Render using infix notation. + Infix + | -- | Render using prefix notation. + Prefix + deriving (Eq, Show) ppOccName :: OccName -> Html ppOccName = toHtml . occNameString - ppRdrName :: RdrName -> Html ppRdrName = ppOccName . rdrNameOcc ppIPName :: HsIPName -> Html -ppIPName = toHtml . ('?':) . unpackFS . hsIPNameFS - +ppIPName = toHtml . ('?' :) . unpackFS . hsIPNameFS ppUncheckedLink :: Qualification -> Wrap (ModuleName, OccName) -> Html ppUncheckedLink _ x = linkIdOcc' mdl (Just occ) << occHtml @@ -59,19 +72,17 @@ ppUncheckedLink _ x = linkIdOcc' mdl (Just occ) << occHtml ppLDocName :: Qualification -> Notation -> GenLocated l DocName -> Html ppLDocName qual notation (L _ d) = ppDocName qual notation True d - ppDocName :: Qualification -> Notation -> Bool -> DocName -> Html ppDocName qual notation insertAnchors docName = case docName of Documented name mdl -> linkIdOcc mdl (Just (nameOccName name)) insertAnchors - << ppQualifyName qual notation name mdl + << ppQualifyName qual notation name mdl Undocumented name | isExternalName name || isWiredInName name -> ppQualifyName qual notation name (nameModule name) | otherwise -> ppName notation name - ppWrappedDocName :: Qualification -> Notation -> Bool -> Wrap DocName -> Html ppWrappedDocName qual notation insertAnchors docName = case docName of Unadorned n -> ppDocName qual notation insertAnchors n @@ -88,7 +99,7 @@ ppWrappedName notation docName = case docName of ppQualifyName :: Qualification -> Notation -> Name -> Module -> Html ppQualifyName qual notation name mdl = case qual of - NoQual -> ppName notation name + NoQual -> ppName notation name FullQual -> ppFullQualName notation mdl name LocalQual localmdl -> if moduleString mdl == moduleString localmdl @@ -97,14 +108,13 @@ ppQualifyName qual notation name mdl = RelativeQual localmdl -> case stripPrefix (moduleString localmdl) (moduleString mdl) of -- local, A.x -> x - Just [] -> ppName notation name + Just [] -> ppName notation name -- sub-module, A.B.x -> B.x - Just ('.':m) -> toHtml $ m ++ '.' : getOccString name + Just ('.' : m) -> toHtml $ m ++ '.' : getOccString name -- some module with same prefix, ABC.x -> ABC.x - Just _ -> ppFullQualName notation mdl name + Just _ -> ppFullQualName notation mdl name -- some other module, D.x -> D.x - Nothing -> ppFullQualName notation mdl name - + Nothing -> ppFullQualName notation mdl name ppFullQualName :: Notation -> Module -> Name -> Html ppFullQualName notation mdl name = wrapInfix notation (getOccName name) qname @@ -114,14 +124,15 @@ ppFullQualName notation mdl name = wrapInfix notation (getOccName name) qname ppName :: Notation -> Name -> Html ppName notation name = case m_pun of - Just str -> toHtml (unpackFS str) -- use the punned form - Nothing -> wrapInfix notation (getOccName name) $ - toHtml (getOccString name) -- use the original identifier + Just str -> toHtml (unpackFS str) -- use the punned form + Nothing -> + wrapInfix notation (getOccName name) $ + toHtml (getOccString name) -- use the original identifier where m_pun = case notation of - Raw -> namePun_maybe name + Raw -> namePun_maybe name Prefix -> namePun_maybe name - Infix -> Nothing + Infix -> Nothing ppBinder :: Bool -> OccName -> Html ppBinder = ppBinderWith Prefix @@ -137,8 +148,9 @@ ppBinderWith notation isRef n = makeAnchor << ppBinder' notation n where name = nameAnchorId n - makeAnchor | isRef = linkedAnchor name - | otherwise = namedAnchor name ! [theclass "def"] + makeAnchor + | isRef = linkedAnchor name + | otherwise = namedAnchor name ! [theclass "def"] ppBinder' :: Notation -> OccName -> Html ppBinder' notation n = wrapInfix notation n $ ppOccName n @@ -154,39 +166,41 @@ wrapInfix notation n = case notation of linkId :: Module -> Maybe Name -> Html -> Html linkId mdl mbName = linkIdOcc mdl (fmap nameOccName mbName) True - linkIdOcc :: Module -> Maybe OccName -> Bool -> Html -> Html linkIdOcc mdl mbName insertAnchors = if insertAnchors - then anchor ! [href url, title ttl] - else id + then anchor ! [href url, title ttl] + else id where ttl = moduleNameString (moduleName mdl) url = case mbName of - Nothing -> moduleUrl mdl + Nothing -> moduleUrl mdl Just name -> moduleNameUrl mdl name - linkIdOcc' :: ModuleName -> Maybe OccName -> Html -> Html linkIdOcc' mdl mbName = anchor ! [href url, title ttl] where ttl = moduleNameString mdl url = case mbName of - Nothing -> moduleHtmlFile' mdl + Nothing -> moduleHtmlFile' mdl Just name -> moduleNameUrl' mdl name - ppModule :: Module -> Html -ppModule mdl = anchor ! [href (moduleUrl mdl)] - << toHtml (moduleString mdl) - +ppModule mdl = + anchor + ! [href (moduleUrl mdl)] + << toHtml (moduleString mdl) ppModuleRef :: Maybe Html -> ModuleName -> String -> Html -ppModuleRef Nothing mdl ref = anchor ! [href (moduleHtmlFile' mdl ++ ref)] - << toHtml (moduleNameString mdl) -ppModuleRef (Just lbl) mdl ref = anchor ! [href (moduleHtmlFile' mdl ++ ref)] - << lbl - - -- NB: The ref parameter already includes the '#'. - -- This function is only called from markupModule expanding a - -- DocModule, which doesn't seem to be ever be used. +ppModuleRef Nothing mdl ref = + anchor + ! [href (moduleHtmlFile' mdl ++ ref)] + << toHtml (moduleNameString mdl) +ppModuleRef (Just lbl) mdl ref = + anchor + ! [href (moduleHtmlFile' mdl ++ ref)] + << lbl + +-- NB: The ref parameter already includes the '#'. +-- This function is only called from markupModule expanding a +-- DocModule, which doesn't seem to be ever be used. diff --git a/haddock-api/src/Haddock/Backends/Xhtml/Themes.hs b/haddock-api/src/Haddock/Backends/Xhtml/Themes.hs index 08ef747aa1..604af00c54 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml/Themes.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml/Themes.hs @@ -1,4 +1,7 @@ ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.Backends.Html.Themes -- Copyright : (c) Mark Lentczner 2010 @@ -7,17 +10,16 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------ -module Haddock.Backends.Xhtml.Themes ( - Themes, - getThemes, - - cssFiles, styleSheet - ) - where - +module Haddock.Backends.Xhtml.Themes + ( Themes + , getThemes + , cssFiles + , styleSheet + ) +where + +import Haddock.Backends.Xhtml.Types (BaseURL, withBaseURL) import Haddock.Options -import Haddock.Backends.Xhtml.Types ( BaseURL, withBaseURL ) import Control.Monad (liftM) import Data.Char (toLower) @@ -27,18 +29,19 @@ import Data.Maybe (isJust, listToMaybe) import System.Directory import System.FilePath -import Text.XHtml hiding ( name, title, p, quote, () ) +import Text.XHtml hiding (name, p, quote, title, ()) import qualified Text.XHtml as XHtml - -------------------------------------------------------------------------------- + -- * CSS Themes + -------------------------------------------------------------------------------- -data Theme = Theme { - themeName :: String, - themeHref :: String, - themeFiles :: [FilePath] +data Theme = Theme + { themeName :: String + , themeHref :: String + , themeFiles :: [FilePath] } type Themes = [Theme] @@ -46,19 +49,17 @@ type Themes = [Theme] type PossibleTheme = Either String Theme type PossibleThemes = Either String Themes - -- | Find a theme by name (case insensitive match) findTheme :: String -> Themes -> Maybe Theme -findTheme s = listToMaybe . filter ((== ls).lower.themeName) - where lower = map toLower - ls = lower s - +findTheme s = listToMaybe . filter ((== ls) . lower . themeName) + where + lower = map toLower + ls = lower s -- | Standard theme used by default standardTheme :: FilePath -> IO PossibleThemes standardTheme libDir = liftM (liftEither (take 1)) (defaultThemes libDir) - -- | Default themes that are part of Haddock; added with @--built-in-themes@ -- The first theme in this list is considered the standard theme. -- Themes are "discovered" by scanning the html sub-dir of the libDir, @@ -72,20 +73,18 @@ defaultThemes libDir = do where discoverThemes paths = filterExt ".std-theme" paths ++ filterExt ".theme" paths - filterExt ext = filter ((== ext).takeExtension) - + filterExt ext = filter ((== ext) . takeExtension) -- | Build a theme from a single .css file singleFileTheme :: FilePath -> IO PossibleTheme singleFileTheme path = if isCssFilePath path - then retRight $ Theme name file [path] - else errMessage "File extension isn't .css" path + then retRight $ Theme name file [path] + else errMessage "File extension isn't .css" path where name = takeBaseName path file = takeFileName path - -- | Build a theme from a directory directoryTheme :: FilePath -> IO PossibleTheme directoryTheme path = do @@ -95,21 +94,22 @@ directoryTheme path = do [] -> errMessage "No .css file in theme directory" path _ -> errMessage "More than one .css file in theme directory" path - -- | Check if we have a built in theme doesBuiltInExist :: IO PossibleThemes -> String -> IO Bool doesBuiltInExist pts s = fmap (either (const False) test) pts - where test = isJust . findTheme s - + where + test = isJust . findTheme s -- | Find a built in theme builtInTheme :: IO PossibleThemes -> String -> IO PossibleTheme builtInTheme pts s = either Left fetch <$> pts - where fetch = maybe (Left ("Unknown theme: " ++ s)) Right . findTheme s - + where + fetch = maybe (Left ("Unknown theme: " ++ s)) Right . findTheme s -------------------------------------------------------------------------------- + -- * CSS Theme Arguments + -------------------------------------------------------------------------------- -- | Process input flags for CSS Theme arguments @@ -118,78 +118,85 @@ getThemes libDir flags = liftM concatEither (mapM themeFlag flags) >>= someTheme where themeFlag :: Flag -> IO (Either String Themes) - themeFlag (Flag_CSS path) = (liftM . liftEither) (:[]) (theme path) + themeFlag (Flag_CSS path) = (liftM . liftEither) (: []) (theme path) themeFlag (Flag_BuiltInThemes) = builtIns themeFlag _ = retRight [] theme :: FilePath -> IO PossibleTheme - theme path = pick path - [(doesFileExist, singleFileTheme), - (doesDirectoryExist, directoryTheme), - (doesBuiltInExist builtIns, builtInTheme builtIns)] - "Theme not found" - - pick :: FilePath - -> [(FilePath -> IO Bool, FilePath -> IO PossibleTheme)] -> String + theme path = + pick + path + [ (doesFileExist, singleFileTheme) + , (doesDirectoryExist, directoryTheme) + , (doesBuiltInExist builtIns, builtInTheme builtIns) + ] + "Theme not found" + + pick + :: FilePath + -> [(FilePath -> IO Bool, FilePath -> IO PossibleTheme)] + -> String -> IO PossibleTheme pick path [] msg = errMessage msg path - pick path ((test,build):opts) msg = do + pick path ((test, build) : opts) msg = do pass <- test path if pass then build path else pick path opts msg - someTheme :: Either String Themes -> IO (Either String Themes) someTheme (Right []) = standardTheme libDir someTheme est = return est builtIns = defaultThemes libDir - errMessage :: String -> FilePath -> IO (Either String a) errMessage msg path = return (Left msg') - where msg' = "Error: " ++ msg ++ ": \"" ++ path ++ "\"\n" - + where + msg' = "Error: " ++ msg ++ ": \"" ++ path ++ "\"\n" retRight :: a -> IO (Either String a) retRight = return . Right - -------------------------------------------------------------------------------- + -- * File Utilities --------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- getDirectoryItems :: FilePath -> IO [FilePath] getDirectoryItems path = map (combine path) . filter notDot <$> getDirectoryContents path - where notDot s = s /= "." && s /= ".." - + where + notDot s = s /= "." && s /= ".." isCssFilePath :: FilePath -> Bool isCssFilePath path = takeExtension path == ".css" - -------------------------------------------------------------------------------- + -- * Style Sheet Utilities + -------------------------------------------------------------------------------- cssFiles :: Themes -> [String] cssFiles ts = nub $ concatMap themeFiles ts - styleSheet :: BaseURL -> Themes -> Html styleSheet base_url ts = toHtml $ zipWith mkLink rels ts where rels = "stylesheet" : repeat "alternate stylesheet" mkLink aRel t = thelink - ! [ href (withBaseURL base_url (themeHref t)), rel aRel, thetype "text/css", - XHtml.title (themeName t) + ! [ href (withBaseURL base_url (themeHref t)) + , rel aRel + , thetype "text/css" + , XHtml.title (themeName t) ] << noHtml -------------------------------------------------------------------------------- + -- * Either Utilities + -------------------------------------------------------------------------------- -- These three routines are here because Haddock does not have access to the @@ -199,10 +206,8 @@ styleSheet base_url ts = toHtml $ zipWith mkLink rels ts sequenceEither :: [Either a b] -> Either a [b] sequenceEither es = maybe (Right $ rights es) Left (listToMaybe (lefts es)) - liftEither :: (b -> c) -> Either a b -> Either a c liftEither f = either Left (Right . f) - concatEither :: [Either a [b]] -> Either a [b] concatEither = liftEither concat . sequenceEither diff --git a/haddock-api/src/Haddock/Backends/Xhtml/Types.hs b/haddock-api/src/Haddock/Backends/Xhtml/Types.hs index a68cb559c8..25bbcff459 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml/Types.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml/Types.hs @@ -1,4 +1,7 @@ ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.Backends.Html.Types -- Copyright : (c) Simon Marlow 2003-2006, @@ -9,33 +12,30 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------ -module Haddock.Backends.Xhtml.Types ( - SourceURLs, WikiURLs, - BaseURL, - withBaseURL, - LinksInfo, - Splice, - Unicode, -) where - +module Haddock.Backends.Xhtml.Types + ( SourceURLs + , WikiURLs + , BaseURL + , withBaseURL + , LinksInfo + , Splice + , Unicode + ) where import Data.Map import GHC import qualified System.FilePath as FilePath - -- the base, module and entity URLs for the source code and wiki links. type SourceURLs = (Maybe FilePath, Maybe FilePath, Map Unit FilePath, Map Unit FilePath) type WikiURLs = (Maybe FilePath, Maybe FilePath, Maybe FilePath) -- | base url for loading js, json, css resources. The default is "." --- type BaseURL = Maybe String -- TODO: we shouldn't use 'FilePath.' withBaseURL :: BaseURL -> String -> String -withBaseURL Nothing uri = uri +withBaseURL Nothing uri = uri withBaseURL (Just baseUrl) uri = baseUrl FilePath. uri -- The URL for source and wiki links diff --git a/haddock-api/src/Haddock/Backends/Xhtml/Utils.hs b/haddock-api/src/Haddock/Backends/Xhtml/Utils.hs index 7f8be25a6a..53c3d37315 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml/Utils.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml/Utils.hs @@ -1,4 +1,7 @@ ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.Backends.Html.Util -- Copyright : (c) Simon Marlow 2003-2006, @@ -9,38 +12,54 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------ -module Haddock.Backends.Xhtml.Utils ( - renderToString, - - namedAnchor, linkedAnchor, - spliceURL, spliceURL', - groupId, - - (<+>), (<=>), char, - keyword, punctuate, - - braces, brackets, pabrackets, parens, parenList, ubxParenList, ubxSumList, - arrow, lollipop, comma, dcolon, dot, darrow, equals, forallSymbol, quote, promoQuote, - multAnnotation, - atSign, - - hsep, vcat, - - DetailsState(..), collapseDetails, thesummary, - collapseToggle, collapseControl, -) where - +module Haddock.Backends.Xhtml.Utils + ( renderToString + , namedAnchor + , linkedAnchor + , spliceURL + , spliceURL' + , groupId + , (<+>) + , (<=>) + , char + , keyword + , punctuate + , braces + , brackets + , pabrackets + , parens + , parenList + , ubxParenList + , ubxSumList + , arrow + , lollipop + , comma + , dcolon + , dot + , darrow + , equals + , forallSymbol + , quote + , promoQuote + , multAnnotation + , atSign + , hsep + , vcat + , DetailsState (..) + , collapseDetails + , thesummary + , collapseToggle + , collapseControl + ) where import Haddock.Utils -import Text.XHtml hiding ( name, title, p, quote ) +import Text.XHtml hiding (name, p, quote, title) import qualified Text.XHtml as XHtml -import GHC ( SrcSpan(..), srcSpanStartLine, Name ) -import GHC.Unit.Module ( Module, ModuleName, moduleName, moduleNameString ) -import GHC.Types.Name ( getOccString, nameOccName, isValOcc ) - +import GHC (Name, SrcSpan (..), srcSpanStartLine) +import GHC.Types.Name (getOccString, isValOcc, nameOccName) +import GHC.Unit.Module (Module, ModuleName, moduleName, moduleNameString) -- | Replace placeholder string elements with provided values. -- @@ -49,59 +68,61 @@ import GHC.Types.Name ( getOccString, nameOccName, isValOcc ) -- -- >>> spliceURL mmod mname Nothing "output/%{MODULE}.hs#%{NAME}" -- "output/Foo.hs#foo" -spliceURL :: Maybe Module -> Maybe GHC.Name -> - Maybe SrcSpan -> String -> String +spliceURL + :: Maybe Module + -> Maybe GHC.Name + -> Maybe SrcSpan + -> String + -> String spliceURL mmod = spliceURL' (moduleName <$> mmod) - -- | Same as 'spliceURL' but takes 'ModuleName' instead of 'Module'. -spliceURL' :: Maybe ModuleName -> Maybe GHC.Name -> - Maybe SrcSpan -> String -> String +spliceURL' + :: Maybe ModuleName + -> Maybe GHC.Name + -> Maybe SrcSpan + -> String + -> String spliceURL' maybe_mod maybe_name maybe_loc = run - where - mdl = case maybe_mod of - Nothing -> "" - Just m -> moduleNameString m - - (name, kind) = - case maybe_name of - Nothing -> ("","") - Just n | isValOcc (nameOccName n) -> (escapeStr (getOccString n), "v") - | otherwise -> (escapeStr (getOccString n), "t") - - line = case maybe_loc of - Nothing -> "" - Just span_ -> - case span_ of - RealSrcSpan span__ _ -> - show $ srcSpanStartLine span__ - UnhelpfulSpan _ -> "" - - run "" = "" - run ('%':'M':rest) = mdl ++ run rest - run ('%':'N':rest) = name ++ run rest - run ('%':'K':rest) = kind ++ run rest - run ('%':'L':rest) = line ++ run rest - run ('%':'%':rest) = '%' : run rest - - run ('%':'{':'M':'O':'D':'U':'L':'E':'}':rest) = mdl ++ run rest - run ('%':'{':'N':'A':'M':'E':'}':rest) = name ++ run rest - run ('%':'{':'K':'I':'N':'D':'}':rest) = kind ++ run rest - - run ('%':'{':'M':'O':'D':'U':'L':'E':'/':'.':'/':c:'}':rest) = - map (\x -> if x == '.' then c else x) mdl ++ run rest - - run ('%':'{':'L':'I':'N':'E':'}':rest) = line ++ run rest - - run (c:rest) = c : run rest - + where + mdl = case maybe_mod of + Nothing -> "" + Just m -> moduleNameString m + + (name, kind) = + case maybe_name of + Nothing -> ("", "") + Just n + | isValOcc (nameOccName n) -> (escapeStr (getOccString n), "v") + | otherwise -> (escapeStr (getOccString n), "t") + + line = case maybe_loc of + Nothing -> "" + Just span_ -> + case span_ of + RealSrcSpan span__ _ -> + show $ srcSpanStartLine span__ + UnhelpfulSpan _ -> "" + + run "" = "" + run ('%' : 'M' : rest) = mdl ++ run rest + run ('%' : 'N' : rest) = name ++ run rest + run ('%' : 'K' : rest) = kind ++ run rest + run ('%' : 'L' : rest) = line ++ run rest + run ('%' : '%' : rest) = '%' : run rest + run ('%' : '{' : 'M' : 'O' : 'D' : 'U' : 'L' : 'E' : '}' : rest) = mdl ++ run rest + run ('%' : '{' : 'N' : 'A' : 'M' : 'E' : '}' : rest) = name ++ run rest + run ('%' : '{' : 'K' : 'I' : 'N' : 'D' : '}' : rest) = kind ++ run rest + run ('%' : '{' : 'M' : 'O' : 'D' : 'U' : 'L' : 'E' : '/' : '.' : '/' : c : '}' : rest) = + map (\x -> if x == '.' then c else x) mdl ++ run rest + run ('%' : '{' : 'L' : 'I' : 'N' : 'E' : '}' : rest) = line ++ run rest + run (c : rest) = c : run rest renderToString :: Bool -> Html -> String renderToString debug html | debug = renderHtml html | otherwise = showHtml html - hsep :: [Html] -> Html hsep [] = noHtml hsep htmls = foldr1 (<+>) htmls @@ -109,8 +130,7 @@ hsep htmls = foldr1 (<+>) htmls -- | Concatenate a series of 'Html' values vertically, with linebreaks in between. vcat :: [Html] -> Html vcat [] = noHtml -vcat htmls = foldr1 (\a b -> a+++br+++b) htmls - +vcat htmls = foldr1 (\a b -> a +++ br +++ b) htmls infixr 8 <+> (<+>) :: Html -> Html -> Html @@ -121,68 +141,57 @@ a <+> b = a +++ sep +++ b -- | Join two 'Html' values together with a linebreak in between. -- Has 'noHtml' as left identity. infixr 8 <=> + (<=>) :: Html -> Html -> Html a <=> b = a +++ sep +++ b where sep = if isNoHtml a then noHtml else br - keyword :: String -> Html keyword s = thespan ! [theclass "keyword"] << toHtml s - equals, comma :: Html equals = char '=' -comma = char ',' - +comma = char ',' char :: Char -> Html char c = toHtml [c] - quote :: Html -> Html quote h = char '`' +++ h +++ '`' - -- | Promoted type quote (e.g. @'[a, b]@, @'(a, b, c)@). promoQuote :: Html -> Html promoQuote h = char '\'' +++ h - parens, brackets, pabrackets, braces :: Html -> Html -parens h = char '(' +++ h +++ char ')' -brackets h = char '[' +++ h +++ char ']' -pabrackets h = toHtml "[:" +++ h +++ toHtml ":]" -braces h = char '{' +++ h +++ char '}' - +parens h = char '(' +++ h +++ char ')' +brackets h = char '[' +++ h +++ char ']' +pabrackets h = toHtml "[:" +++ h +++ toHtml ":]" +braces h = char '{' +++ h +++ char '}' punctuate :: Html -> [Html] -> [Html] -punctuate _ [] = [] -punctuate h (d0:ds) = go d0 ds - where - go d [] = [d] - go d (e:es) = (d +++ h) : go e es - +punctuate _ [] = [] +punctuate h (d0 : ds) = go d0 ds + where + go d [] = [d] + go d (e : es) = (d +++ h) : go e es parenList :: [Html] -> Html parenList = parens . hsep . punctuate comma - ubxParenList :: [Html] -> Html ubxParenList = ubxparens . hsep . punctuate comma - -ubxSumList :: [Html] -> Html +ubxSumList :: [Html] -> Html ubxSumList = ubxparens . hsep . punctuate (toHtml " | ") - ubxparens :: Html -> Html ubxparens h = toHtml "(#" <+> h <+> toHtml "#)" - dcolon, arrow, lollipop, darrow, forallSymbol :: Bool -> Html dcolon unicode = toHtml (if unicode then "∷" else "::") -arrow unicode = toHtml (if unicode then "→" else "->") +arrow unicode = toHtml (if unicode then "→" else "->") lollipop unicode = toHtml (if unicode then "⊸" else "%1 ->") darrow unicode = toHtml (if unicode then "⇒" else "=>") forallSymbol unicode = if unicode then toHtml "∀" else keyword "forall" @@ -196,15 +205,12 @@ multAnnotation = toHtml "%" dot :: Html dot = toHtml "." - -- | Generate a named anchor namedAnchor :: String -> Html -> Html namedAnchor n = anchor ! [XHtml.identifier n] - linkedAnchor :: String -> Html -> Html -linkedAnchor n = anchor ! [href ('#':n)] - +linkedAnchor n = anchor ! [href ('#' : n)] -- | generate an anchor identifier for a group groupId :: String -> String @@ -218,18 +224,21 @@ data DetailsState = DetailsOpen | DetailsClosed collapseDetails :: String -> DetailsState -> Html -> Html collapseDetails id_ state = tag "details" ! (identifier id_ : openAttrs) - where openAttrs = case state of { DetailsOpen -> [emptyAttr "open"]; DetailsClosed -> [] } + where + openAttrs = case state of DetailsOpen -> [emptyAttr "open"]; DetailsClosed -> [] thesummary :: Html -> Html thesummary = tag "summary" -- | Attributes for an area that toggles a collapsed area collapseToggle :: String -> String -> [HtmlAttr] -collapseToggle id_ classes = [ theclass cs, strAttr "data-details-id" id_ ] - where cs = unwords (words classes ++ ["details-toggle"]) +collapseToggle id_ classes = [theclass cs, strAttr "data-details-id" id_] + where + cs = unwords (words classes ++ ["details-toggle"]) -- | Attributes for an area that toggles a collapsed area, -- and displays a control. collapseControl :: String -> String -> [HtmlAttr] collapseControl id_ classes = collapseToggle id_ cs - where cs = unwords (words classes ++ ["details-toggle-control"]) + where + cs = unwords (words classes ++ ["details-toggle-control"]) diff --git a/haddock-api/src/Haddock/Convert.hs b/haddock-api/src/Haddock/Convert.hs index 98e8365e8d..5cfb4d84f0 100644 --- a/haddock-api/src/Haddock/Convert.hs +++ b/haddock-api/src/Haddock/Convert.hs @@ -1,10 +1,13 @@ -{-# LANGUAGE CPP #-} +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE PatternGuards #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE PatternGuards #-} +{-# LANGUAGE TypeFamilies #-} ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.Convert -- Copyright : (c) Isaac Dupree 2009, @@ -16,65 +19,79 @@ -- -- Conversion between TyThing and HsDecl. This functionality may be moved into -- GHC at some point. ------------------------------------------------------------------------------ -module Haddock.Convert ( - tyThingToLHsDecl, - synifyInstHead, - synifyFamInst, - PrintRuntimeReps(..), -) where +module Haddock.Convert + ( tyThingToLHsDecl + , synifyInstHead + , synifyFamInst + , PrintRuntimeReps (..) + ) where import Control.DeepSeq (force) -import GHC.Data.Bag ( emptyBag ) -import GHC.Types.Basic ( TupleSort(..), DefMethSpec(..), TopLevelFlag(..) ) -import GHC.Types.SourceText (SourceText(..)) -import GHC.Types.Fixity (LexicalFixity(..)) import GHC.Core.Class import GHC.Core.Coercion.Axiom import GHC.Core.ConLike import GHC.Core.DataCon import GHC.Core.FamInstEnv import GHC.Core.PatSyn +import GHC.Core.TyCo.Compare (eqTypes) +import GHC.Core.TyCo.Rep import GHC.Core.TyCon import GHC.Core.Type -import GHC.Core.TyCo.Rep -import GHC.Core.TyCo.Compare( eqTypes ) - +import GHC.Data.Bag (emptyBag) +import GHC.Types.Basic (DefMethSpec (..), TopLevelFlag (..), TupleSort (..)) +import GHC.Types.Fixity (LexicalFixity (..)) +import GHC.Types.SourceText (SourceText (..)) + +import GHC.Builtin.Names + ( boxedRepDataConKey + , eqTyConKey + , hasKey + , ipClassKey + , liftedDataConKey + , tYPETyConKey + ) +import GHC.Builtin.Types + ( eqTyConName + , liftedTypeKindTyConName + , listTyConName + , promotedConsDataCon + , promotedNilDataCon + , unitTy + ) +import GHC.Builtin.Types.Prim (alphaTyVars) import GHC.Hs -import GHC.Types.TyThing +import GHC.Types.Id (idType, setIdType) import GHC.Types.Name -import GHC.Unit.Types -import GHC.Types.Id ( setIdType, idType ) -import GHC.Types.Name.Set ( emptyNameSet ) -import GHC.Types.Name.Reader ( mkVarUnqual ) -import GHC.Builtin.Types.Prim ( alphaTyVars ) -import GHC.Builtin.Types ( eqTyConName, listTyConName, liftedTypeKindTyConName - , unitTy, promotedNilDataCon, promotedConsDataCon ) -import GHC.Builtin.Names ( hasKey, eqTyConKey, ipClassKey, tYPETyConKey - , liftedDataConKey, boxedRepDataConKey ) -import GHC.Types.Unique ( getUnique ) -import GHC.Utils.Misc ( chkAppend, dropList, equalLength - , filterByList, filterOut ) -import GHC.Utils.Panic.Plain ( assert ) +import GHC.Types.Name.Reader (mkVarUnqual) +import GHC.Types.Name.Set (emptyNameSet) +import GHC.Types.SrcLoc +import GHC.Types.TyThing +import GHC.Types.Unique (getUnique) import GHC.Types.Var import GHC.Types.Var.Set -import GHC.Types.SrcLoc - -import Language.Haskell.Syntax.Basic (FieldLabelString(..)) - -import Haddock.Types -import Haddock.GhcUtils ( orderedFVs, defaultRuntimeRepVars, mkEmptySigType ) +import GHC.Unit.Types +import GHC.Utils.Misc + ( chkAppend + , dropList + , equalLength + , filterByList + , filterOut + ) +import GHC.Utils.Panic.Plain (assert) + +import Language.Haskell.Syntax.Basic (FieldLabelString (..)) + +import Haddock.GhcUtils (defaultRuntimeRepVars, mkEmptySigType, orderedFVs) import Haddock.Interface.RenameType +import Haddock.Types -import Data.Either (lefts, rights) -import Data.Maybe ( catMaybes, mapMaybe, maybeToList ) -import Data.Either ( partitionEithers ) - +import Data.Either (lefts, partitionEithers, rights) +import Data.Maybe (catMaybes, mapMaybe, maybeToList) -- | Whether or not to default 'RuntimeRep' variables to 'LiftedRep'. Check -- out Note [Defaulting RuntimeRep variables] in GHC.Iface.Type for the -- motivation. -data PrintRuntimeReps = ShowRuntimeRep | HideRuntimeRep deriving Show +data PrintRuntimeReps = ShowRuntimeRep | HideRuntimeRep deriving (Show) -- the main function here! yay! tyThingToLHsDecl @@ -91,87 +108,103 @@ tyThingToLHsDecl prr t = case t of -- into a ForD instead of a SigD if we wanted. Haddock doesn't -- need to care. AnId i -> allOK $ SigD noExtField (synifyIdSig prr ImplicitizeForAll [] i) - -- type-constructors (e.g. Maybe) are complicated, put the definition -- later in the file (also it's used for class associated-types too.) ATyCon tc - | Just cl <- tyConClass_maybe tc -- classes are just a little tedious - -> let extractFamilyDecl :: TyClDecl a -> Either String (FamilyDecl a) - extractFamilyDecl (FamDecl _ d) = return d - extractFamilyDecl _ = - Left "tyThingToLHsDecl: impossible associated tycon" - - cvt :: HsTyVarBndr flag GhcRn -> HsType GhcRn - -- Without this signature, we trigger GHC#18932 - cvt (UserTyVar _ _ n) = HsTyVar noAnn NotPromoted n - cvt (KindedTyVar _ _ (L name_loc n) kind) = HsKindSig noAnn - (L (l2l name_loc) (HsTyVar noAnn NotPromoted (L name_loc n))) kind - - -- | Convert a LHsTyVarBndr to an equivalent LHsType. - hsLTyVarBndrToType :: LHsTyVarBndr flag GhcRn -> LHsType GhcRn - hsLTyVarBndrToType = fmap cvt - - extractFamDefDecl :: FamilyDecl GhcRn -> Type -> TyFamDefltDecl GhcRn - extractFamDefDecl fd rhs = - TyFamInstDecl noAnn $ FamEqn - { feqn_ext = noAnn - , feqn_tycon = fdLName fd - , feqn_bndrs = HsOuterImplicit{hso_ximplicit = hsq_ext (fdTyVars fd)} - , feqn_pats = map (HsValArg noExtField . hsLTyVarBndrToType) $ - hsq_explicit $ fdTyVars fd - , feqn_fixity = fdFixity fd - , feqn_rhs = synifyType WithinType [] rhs } - - extractAtItem - :: ClassATItem - -> Either String (LFamilyDecl GhcRn, Maybe (LTyFamDefltDecl GhcRn)) - extractAtItem (ATI at_tc def) = do - tyDecl <- synifyTyCon prr Nothing at_tc - famDecl <- extractFamilyDecl tyDecl - let defEqnTy = fmap (noLocA . extractFamDefDecl famDecl . fst) def - pure (noLocA famDecl, defEqnTy) - - atTyClDecls = map extractAtItem (classATItems cl) - (atFamDecls, atDefFamDecls) = unzip (rights atTyClDecls) - vs = tyConVisibleTyVars (classTyCon cl) - - in withErrs (lefts atTyClDecls) . TyClD noExtField $ ClassDecl - { -- This should not always be `Just`, since `Just` of an empty - -- context causes pretty printing to print `()` for the - -- context - tcdCtxt = - case classSCTheta cl of - [] -> Nothing - th -> Just $ synifyCtx th - - , tcdLName = synifyNameN cl - , tcdTyVars = synifyTyVars vs - , tcdFixity = synifyFixity cl - , tcdFDs = map (\ (l,r) -> noLocA - (FunDep noAnn (map (noLocA . getName) l) (map (noLocA . getName) r)) ) $ - snd $ classTvsFds cl - , tcdSigs = noLocA (MinimalSig (noAnn, NoSourceText) . noLocA . fmap noLocA $ classMinimalDef cl) : - [ noLocA tcdSig + | Just cl <- tyConClass_maybe tc -> -- classes are just a little tedious + let extractFamilyDecl :: TyClDecl a -> Either String (FamilyDecl a) + extractFamilyDecl (FamDecl _ d) = return d + extractFamilyDecl _ = + Left "tyThingToLHsDecl: impossible associated tycon" + + cvt :: HsTyVarBndr flag GhcRn -> HsType GhcRn + -- Without this signature, we trigger GHC#18932 + cvt (UserTyVar _ _ n) = HsTyVar noAnn NotPromoted n + cvt (KindedTyVar _ _ (L name_loc n) kind) = + HsKindSig + noAnn + (L (l2l name_loc) (HsTyVar noAnn NotPromoted (L name_loc n))) + kind + + -- \| Convert a LHsTyVarBndr to an equivalent LHsType. + hsLTyVarBndrToType :: LHsTyVarBndr flag GhcRn -> LHsType GhcRn + hsLTyVarBndrToType = fmap cvt + + extractFamDefDecl :: FamilyDecl GhcRn -> Type -> TyFamDefltDecl GhcRn + extractFamDefDecl fd rhs = + TyFamInstDecl noAnn $ + FamEqn + { feqn_ext = noAnn + , feqn_tycon = fdLName fd + , feqn_bndrs = HsOuterImplicit{hso_ximplicit = hsq_ext (fdTyVars fd)} + , feqn_pats = + map (HsValArg noExtField . hsLTyVarBndrToType) $ + hsq_explicit $ + fdTyVars fd + , feqn_fixity = fdFixity fd + , feqn_rhs = synifyType WithinType [] rhs + } + + extractAtItem + :: ClassATItem + -> Either String (LFamilyDecl GhcRn, Maybe (LTyFamDefltDecl GhcRn)) + extractAtItem (ATI at_tc def) = do + tyDecl <- synifyTyCon prr Nothing at_tc + famDecl <- extractFamilyDecl tyDecl + let defEqnTy = fmap (noLocA . extractFamDefDecl famDecl . fst) def + pure (noLocA famDecl, defEqnTy) + + atTyClDecls = map extractAtItem (classATItems cl) + (atFamDecls, atDefFamDecls) = unzip (rights atTyClDecls) + vs = tyConVisibleTyVars (classTyCon cl) + in withErrs (lefts atTyClDecls) . TyClD noExtField $ + ClassDecl + { -- This should not always be `Just`, since `Just` of an empty + -- context causes pretty printing to print `()` for the + -- context + tcdCtxt = + case classSCTheta cl of + [] -> Nothing + th -> Just $ synifyCtx th + , tcdLName = synifyNameN cl + , tcdTyVars = synifyTyVars vs + , tcdFixity = synifyFixity cl + , tcdFDs = + map + ( \(l, r) -> + noLocA + (FunDep noAnn (map (noLocA . getName) l) (map (noLocA . getName) r)) + ) + $ snd + $ classTvsFds cl + , tcdSigs = + noLocA (MinimalSig (noAnn, NoSourceText) . noLocA . fmap noLocA $ classMinimalDef cl) + : [ noLocA tcdSig | clsOp <- classOpItems cl - , tcdSig <- synifyTcIdSig vs clsOp ] - , tcdMeths = emptyBag --ignore default method definitions, they don't affect signature - -- class associated-types are a subset of TyCon: - , tcdATs = atFamDecls - , tcdATDefs = catMaybes atDefFamDecls - , tcdDocs = [] --we don't have any docs at this point - , tcdCExt = emptyNameSet - } - | otherwise - -> synifyTyCon prr Nothing tc >>= allOK . TyClD noExtField - + , tcdSig <- synifyTcIdSig vs clsOp + ] + , tcdMeths = emptyBag -- ignore default method definitions, they don't affect signature + -- class associated-types are a subset of TyCon: + , tcdATs = atFamDecls + , tcdATDefs = catMaybes atDefFamDecls + , tcdDocs = [] -- we don't have any docs at this point + , tcdCExt = emptyNameSet + } + | otherwise -> + synifyTyCon prr Nothing tc >>= allOK . TyClD noExtField -- type-constructors (e.g. Maybe) are complicated, put the definition -- later in the file (also it's used for class associated-types too.) ACoAxiom ax -> synifyAxiom ax >>= allOK - -- a data-constructor alone just gets rendered as a function: - AConLike (RealDataCon dc) -> allOK $ SigD noExtField (TypeSig noAnn [synifyNameN dc] - (synifySigWcType ImplicitizeForAll [] (dataConWrapperType dc))) - + AConLike (RealDataCon dc) -> + allOK $ + SigD + noExtField + ( TypeSig + noAnn + [synifyNameN dc] + (synifySigWcType ImplicitizeForAll [] (dataConWrapperType dc)) + ) AConLike (PatSynCon ps) -> allOK . SigD noExtField $ PatSynSig noAnn [synifyNameN ps] (synifyPatSynSigType ps) where @@ -179,65 +212,76 @@ tyThingToLHsDecl prr t = case t of allOK x = return (mempty, x) synifyAxBranch :: TyCon -> CoAxBranch -> TyFamInstEqn GhcRn -synifyAxBranch tc (CoAxBranch { cab_tvs = tkvs, cab_lhs = args, cab_rhs = rhs }) - = let name = synifyNameN tc - args_types_only = filterOutInvisibleTypes tc args - typats = map (synifyType WithinType []) args_types_only - annot_typats = zipWith3 annotHsType args_poly args_types_only typats - hs_rhs = synifyType WithinType [] rhs - outer_bndrs = HsOuterImplicit{hso_ximplicit = map tyVarName tkvs} - -- TODO: this must change eventually - in FamEqn { feqn_ext = noAnn - , feqn_tycon = name - , feqn_bndrs = outer_bndrs - , feqn_pats = map (HsValArg noExtField) annot_typats - , feqn_fixity = synifyFixity name - , feqn_rhs = hs_rhs } +synifyAxBranch tc (CoAxBranch{cab_tvs = tkvs, cab_lhs = args, cab_rhs = rhs}) = + let name = synifyNameN tc + args_types_only = filterOutInvisibleTypes tc args + typats = map (synifyType WithinType []) args_types_only + annot_typats = zipWith3 annotHsType args_poly args_types_only typats + hs_rhs = synifyType WithinType [] rhs + outer_bndrs = HsOuterImplicit{hso_ximplicit = map tyVarName tkvs} + in -- TODO: this must change eventually + FamEqn + { feqn_ext = noAnn + , feqn_tycon = name + , feqn_bndrs = outer_bndrs + , feqn_pats = map (HsValArg noExtField) annot_typats + , feqn_fixity = synifyFixity name + , feqn_rhs = hs_rhs + } where args_poly = tyConArgsPolyKinded tc synifyAxiom :: CoAxiom br -> Either String (HsDecl GhcRn) -synifyAxiom ax@(CoAxiom { co_ax_tc = tc }) +synifyAxiom ax@(CoAxiom{co_ax_tc = tc}) | isOpenTypeFamilyTyCon tc - , Just branch <- coAxiomSingleBranch_maybe ax - = return $ InstD noExtField - $ TyFamInstD noExtField - $ TyFamInstDecl { tfid_xtn = noAnn, tfid_eqn = synifyAxBranch tc branch } - + , Just branch <- coAxiomSingleBranch_maybe ax = + return $ + InstD noExtField $ + TyFamInstD noExtField $ + TyFamInstDecl{tfid_xtn = noAnn, tfid_eqn = synifyAxBranch tc branch} | Just ax' <- isClosedSynFamilyTyConWithAxiom_maybe tc - , getUnique ax' == getUnique ax -- without the getUniques, type error - = synifyTyCon ShowRuntimeRep (Just ax) tc >>= return . TyClD noExtField - - | otherwise - = Left "synifyAxiom: closed/open family confusion" + , getUnique ax' == getUnique ax -- without the getUniques, type error + = + synifyTyCon ShowRuntimeRep (Just ax) tc >>= return . TyClD noExtField + | otherwise = + Left "synifyAxiom: closed/open family confusion" -- | Turn type constructors into data declarations, type families, or type synonyms synifyTyCon :: PrintRuntimeReps - -> Maybe (CoAxiom br) -- ^ RHS of type synonym - -> TyCon -- ^ type constructor to convert + -> Maybe (CoAxiom br) + -- ^ RHS of type synonym + -> TyCon + -- ^ type constructor to convert -> Either String (TyClDecl GhcRn) synifyTyCon prr _coax tc - | isPrimTyCon tc - = return $ - DataDecl { tcdLName = synifyNameN tc - , tcdTyVars = HsQTvs { hsq_ext = [] -- No kind polymorphism - , hsq_explicit = zipWith mk_hs_tv - (map scaledThing tyVarKinds) - alphaTyVars --a, b, c... which are unfortunately all kind * - } - - , tcdFixity = synifyFixity tc - - , tcdDataDefn = HsDataDefn { dd_ext = noExtField - , dd_cons = DataTypeCons False [] -- No constructors; arbitrary lie, they are neither - -- algebraic data nor newtype: - , dd_ctxt = Nothing - , dd_cType = Nothing - , dd_kindSig = synifyDataTyConReturnKind tc - -- we have their kind accurately: - , dd_derivs = [] } - , tcdDExt = DataDeclRn False emptyNameSet } + | isPrimTyCon tc = + return $ + DataDecl + { tcdLName = synifyNameN tc + , tcdTyVars = + HsQTvs + { hsq_ext = [] -- No kind polymorphism + , hsq_explicit = + zipWith + mk_hs_tv + (map scaledThing tyVarKinds) + alphaTyVars -- a, b, c... which are unfortunately all kind * + } + , tcdFixity = synifyFixity tc + , tcdDataDefn = + HsDataDefn + { dd_ext = noExtField + , dd_cons = DataTypeCons False [] -- No constructors; arbitrary lie, they are neither + -- algebraic data nor newtype: + , dd_ctxt = Nothing + , dd_cType = Nothing + , dd_kindSig = synifyDataTyConReturnKind tc + , -- we have their kind accurately: + dd_derivs = [] + } + , tcdDExt = DataDeclRn False emptyNameSet + } where -- tyConTyVars doesn't work on fun/prim, but we can make them up: mk_hs_tv realKind fakeTyVar @@ -246,120 +290,131 @@ synifyTyCon prr _coax tc conKind = defaultType prr (tyConKind tc) tyVarKinds = fst . splitFunTys . snd . splitInvisPiTys $ conKind - synifyTyCon _prr _coax tc - | Just flav <- famTyConFlav_maybe tc - = case flav of - -- Type families - OpenSynFamilyTyCon -> mkFamDecl OpenTypeFamily - ClosedSynFamilyTyCon mb - | Just (CoAxiom { co_ax_branches = branches }) <- mb - -> mkFamDecl $ ClosedTypeFamily $ Just - $ map (noLocA . synifyAxBranch tc) (fromBranches branches) - | otherwise - -> mkFamDecl $ ClosedTypeFamily $ Just [] - BuiltInSynFamTyCon {} - -> mkFamDecl $ ClosedTypeFamily $ Just [] - AbstractClosedSynFamilyTyCon {} - -> mkFamDecl $ ClosedTypeFamily Nothing - DataFamilyTyCon {} - -> mkFamDecl DataFamily + | Just flav <- famTyConFlav_maybe tc = + case flav of + -- Type families + OpenSynFamilyTyCon -> mkFamDecl OpenTypeFamily + ClosedSynFamilyTyCon mb + | Just (CoAxiom{co_ax_branches = branches}) <- mb -> + mkFamDecl $ + ClosedTypeFamily $ + Just $ + map (noLocA . synifyAxBranch tc) (fromBranches branches) + | otherwise -> + mkFamDecl $ ClosedTypeFamily $ Just [] + BuiltInSynFamTyCon{} -> + mkFamDecl $ ClosedTypeFamily $ Just [] + AbstractClosedSynFamilyTyCon{} -> + mkFamDecl $ ClosedTypeFamily Nothing + DataFamilyTyCon{} -> + mkFamDecl DataFamily where resultVar = tyConFamilyResVar_maybe tc - mkFamDecl i = return $ FamDecl noExtField $ - FamilyDecl - { fdExt = noAnn - , fdInfo = i - , fdTopLevel = TopLevel - , fdLName = synifyNameN tc - , fdTyVars = synifyTyVars (tyConVisibleTyVars tc) - , fdFixity = synifyFixity tc - , fdResultSig = synifyFamilyResultSig resultVar (tyConResKind tc) - , fdInjectivityAnn = - synifyInjectivityAnn - resultVar - (tyConTyVars tc) - (tyConInjectivityInfo tc) - } - + mkFamDecl i = + return $ + FamDecl noExtField $ + FamilyDecl + { fdExt = noAnn + , fdInfo = i + , fdTopLevel = TopLevel + , fdLName = synifyNameN tc + , fdTyVars = synifyTyVars (tyConVisibleTyVars tc) + , fdFixity = synifyFixity tc + , fdResultSig = synifyFamilyResultSig resultVar (tyConResKind tc) + , fdInjectivityAnn = + synifyInjectivityAnn + resultVar + (tyConTyVars tc) + (tyConInjectivityInfo tc) + } synifyTyCon _prr coax tc -- type synonyms - | Just ty <- synTyConRhs_maybe tc - = return $ SynDecl { tcdSExt = emptyNameSet - , tcdLName = synifyNameN tc - , tcdTyVars = synifyTyVars (tyConVisibleTyVars tc) - , tcdFixity = synifyFixity tc - , tcdRhs = synifyType WithinType [] ty - } - + | Just ty <- synTyConRhs_maybe tc = + return $ + SynDecl + { tcdSExt = emptyNameSet + , tcdLName = synifyNameN tc + , tcdTyVars = synifyTyVars (tyConVisibleTyVars tc) + , tcdFixity = synifyFixity tc + , tcdRhs = synifyType WithinType [] ty + } -- (closed) newtype and data | otherwise = do - let -- This should not always be `Just`, since `Just` of an empty - -- context causes pretty printing to print `()` for the context - alg_ctx = - case tyConStupidTheta tc of - [] -> Nothing - th -> Just $ synifyCtx th - - -- Data families are named according to their CoAxioms, not their TyCons - name = case coax of - Just a -> synifyNameN a - _ -> synifyNameN tc - - -- For a data declaration: - -- data Vec :: Nat -> Type -> Type where - -- GHC will still report visible tyvars with default names 'a' and 'b'. - -- Since 'Nat' is not inhabited by lifted types, 'a' will be given a kind - -- signature (due to the logic in 'synify_ty_var'). Similarly, 'Vec' - -- constructs lifted types and will therefore not be given a result kind - -- signature. Thus, the generated documentation for 'Vec' will look like: - -- data Vec (a :: Nat) b where - tyvars = synifyTyVars (tyConVisibleTyVars tc) - kindSig = synifyDataTyConReturnKind tc - - -- The data constructors. - -- - -- Any data-constructors not exported from the module that *defines* the - -- type will not (cannot) be included. - -- - -- Very simple constructors, Haskell98 with no existentials or anything, - -- probably look nicer in non-GADT syntax. In source code, all constructors - -- must be declared with the same (GADT vs. not) syntax, and it probably - -- is less confusing to follow that principle for the documentation as well. - -- - -- There is no sensible infix-representation for GADT-syntax constructor - -- declarations. They cannot be made in source code, but we could end up - -- with some here in the case where some constructors use existentials. - -- That seems like an acceptable compromise (they'll just be documented - -- in prefix position), since, otherwise, the logic (at best) gets much more - -- complicated. (would use dataConIsInfix.) - use_gadt_syntax = isGadtSyntaxTyCon tc - - consRaw <- - case partitionEithers - $ synifyDataCon use_gadt_syntax - <$> tyConDataCons tc - of - ([], cs) -> Right cs - (errs, _) -> Left (unlines errs) - - cons <- case (isNewTyCon tc, consRaw) of - (False, cons) -> Right (DataTypeCons False cons) - (True, [con]) -> Right (NewTypeCon con) - (True, _) -> Left "Newtype hasn't 1 constructor" - - let -- "deriving" doesn't affect the signature, no need to specify any. - alg_deriv = [] - defn = HsDataDefn { dd_ext = noExtField - , dd_ctxt = alg_ctx - , dd_cType = Nothing - , dd_kindSig = kindSig - , dd_cons = cons - , dd_derivs = alg_deriv } - pure DataDecl { tcdLName = name, tcdTyVars = tyvars - , tcdFixity = synifyFixity name - , tcdDataDefn = defn - , tcdDExt = DataDeclRn False emptyNameSet } + let + -- This should not always be `Just`, since `Just` of an empty + -- context causes pretty printing to print `()` for the context + alg_ctx = + case tyConStupidTheta tc of + [] -> Nothing + th -> Just $ synifyCtx th + + -- Data families are named according to their CoAxioms, not their TyCons + name = case coax of + Just a -> synifyNameN a + _ -> synifyNameN tc + + -- For a data declaration: + -- data Vec :: Nat -> Type -> Type where + -- GHC will still report visible tyvars with default names 'a' and 'b'. + -- Since 'Nat' is not inhabited by lifted types, 'a' will be given a kind + -- signature (due to the logic in 'synify_ty_var'). Similarly, 'Vec' + -- constructs lifted types and will therefore not be given a result kind + -- signature. Thus, the generated documentation for 'Vec' will look like: + -- data Vec (a :: Nat) b where + tyvars = synifyTyVars (tyConVisibleTyVars tc) + kindSig = synifyDataTyConReturnKind tc + + -- The data constructors. + -- + -- Any data-constructors not exported from the module that *defines* the + -- type will not (cannot) be included. + -- + -- Very simple constructors, Haskell98 with no existentials or anything, + -- probably look nicer in non-GADT syntax. In source code, all constructors + -- must be declared with the same (GADT vs. not) syntax, and it probably + -- is less confusing to follow that principle for the documentation as well. + -- + -- There is no sensible infix-representation for GADT-syntax constructor + -- declarations. They cannot be made in source code, but we could end up + -- with some here in the case where some constructors use existentials. + -- That seems like an acceptable compromise (they'll just be documented + -- in prefix position), since, otherwise, the logic (at best) gets much more + -- complicated. (would use dataConIsInfix.) + use_gadt_syntax = isGadtSyntaxTyCon tc + + consRaw <- + case partitionEithers $ + synifyDataCon use_gadt_syntax + <$> tyConDataCons tc of + ([], cs) -> Right cs + (errs, _) -> Left (unlines errs) + + cons <- case (isNewTyCon tc, consRaw) of + (False, cons) -> Right (DataTypeCons False cons) + (True, [con]) -> Right (NewTypeCon con) + (True, _) -> Left "Newtype hasn't 1 constructor" + + let + -- "deriving" doesn't affect the signature, no need to specify any. + alg_deriv = [] + defn = + HsDataDefn + { dd_ext = noExtField + , dd_ctxt = alg_ctx + , dd_cType = Nothing + , dd_kindSig = kindSig + , dd_cons = cons + , dd_derivs = alg_deriv + } + pure + DataDecl + { tcdLName = name + , tcdTyVars = tyvars + , tcdFixity = synifyFixity name + , tcdDataDefn = defn + , tcdDExt = DataDeclRn False emptyNameSet + } -- | In this module, every TyCon being considered has come from an interface -- file. This means that when considering a data type constructor such as: @@ -378,99 +433,119 @@ synifyTyCon _prr coax tc synifyDataTyConReturnKind :: TyCon -> Maybe (LHsKind GhcRn) synifyDataTyConReturnKind tc | isLiftedTypeKind ret_kind = Nothing -- Don't bother displaying :: * - | otherwise = Just (synifyKindSig ret_kind) - where ret_kind = tyConResKind tc + | otherwise = Just (synifyKindSig ret_kind) + where + ret_kind = tyConResKind tc -synifyInjectivityAnn :: Maybe Name -> [TyVar] -> Injectivity - -> Maybe (LInjectivityAnn GhcRn) +synifyInjectivityAnn + :: Maybe Name + -> [TyVar] + -> Injectivity + -> Maybe (LInjectivityAnn GhcRn) synifyInjectivityAnn (Just lhs) tvs (Injective inj) = - let rhs = map (noLocA . tyVarName) (filterByList inj tvs) - in Just $ noLocA $ InjectivityAnn noAnn (noLocA lhs) rhs + let rhs = map (noLocA . tyVarName) (filterByList inj tvs) + in Just $ noLocA $ InjectivityAnn noAnn (noLocA lhs) rhs synifyInjectivityAnn _ _ _ = Nothing synifyFamilyResultSig :: Maybe Name -> Kind -> LFamilyResultSig GhcRn synifyFamilyResultSig Nothing kind - | isLiftedTypeKind kind - = noLocA $ NoSig noExtField - | otherwise - = noLocA $ KindSig noExtField (synifyKindSig kind) + | isLiftedTypeKind kind = + noLocA $ NoSig noExtField + | otherwise = + noLocA $ KindSig noExtField (synifyKindSig kind) synifyFamilyResultSig (Just name) kind = - noLocA $ TyVarSig noExtField (noLocA $ KindedTyVar noAnn () (noLocA name) (synifyKindSig kind)) + noLocA $ TyVarSig noExtField (noLocA $ KindedTyVar noAnn () (noLocA name) (synifyKindSig kind)) -- User beware: it is your responsibility to pass True (use_gadt_syntax) for any -- constructor that would be misrepresented by omitting its result-type. But you -- might want pass False in simple enough cases, if you think it looks better. synifyDataCon :: Bool -> DataCon -> Either String (LConDecl GhcRn) synifyDataCon use_gadt_syntax dc = - let - -- dataConIsInfix allegedly tells us whether it was declared with - -- infix *syntax*. - use_infix_syntax = dataConIsInfix dc - use_named_field_syntax = not (null field_tys) - name = synifyNameN dc - -- con_qvars means a different thing depending on gadt-syntax - (_univ_tvs, ex_tvs, _eq_spec, theta, arg_tys, res_ty) = dataConFullSig dc - user_tvbndrs = dataConUserTyVarBinders dc -- Used for GADT data constructors - - outer_bndrs | null user_tvbndrs - = HsOuterImplicit { hso_ximplicit = [] } - | otherwise - = HsOuterExplicit { hso_xexplicit = noExtField - , hso_bndrs = map synifyTyVarBndr user_tvbndrs } - - -- skip any EqTheta, use 'orig'inal syntax - ctx | null theta = Nothing + let + -- dataConIsInfix allegedly tells us whether it was declared with + -- infix *syntax*. + use_infix_syntax = dataConIsInfix dc + use_named_field_syntax = not (null field_tys) + name = synifyNameN dc + -- con_qvars means a different thing depending on gadt-syntax + (_univ_tvs, ex_tvs, _eq_spec, theta, arg_tys, res_ty) = dataConFullSig dc + user_tvbndrs = dataConUserTyVarBinders dc -- Used for GADT data constructors + outer_bndrs + | null user_tvbndrs = + HsOuterImplicit{hso_ximplicit = []} + | otherwise = + HsOuterExplicit + { hso_xexplicit = noExtField + , hso_bndrs = map synifyTyVarBndr user_tvbndrs + } + + -- skip any EqTheta, use 'orig'inal syntax + ctx + | null theta = Nothing | otherwise = Just $ synifyCtx theta - linear_tys = - zipWith (\ty bang -> - let tySyn = synifyType WithinType [] (scaledThing ty) - in case bang of - (HsSrcBang _ NoSrcUnpack NoSrcStrict) -> tySyn - bang' -> noLocA $ HsBangTy noAnn bang' tySyn) - arg_tys (dataConSrcBangs dc) - - field_tys = zipWith con_decl_field (dataConFieldLabels dc) linear_tys - con_decl_field fl synTy = noLocA $ - ConDeclField noAnn [noLocA $ FieldOcc (flSelector fl) (noLocA $ mkVarUnqual $ field_label $ flLabel fl)] synTy - Nothing - - mk_h98_arg_tys :: Either String (HsConDeclH98Details GhcRn) - mk_h98_arg_tys = case (use_named_field_syntax, use_infix_syntax) of - (True,True) -> Left "synifyDataCon: contradiction!" - (True,False) -> return $ RecCon (noLocA field_tys) - (False,False) -> return $ PrefixCon noTypeArgs (map hsUnrestricted linear_tys) - (False,True) -> case linear_tys of - [a,b] -> return $ InfixCon (hsUnrestricted a) (hsUnrestricted b) - _ -> Left "synifyDataCon: infix with non-2 args?" - - mk_gadt_arg_tys :: HsConDeclGADTDetails GhcRn - mk_gadt_arg_tys - | use_named_field_syntax = RecConGADT noExtField (noLocA field_tys) - | otherwise = PrefixConGADT noExtField (map hsUnrestricted linear_tys) - - -- finally we get synifyDataCon's result! - in if use_gadt_syntax - then do - let hat = mk_gadt_arg_tys - return $ noLocA $ ConDeclGADT - { con_g_ext = noExtField - , con_names = pure name - , con_bndrs = noLocA outer_bndrs - , con_mb_cxt = ctx - , con_g_args = hat - , con_res_ty = synifyType WithinType [] res_ty - , con_doc = Nothing } - else do - hat <- mk_h98_arg_tys - return $ noLocA $ ConDeclH98 - { con_ext = noExtField - , con_name = name - , con_forall = False - , con_ex_tvs = map (synifyTyVarBndr . (mkForAllTyBinder InferredSpec)) ex_tvs - , con_mb_cxt = ctx - , con_args = hat - , con_doc = Nothing } + linear_tys = + zipWith + ( \ty bang -> + let tySyn = synifyType WithinType [] (scaledThing ty) + in case bang of + (HsSrcBang _ NoSrcUnpack NoSrcStrict) -> tySyn + bang' -> noLocA $ HsBangTy noAnn bang' tySyn + ) + arg_tys + (dataConSrcBangs dc) + + field_tys = zipWith con_decl_field (dataConFieldLabels dc) linear_tys + con_decl_field fl synTy = + noLocA $ + ConDeclField + noAnn + [noLocA $ FieldOcc (flSelector fl) (noLocA $ mkVarUnqual $ field_label $ flLabel fl)] + synTy + Nothing + + mk_h98_arg_tys :: Either String (HsConDeclH98Details GhcRn) + mk_h98_arg_tys = case (use_named_field_syntax, use_infix_syntax) of + (True, True) -> Left "synifyDataCon: contradiction!" + (True, False) -> return $ RecCon (noLocA field_tys) + (False, False) -> return $ PrefixCon noTypeArgs (map hsUnrestricted linear_tys) + (False, True) -> case linear_tys of + [a, b] -> return $ InfixCon (hsUnrestricted a) (hsUnrestricted b) + _ -> Left "synifyDataCon: infix with non-2 args?" + + mk_gadt_arg_tys :: HsConDeclGADTDetails GhcRn + mk_gadt_arg_tys + | use_named_field_syntax = RecConGADT noExtField (noLocA field_tys) + | otherwise = PrefixConGADT noExtField (map hsUnrestricted linear_tys) + in + -- finally we get synifyDataCon's result! + if use_gadt_syntax + then do + let hat = mk_gadt_arg_tys + return $ + noLocA $ + ConDeclGADT + { con_g_ext = noExtField + , con_names = pure name + , con_bndrs = noLocA outer_bndrs + , con_mb_cxt = ctx + , con_g_args = hat + , con_res_ty = synifyType WithinType [] res_ty + , con_doc = Nothing + } + else do + hat <- mk_h98_arg_tys + return $ + noLocA $ + ConDeclH98 + { con_ext = noExtField + , con_name = name + , con_forall = False + , con_ex_tvs = map (synifyTyVarBndr . (mkForAllTyBinder InferredSpec)) ex_tvs + , con_mb_cxt = ctx + , con_args = hat + , con_doc = Nothing + } synifyNameN :: NamedThing n => n -> LocatedN Name synifyNameN n = L (noAnnSrcSpan $! srcLocSpan (getSrcLoc n)) (getName n) @@ -482,14 +557,19 @@ synifyNameN n = L (noAnnSrcSpan $! srcLocSpan (getSrcLoc n)) (getName n) -- a user can always declare an infix name in prefix form or a prefix name in -- infix form. Unfortunately, that is not something we can usually reconstruct. synifyFixity :: NamedThing n => n -> LexicalFixity -synifyFixity n | isSymOcc (getOccName n) = Infix - | otherwise = Prefix +synifyFixity n + | isSymOcc (getOccName n) = Infix + | otherwise = Prefix synifyIdSig - :: PrintRuntimeReps -- ^ are we printing tyvars of kind 'RuntimeRep'? - -> SynifyTypeState -- ^ what to do with a 'forall' - -> [TyVar] -- ^ free variables in the type to convert - -> Id -- ^ the 'Id' from which to get the type signature + :: PrintRuntimeReps + -- ^ are we printing tyvars of kind 'RuntimeRep'? + -> SynifyTypeState + -- ^ what to do with a 'forall' + -> [TyVar] + -- ^ free variables in the type to convert + -> Id + -- ^ the 'Id' from which to get the type signature -> Sig GhcRn synifyIdSig prr s vs i = TypeSig noAnn [n] (synifySigWcType s vs t) where @@ -501,9 +581,10 @@ synifyIdSig prr s vs i = TypeSig noAnn [n] (synifySigWcType s vs t) -- 'ClassOpSig'. synifyTcIdSig :: [TyVar] -> ClassOpItem -> [Sig GhcRn] synifyTcIdSig vs (i, dm) = - [ ClassOpSig noAnn False [synifyNameN i] (mainSig (varType i)) ] ++ - [ ClassOpSig noAnn True [noLocA dn] (defSig dt) - | Just (dn, GenericDM dt) <- [dm] ] + [ClassOpSig noAnn False [synifyNameN i] (mainSig (varType i))] + ++ [ ClassOpSig noAnn True [noLocA dn] (defSig dt) + | Just (dn, GenericDM dt) <- [dm] + ] where mainSig t = synifySigType DeleteTopLevelQuantification vs t defSig t = synifySigType ImplicitizeForAll vs t @@ -511,10 +592,12 @@ synifyTcIdSig vs (i, dm) = synifyCtx :: [PredType] -> LHsContext GhcRn synifyCtx ts = noLocA (map (synifyType WithinType []) ts) - synifyTyVars :: [TyVar] -> LHsQTyVars GhcRn -synifyTyVars ktvs = HsQTvs { hsq_ext = [] - , hsq_explicit = map synifyTyVar ktvs } +synifyTyVars ktvs = + HsQTvs + { hsq_ext = [] + , hsq_explicit = map synifyTyVar ktvs + } synifyTyVar :: TyVar -> LHsTyVarBndr (HsBndrVis GhcRn) GhcRn synifyTyVar = synify_ty_var emptyVarSet (HsBndrRequired noExtField) @@ -529,10 +612,10 @@ synifyTyVarBndr' no_kinds (Bndr tv spec) = synify_ty_var no_kinds spec tv -- signatures (even if they don't have the lifted type kind). synify_ty_var :: VarSet -> flag -> TyVar -> LHsTyVarBndr flag GhcRn synify_ty_var no_kinds flag tv - | isLiftedTypeKind kind || tv `elemVarSet` no_kinds - = noLocA (UserTyVar noAnn flag (noLocA name)) - | otherwise - = noLocA (KindedTyVar noAnn flag (noLocA name) (synifyKindSig kind)) + | isLiftedTypeKind kind || tv `elemVarSet` no_kinds = + noLocA (UserTyVar noAnn flag (noLocA name)) + | otherwise = + noLocA (KindedTyVar noAnn flag (noLocA name) (synifyKindSig kind)) where kind = tyVarKind tv name = getName tv @@ -541,31 +624,35 @@ synify_ty_var no_kinds flag tv -- and if the type contains a free variable. -- This is used to synify type patterns for poly-kinded tyvars in -- synifying class and type instances. -annotHsType :: Bool -- True <=> annotate - -> Type -> LHsType GhcRn -> LHsType GhcRn - -- tiny optimization: if the type is annotated, don't annotate again. -annotHsType _ _ hs_ty@(L _ (HsKindSig {})) = hs_ty +annotHsType + :: Bool -- True <=> annotate + -> Type + -> LHsType GhcRn + -> LHsType GhcRn +-- tiny optimization: if the type is annotated, don't annotate again. +annotHsType _ _ hs_ty@(L _ (HsKindSig{})) = hs_ty annotHsType True ty hs_ty - | not $ isEmptyVarSet $ filterVarSet isTyVar $ tyCoVarsOfType ty - = let ki = typeKind ty - hs_ki = synifyType WithinType [] ki - in noLocA (HsKindSig noAnn hs_ty hs_ki) -annotHsType _ _ hs_ty = hs_ty + | not $ isEmptyVarSet $ filterVarSet isTyVar $ tyCoVarsOfType ty = + let ki = typeKind ty + hs_ki = synifyType WithinType [] ki + in noLocA (HsKindSig noAnn hs_ty hs_ki) +annotHsType _ _ hs_ty = hs_ty -- | For every argument type that a type constructor accepts, -- report whether or not the argument is poly-kinded. This is used to -- eventually feed into 'annotThType'. tyConArgsPolyKinded :: TyCon -> [Bool] tyConArgsPolyKinded tc = - map (is_poly_ty . tyVarKind) tc_vis_tvs - ++ map (is_poly_ty . piTyBinderType) tc_res_kind_vis_bndrs - ++ repeat True + map (is_poly_ty . tyVarKind) tc_vis_tvs + ++ map (is_poly_ty . piTyBinderType) tc_res_kind_vis_bndrs + ++ repeat True where is_poly_ty :: Type -> Bool - is_poly_ty ty = not $ - isEmptyVarSet $ - filterVarSet isTyVar $ - tyCoVarsOfType ty + is_poly_ty ty = + not $ + isEmptyVarSet $ + filterVarSet isTyVar $ + tyCoVarsOfType ty tc_vis_tvs :: [TyVar] tc_vis_tvs = tyConVisibleTyVars tc @@ -573,22 +660,21 @@ tyConArgsPolyKinded tc = tc_res_kind_vis_bndrs :: [PiTyBinder] tc_res_kind_vis_bndrs = filter isVisiblePiTyBinder $ fst $ splitPiTys $ tyConResKind tc ---states of what to do with foralls: +-- states of what to do with foralls: data SynifyTypeState - = WithinType - -- ^ normal situation. This is the safe one to use if you don't - -- quite understand what's going on. - | ImplicitizeForAll - -- ^ beginning of a function definition, in which, to make it look - -- less ugly, those rank-1 foralls (without kind annotations) are made - -- implicit. - | DeleteTopLevelQuantification - -- ^ because in class methods the context is added to the type - -- (e.g. adding @forall a. Num a =>@ to @(+) :: a -> a -> a@) - -- which is rather sensible, - -- but we want to restore things to the source-syntax situation where - -- the defining class gets to quantify all its functions for free! - + = -- | normal situation. This is the safe one to use if you don't + -- quite understand what's going on. + WithinType + | -- | beginning of a function definition, in which, to make it look + -- less ugly, those rank-1 foralls (without kind annotations) are made + -- implicit. + ImplicitizeForAll + | -- | because in class methods the context is added to the type + -- (e.g. adding @forall a. Num a =>@ to @(+) :: a -> a -> a@) + -- which is rather sensible, + -- but we want to restore things to the source-syntax situation where + -- the defining class gets to quantify all its functions for free! + DeleteTopLevelQuantification synifySigType :: SynifyTypeState -> [TyVar] -> Type -> LHsSigType GhcRn -- The use of mkEmptySigType (which uses empty binders in OuterImplicit) @@ -611,13 +697,16 @@ defaultType HideRuntimeRep = defaultRuntimeRepVars -- | Convert a core type into an 'HsType'. synifyType - :: SynifyTypeState -- ^ what to do with a 'forall' - -> [TyVar] -- ^ free variables in the type to convert - -> Type -- ^ the type to convert + :: SynifyTypeState + -- ^ what to do with a 'forall' + -> [TyVar] + -- ^ free variables in the type to convert + -> Type + -- ^ the type to convert -> LHsType GhcRn synifyType _ _ (TyVarTy tv) = noLocA $ HsTyVar noAnn NotPromoted $ noLocA (getName tv) -synifyType _ vs (TyConApp tc tys) - = maybe_sig res_ty +synifyType _ vs (TyConApp tc tys) = + maybe_sig res_ty where res_ty :: LHsType GhcRn res_ty @@ -625,121 +714,127 @@ synifyType _ vs (TyConApp tc tys) | tc `hasKey` tYPETyConKey , [TyConApp rep [TyConApp lev []]] <- tys , rep `hasKey` boxedRepDataConKey - , lev `hasKey` liftedDataConKey - = noLocA (HsTyVar noAnn NotPromoted (noLocA liftedTypeKindTyConName)) - + , lev `hasKey` liftedDataConKey = + noLocA (HsTyVar noAnn NotPromoted (noLocA liftedTypeKindTyConName)) -- Use non-prefix tuple syntax where possible, because it looks nicer. | Just sort <- tyConTuple_maybe tc - , tyConArity tc == tys_len - = noLocA $ HsTupleTy noAnn - (case sort of - BoxedTuple -> HsBoxedOrConstraintTuple - ConstraintTuple -> HsBoxedOrConstraintTuple - UnboxedTuple -> HsUnboxedTuple) - (map (synifyType WithinType vs) vis_tys) - - | isUnboxedSumTyCon tc - = noLocA $ HsSumTy noAnn (map (synifyType WithinType vs) vis_tys) - + , tyConArity tc == tys_len = + noLocA $ + HsTupleTy + noAnn + ( case sort of + BoxedTuple -> HsBoxedOrConstraintTuple + ConstraintTuple -> HsBoxedOrConstraintTuple + UnboxedTuple -> HsUnboxedTuple + ) + (map (synifyType WithinType vs) vis_tys) + | isUnboxedSumTyCon tc = + noLocA $ HsSumTy noAnn (map (synifyType WithinType vs) vis_tys) | Just dc <- isPromotedDataCon_maybe tc , isTupleDataCon dc - , dataConSourceArity dc == length vis_tys - = noLocA $ HsExplicitTupleTy noExtField (map (synifyType WithinType vs) vis_tys) - + , dataConSourceArity dc == length vis_tys = + noLocA $ HsExplicitTupleTy noExtField (map (synifyType WithinType vs) vis_tys) -- ditto for lists - | getName tc == listTyConName, [ty] <- vis_tys - = noLocA $ HsListTy noAnn (synifyType WithinType vs ty) - - | tc == promotedNilDataCon, [] <- vis_tys - = noLocA $ HsExplicitListTy noExtField IsPromoted [] - + | getName tc == listTyConName + , [ty] <- vis_tys = + noLocA $ HsListTy noAnn (synifyType WithinType vs ty) + | tc == promotedNilDataCon + , [] <- vis_tys = + noLocA $ HsExplicitListTy noExtField IsPromoted [] | tc == promotedConsDataCon - , [ty1, ty2] <- vis_tys - = let hTy = synifyType WithinType vs ty1 - in case synifyType WithinType vs ty2 of - tTy | L _ (HsExplicitListTy _ IsPromoted tTy') <- stripKindSig tTy - -> noLocA $ HsExplicitListTy noExtField IsPromoted (hTy : tTy') - | otherwise - -> noLocA $ HsOpTy noAnn IsPromoted hTy (noLocA $ getName tc) tTy - + , [ty1, ty2] <- vis_tys = + let hTy = synifyType WithinType vs ty1 + in case synifyType WithinType vs ty2 of + tTy + | L _ (HsExplicitListTy _ IsPromoted tTy') <- stripKindSig tTy -> + noLocA $ HsExplicitListTy noExtField IsPromoted (hTy : tTy') + | otherwise -> + noLocA $ HsOpTy noAnn IsPromoted hTy (noLocA $ getName tc) tTy -- ditto for implicit parameter tycons | tc `hasKey` ipClassKey , [name, ty] <- tys - , Just x <- isStrLitTy name - = noLocA $ HsIParamTy noAnn (noLocA $ HsIPName x) (synifyType WithinType vs ty) - + , Just x <- isStrLitTy name = + noLocA $ HsIParamTy noAnn (noLocA $ HsIPName x) (synifyType WithinType vs ty) -- and equalities | tc `hasKey` eqTyConKey - , [ty1, ty2] <- tys - = noLocA $ HsOpTy noAnn - NotPromoted - (synifyType WithinType vs ty1) - (noLocA eqTyConName) - (synifyType WithinType vs ty2) - + , [ty1, ty2] <- tys = + noLocA $ + HsOpTy + noAnn + NotPromoted + (synifyType WithinType vs ty1) + (noLocA eqTyConName) + (synifyType WithinType vs ty2) -- and infix type operators | isSymOcc (nameOccName (getName tc)) - , ty1:ty2:tys_rest <- vis_tys - = mk_app_tys (HsOpTy noAnn - prom - (synifyType WithinType vs ty1) - (noLocA $ getName tc) - (synifyType WithinType vs ty2)) - tys_rest - + , ty1 : ty2 : tys_rest <- vis_tys = + mk_app_tys + ( HsOpTy + noAnn + prom + (synifyType WithinType vs ty1) + (noLocA $ getName tc) + (synifyType WithinType vs ty2) + ) + tys_rest -- Most TyCons: - | otherwise - = mk_app_tys (HsTyVar noAnn prom $ noLocA (getName tc)) - vis_tys + | otherwise = + mk_app_tys + (HsTyVar noAnn prom $ noLocA (getName tc)) + vis_tys where !prom = if isPromotedDataCon tc then IsPromoted else NotPromoted mk_app_tys ty_app ty_args = - foldl (\t1 t2 -> noLocA $ HsAppTy noExtField t1 t2) - (noLocA ty_app) - (map (synifyType WithinType vs) $ - filterOut isCoercionTy ty_args) + foldl + (\t1 t2 -> noLocA $ HsAppTy noExtField t1 t2) + (noLocA ty_app) + ( map (synifyType WithinType vs) $ + filterOut isCoercionTy ty_args + ) tys_len = length tys vis_tys = filterOutInvisibleTypes tc tys maybe_sig :: LHsType GhcRn -> LHsType GhcRn maybe_sig ty' - | tyConAppNeedsKindSig False tc tys_len - = let full_kind = typeKind (mkTyConApp tc tys) - full_kind' = synifyType WithinType vs full_kind - in noLocA $ HsKindSig noAnn ty' full_kind' + | tyConAppNeedsKindSig False tc tys_len = + let full_kind = typeKind (mkTyConApp tc tys) + full_kind' = synifyType WithinType vs full_kind + in noLocA $ HsKindSig noAnn ty' full_kind' | otherwise = ty' - -synifyType _ vs ty@(AppTy {}) = let - (ty_head, ty_args) = splitAppTys ty - ty_head' = synifyType WithinType vs ty_head - ty_args' = map (synifyType WithinType vs) $ - filterOut isCoercionTy $ - filterByList (map isVisibleForAllTyFlag $ appTyForAllTyFlags ty_head ty_args) - ty_args - in foldl (\t1 t2 -> noLocA $ HsAppTy noExtField t1 t2) ty_head' ty_args' - +synifyType _ vs ty@(AppTy{}) = + let + (ty_head, ty_args) = splitAppTys ty + ty_head' = synifyType WithinType vs ty_head + ty_args' = + map (synifyType WithinType vs) $ + filterOut isCoercionTy $ + filterByList + (map isVisibleForAllTyFlag $ appTyForAllTyFlags ty_head ty_args) + ty_args + in + foldl (\t1 t2 -> noLocA $ HsAppTy noExtField t1 t2) ty_head' ty_args' synifyType s vs funty@(FunTy af w t1 t2) | isInvisibleFunArg af = synifySigmaType s vs funty - | otherwise = noLocA $ HsFunTy noExtField w' s1 s2 + | otherwise = noLocA $ HsFunTy noExtField w' s1 s2 where s1 = synifyType WithinType vs t1 s2 = synifyType WithinType vs t2 w' = synifyMult vs w - synifyType s vs forallty@(ForAllTy (Bndr _ argf) _ty) = case argf of - Required -> synifyVisForAllType vs forallty + Required -> synifyVisForAllType vs forallty Invisible _ -> synifySigmaType s vs forallty - synifyType _ _ (LitTy t) = noLocA $ HsTyLit noExtField $ synifyTyLit t synifyType s vs (CastTy t _) = synifyType s vs t -synifyType _ _ (CoercionTy {}) = error "synifyType:Coercion" +synifyType _ _ (CoercionTy{}) = error "synifyType:Coercion" -- | Process a 'Type' which starts with a visible @forall@ into an 'HsType' synifyVisForAllType - :: [TyVar] -- ^ free variables in the type to convert - -> Type -- ^ the forall type to convert + :: [TyVar] + -- ^ free variables in the type to convert + -> Type + -- ^ the forall type to convert -> LHsType GhcRn synifyVisForAllType vs ty = let (tvs, rho) = tcSplitForAllTysReqPreserveSynonyms ty @@ -749,78 +844,96 @@ synifyVisForAllType vs ty = -- Figure out what the type variable order would be inferred in the -- absence of an explicit forall tvs' = orderedFVs (mkVarSet vs) [rho] - - in noLocA $ HsForAllTy { hst_tele = mkHsForAllVisTele noAnn sTvs - , hst_xforall = noExtField - , hst_body = synifyType WithinType (tvs' ++ vs) rho } + in noLocA $ + HsForAllTy + { hst_tele = mkHsForAllVisTele noAnn sTvs + , hst_xforall = noExtField + , hst_body = synifyType WithinType (tvs' ++ vs) rho + } -- | Process a 'Type' which starts with an invisible @forall@ or a constraint -- into an 'HsType' synifySigmaType - :: SynifyTypeState -- ^ what to do with the 'forall' - -> [TyVar] -- ^ free variables in the type to convert - -> Type -- ^ the forall type to convert + :: SynifyTypeState + -- ^ what to do with the 'forall' + -> [TyVar] + -- ^ free variables in the type to convert + -> Type + -- ^ the forall type to convert -> LHsType GhcRn synifySigmaType s vs ty = let (tvs, ctx, tau) = tcSplitSigmaTyPreserveSynonyms ty - sPhi = HsQualTy { hst_ctxt = synifyCtx ctx - , hst_xqual = noExtField - , hst_body = synifyType WithinType (tvs' ++ vs) tau } + sPhi = + HsQualTy + { hst_ctxt = synifyCtx ctx + , hst_xqual = noExtField + , hst_body = synifyType WithinType (tvs' ++ vs) tau + } - sTy = HsForAllTy { hst_tele = mkHsForAllInvisTele noAnn sTvs - , hst_xforall = noExtField - , hst_body = noLocA sPhi } + sTy = + HsForAllTy + { hst_tele = mkHsForAllInvisTele noAnn sTvs + , hst_xforall = noExtField + , hst_body = noLocA sPhi + } sTvs = map synifyTyVarBndr tvs -- Figure out what the type variable order would be inferred in the -- absence of an explicit forall tvs' = orderedFVs (mkVarSet vs) (ctx ++ [tau]) - - in case s of - DeleteTopLevelQuantification -> synifyType ImplicitizeForAll (tvs' ++ vs) tau - - -- Put a forall in if there are any type variables - WithinType - | not (null tvs) -> noLocA sTy - | otherwise -> noLocA sPhi - - ImplicitizeForAll -> implicitForAll [] vs tvs ctx (synifyType WithinType) tau + in case s of + DeleteTopLevelQuantification -> synifyType ImplicitizeForAll (tvs' ++ vs) tau + -- Put a forall in if there are any type variables + WithinType + | not (null tvs) -> noLocA sTy + | otherwise -> noLocA sPhi + ImplicitizeForAll -> implicitForAll [] vs tvs ctx (synifyType WithinType) tau -- | Put a forall in if there are any type variables which require -- explicit kind annotations or if the inferred type variable order -- would be different. implicitForAll - :: [TyCon] -- ^ type constructors that determine their args kinds - -> [TyVar] -- ^ free variables in the type to convert - -> [InvisTVBinder] -- ^ type variable binders in the forall - -> ThetaType -- ^ constraints right after the forall - -> ([TyVar] -> Type -> LHsType GhcRn) -- ^ how to convert the inner type - -> Type -- ^ inner type + :: [TyCon] + -- ^ type constructors that determine their args kinds + -> [TyVar] + -- ^ free variables in the type to convert + -> [InvisTVBinder] + -- ^ type variable binders in the forall + -> ThetaType + -- ^ constraints right after the forall + -> ([TyVar] -> Type -> LHsType GhcRn) + -- ^ how to convert the inner type + -> Type + -- ^ inner type -> LHsType GhcRn implicitForAll tycons vs tvs ctx synInner tau | any (isHsKindedTyVar . unLoc) sTvs = noLocA sTy - | tvs' /= (binderVars tvs) = noLocA sTy - | otherwise = noLocA sPhi + | tvs' /= (binderVars tvs) = noLocA sTy + | otherwise = noLocA sPhi where - sRho = synInner (tvs' ++ vs) tau - sPhi | null ctx = unLoc sRho - | otherwise - = HsQualTy { hst_ctxt = synifyCtx ctx - , hst_xqual = noExtField - , hst_body = synInner (tvs' ++ vs) tau } - sTy = HsForAllTy { hst_tele = mkHsForAllInvisTele noAnn sTvs - , hst_xforall = noExtField - , hst_body = noLocA sPhi } - - no_kinds_needed = noKindTyVars tycons tau - sTvs = map (synifyTyVarBndr' no_kinds_needed) tvs - - -- Figure out what the type variable order would be inferred in the - -- absence of an explicit forall - tvs' = orderedFVs (mkVarSet vs) (ctx ++ [tau]) + sRho = synInner (tvs' ++ vs) tau + sPhi + | null ctx = unLoc sRho + | otherwise = + HsQualTy + { hst_ctxt = synifyCtx ctx + , hst_xqual = noExtField + , hst_body = synInner (tvs' ++ vs) tau + } + sTy = + HsForAllTy + { hst_tele = mkHsForAllInvisTele noAnn sTvs + , hst_xforall = noExtField + , hst_body = noLocA sPhi + } + no_kinds_needed = noKindTyVars tycons tau + sTvs = map (synifyTyVarBndr' no_kinds_needed) tvs + -- Figure out what the type variable order would be inferred in the + -- absence of an explicit forall + tvs' = orderedFVs (mkVarSet vs) (ctx ++ [tau]) -- | Find the set of type variables whose kind signatures can be properly -- inferred just from their uses in the type signature. This means the type @@ -830,41 +943,44 @@ implicitForAll tycons vs tvs ctx synInner tau -- as @x1 x2 ... xn@. -- -- * @f@ has a function kind whose final return has lifted type kind --- noKindTyVars - :: [TyCon] -- ^ type constructors that determine their args kinds - -> Type -- ^ type to inspect - -> VarSet -- ^ set of variables whose kinds can be inferred from uses in the type + :: [TyCon] + -- ^ type constructors that determine their args kinds + -> Type + -- ^ type to inspect + -> VarSet + -- ^ set of variables whose kinds can be inferred from uses in the type noKindTyVars _ (TyVarTy var) | isLiftedTypeKind (tyVarKind var) = unitVarSet var noKindTyVars ts ty | (f, xs) <- splitAppTys ty - , not (null xs) - = let args = map (noKindTyVars ts) xs - func = case f of - TyVarTy var | (xsKinds, outKind) <- splitFunTys (tyVarKind var) - , map scaledThing xsKinds `eqTypes` map typeKind xs - , isLiftedTypeKind outKind - -> unitVarSet var - TyConApp t ks | t `elem` ts - , all noFreeVarsOfType ks - -> mkVarSet [ v | TyVarTy v <- xs ] - _ -> noKindTyVars ts f - in unionVarSets (func : args) + , not (null xs) = + let args = map (noKindTyVars ts) xs + func = case f of + TyVarTy var + | (xsKinds, outKind) <- splitFunTys (tyVarKind var) + , map scaledThing xsKinds `eqTypes` map typeKind xs + , isLiftedTypeKind outKind -> + unitVarSet var + TyConApp t ks + | t `elem` ts + , all noFreeVarsOfType ks -> + mkVarSet [v | TyVarTy v <- xs] + _ -> noKindTyVars ts f + in unionVarSets (func : args) noKindTyVars ts (ForAllTy _ t) = noKindTyVars ts t -noKindTyVars ts (FunTy _ w t1 t2) = noKindTyVars ts w `unionVarSet` - noKindTyVars ts t1 `unionVarSet` - noKindTyVars ts t2 +noKindTyVars ts (FunTy _ w t1 t2) = + noKindTyVars ts w + `unionVarSet` noKindTyVars ts t1 + `unionVarSet` noKindTyVars ts t2 noKindTyVars ts (CastTy t _) = noKindTyVars ts t noKindTyVars _ _ = emptyVarSet synifyMult :: [TyVar] -> Mult -> HsArrow GhcRn synifyMult vs t = case t of - OneTy -> HsLinearArrow noExtField - ManyTy -> HsUnrestrictedArrow noExtField - ty -> HsExplicitMult noExtField (synifyType WithinType vs ty) - - + OneTy -> HsLinearArrow noExtField + ManyTy -> HsUnrestrictedArrow noExtField + ty -> HsExplicitMult noExtField (synifyType WithinType vs ty) synifyPatSynType :: PatSyn -> LHsType GhcRn synifyPatSynType ps = @@ -874,14 +990,18 @@ synifyPatSynType ps = -- HACK: a HsQualTy with theta = [unitTy] will be printed as "() =>", -- i.e., an explicit empty context, which is what we need. This is not -- possible by taking theta = [], as that will print no context at all - req_theta' | null req_theta - , not (null prov_theta && null ex_tvs) - = [unitTy] - | otherwise = req_theta - - in implicitForAll ts [] (univ_tvs ++ ex_tvs) req_theta' - (\vs -> implicitForAll ts vs [] prov_theta (synifyType WithinType)) - (mkScaledFunTys arg_tys res_ty) + req_theta' + | null req_theta + , not (null prov_theta && null ex_tvs) = + [unitTy] + | otherwise = req_theta + in implicitForAll + ts + [] + (univ_tvs ++ ex_tvs) + req_theta' + (\vs -> implicitForAll ts vs [] prov_theta (synifyType WithinType)) + (mkScaledFunTys arg_tys res_ty) synifyTyLit :: TyLit -> HsTyLit GhcRn synifyTyLit (NumTyLit n) = HsNumTy NoSourceText n @@ -896,60 +1016,64 @@ stripKindSig (L _ (HsKindSig _ t _)) = t stripKindSig t = t synifyInstHead :: ([TyVar], [PredType], Class, [Type]) -> [(FamInst, Bool, Maybe (MDoc Name), Located Name, Maybe Module)] -> InstHead GhcRn -synifyInstHead (vs, preds, cls, types) associated_families = InstHead +synifyInstHead (vs, preds, cls, types) associated_families = + InstHead { ihdClsName = getName cls , ihdTypes = map unLoc annot_ts - , ihdInstType = ClassInst - { clsiCtx = map (unLoc . synifyType WithinType []) preds - , clsiTyVars = synifyTyVars (tyConVisibleTyVars cls_tycon) - , clsiSigs = map synifyClsIdSig $ specialized_class_methods - , clsiAssocTys = [ (f_inst, f_doc, f_name, f_mod) - | (f_i, opaque, f_doc, f_name, f_mod) <- associated_families - , Right f_inst <- [synifyFamInst f_i opaque] - ] - } + , ihdInstType = + ClassInst + { clsiCtx = map (unLoc . synifyType WithinType []) preds + , clsiTyVars = synifyTyVars (tyConVisibleTyVars cls_tycon) + , clsiSigs = map synifyClsIdSig $ specialized_class_methods + , clsiAssocTys = + [ (f_inst, f_doc, f_name, f_mod) + | (f_i, opaque, f_doc, f_name, f_mod) <- associated_families + , Right f_inst <- [synifyFamInst f_i opaque] + ] + } } where cls_tycon = classTyCon cls - ts = filterOutInvisibleTypes cls_tycon types + ts = filterOutInvisibleTypes cls_tycon types ts' = map (synifyType WithinType vs) ts annot_ts = zipWith3 annotHsType args_poly ts ts' args_poly = tyConArgsPolyKinded cls_tycon synifyClsIdSig = synifyIdSig ShowRuntimeRep DeleteTopLevelQuantification vs - specialized_class_methods = [ setIdType m (piResultTys (idType m) types) | m <- classMethods cls ] + specialized_class_methods = [setIdType m (piResultTys (idType m) types) | m <- classMethods cls] -- Convert a family instance, this could be a type family or data family synifyFamInst :: FamInst -> Bool -> Either String (InstHead GhcRn) synifyFamInst fi opaque = do - ityp' <- ityp fam_flavor - return InstHead - { ihdClsName = fi_fam fi - , ihdTypes = map unLoc annot_ts - , ihdInstType = ityp' - } + ityp' <- ityp fam_flavor + return + InstHead + { ihdClsName = fi_fam fi + , ihdTypes = map unLoc annot_ts + , ihdInstType = ityp' + } where ityp SynFamilyInst | opaque = return $ TypeInst Nothing ityp SynFamilyInst = - return . TypeInst . Just . unLoc $ synifyType WithinType [] fam_rhs + return . TypeInst . Just . unLoc $ synifyType WithinType [] fam_rhs ityp (DataFamilyInst c) = - DataInst <$> synifyTyCon HideRuntimeRep (Just $ famInstAxiom fi) c - fam_tc = famInstTyCon fi + DataInst <$> synifyTyCon HideRuntimeRep (Just $ famInstAxiom fi) c + fam_tc = famInstTyCon fi fam_flavor = fi_flavor fi - fam_lhs = fi_tys fi - fam_rhs = fi_rhs fi + fam_lhs = fi_tys fi + fam_rhs = fi_rhs fi eta_expanded_lhs -- eta-expand lhs types, because sometimes data/newtype -- instances are eta-reduced; See Trac #9692 -- See Note [Eta reduction for data family axioms] in GHC.Tc.TyCl.Instance in GHC - | DataFamilyInst rep_tc <- fam_flavor - = let (_, rep_tc_args) = splitTyConApp fam_rhs - etad_tyvars = dropList rep_tc_args $ tyConTyVars rep_tc - etad_tys = mkTyVarTys etad_tyvars - eta_exp_lhs = fam_lhs `chkAppend` etad_tys - in eta_exp_lhs - | otherwise - = fam_lhs + | DataFamilyInst rep_tc <- fam_flavor = + let (_, rep_tc_args) = splitTyConApp fam_rhs + etad_tyvars = dropList rep_tc_args $ tyConTyVars rep_tc + etad_tys = mkTyVarTys etad_tyvars + eta_exp_lhs = fam_lhs `chkAppend` etad_tys + in eta_exp_lhs + | otherwise = + fam_lhs ts = filterOutInvisibleTypes fam_tc eta_expanded_lhs synifyTypes = map (synifyType WithinType []) @@ -977,44 +1101,46 @@ invariant didn't hold. -- See Note [Invariant: Never expand type synonyms] tcSplitSigmaTyPreserveSynonyms :: Type -> ([InvisTVBinder], ThetaType, Type) tcSplitSigmaTyPreserveSynonyms ty = - case tcSplitForAllTysInvisPreserveSynonyms ty of - (tvs, rho) -> case tcSplitPhiTyPreserveSynonyms rho of - (theta, tau) -> (tvs, theta, tau) + case tcSplitForAllTysInvisPreserveSynonyms ty of + (tvs, rho) -> case tcSplitPhiTyPreserveSynonyms rho of + (theta, tau) -> (tvs, theta, tau) -- | See Note [Invariant: Never expand type synonyms] -tcSplitSomeForAllTysPreserveSynonyms :: - (ForAllTyFlag -> Bool) -> Type -> ([ForAllTyBinder], Type) +tcSplitSomeForAllTysPreserveSynonyms + :: (ForAllTyFlag -> Bool) -> Type -> ([ForAllTyBinder], Type) tcSplitSomeForAllTysPreserveSynonyms argf_pred ty = split ty ty [] where split _ (ForAllTy tvb@(Bndr _ argf) ty') tvs - | argf_pred argf = split ty' ty' (tvb:tvs) + | argf_pred argf = split ty' ty' (tvb : tvs) split orig_ty _ tvs = (reverse tvs, orig_ty) -- | See Note [Invariant: Never expand type synonyms] tcSplitForAllTysReqPreserveSynonyms :: Type -> ([ReqTVBinder], Type) tcSplitForAllTysReqPreserveSynonyms ty = let (all_bndrs, body) = tcSplitSomeForAllTysPreserveSynonyms isVisibleForAllTyFlag ty - req_bndrs = mapMaybe mk_req_bndr_maybe all_bndrs in - assert ( req_bndrs `equalLength` all_bndrs) - (req_bndrs, body) + req_bndrs = mapMaybe mk_req_bndr_maybe all_bndrs + in assert + (req_bndrs `equalLength` all_bndrs) + (req_bndrs, body) where mk_req_bndr_maybe :: ForAllTyBinder -> Maybe ReqTVBinder mk_req_bndr_maybe (Bndr tv argf) = case argf of - Required -> Just $ Bndr tv () + Required -> Just $ Bndr tv () Invisible _ -> Nothing -- | See Note [Invariant: Never expand type synonyms] tcSplitForAllTysInvisPreserveSynonyms :: Type -> ([InvisTVBinder], Type) tcSplitForAllTysInvisPreserveSynonyms ty = let (all_bndrs, body) = tcSplitSomeForAllTysPreserveSynonyms isInvisibleForAllTyFlag ty - inv_bndrs = mapMaybe mk_inv_bndr_maybe all_bndrs in - assert ( inv_bndrs `equalLength` all_bndrs) - (inv_bndrs, body) + inv_bndrs = mapMaybe mk_inv_bndr_maybe all_bndrs + in assert + (inv_bndrs `equalLength` all_bndrs) + (inv_bndrs, body) where mk_inv_bndr_maybe :: ForAllTyBinder -> Maybe InvisTVBinder mk_inv_bndr_maybe (Bndr tv argf) = case argf of Invisible s -> Just $ Bndr tv s - Required -> Nothing + Required -> Nothing -- | See Note [Invariant: Never expand type synonyms] @@ -1022,10 +1148,10 @@ tcSplitForAllTysInvisPreserveSynonyms ty = tcSplitPhiTyPreserveSynonyms :: Type -> (ThetaType, Type) tcSplitPhiTyPreserveSynonyms ty0 = split ty0 [] where - split ty ts - = case tcSplitPredFunTyPreserveSynonyms_maybe ty of - Just (pred_, ty') -> split ty' (pred_:ts) - Nothing -> (reverse ts, ty) + split ty ts = + case tcSplitPredFunTyPreserveSynonyms_maybe ty of + Just (pred_, ty') -> split ty' (pred_ : ts) + Nothing -> (reverse ts, ty) -- | See Note [Invariant: Never expand type synonyms] tcSplitPredFunTyPreserveSynonyms_maybe :: Type -> Maybe (PredType, Type) diff --git a/haddock-api/src/Haddock/Doc.hs b/haddock-api/src/Haddock/Doc.hs index 9c21015a60..e6e4c404aa 100644 --- a/haddock-api/src/Haddock/Doc.hs +++ b/haddock-api/src/Haddock/Doc.hs @@ -1,8 +1,10 @@ {-# OPTIONS_GHC -fno-warn-orphans #-} -module Haddock.Doc ( module Documentation.Haddock.Doc - , docCodeBlock - , combineDocumentation - ) where + +module Haddock.Doc + ( module Documentation.Haddock.Doc + , docCodeBlock + , combineDocumentation + ) where import Data.Maybe import Documentation.Haddock.Doc @@ -11,10 +13,11 @@ import Haddock.Utils (mkMeta) combineDocumentation :: Documentation name -> Maybe (MDoc name) combineDocumentation (Documentation Nothing Nothing) = Nothing -combineDocumentation (Documentation mDoc mWarning) = - Just (maybe emptyMetaDoc mkMeta mWarning - `metaDocAppend` - fromMaybe emptyMetaDoc mDoc) +combineDocumentation (Documentation mDoc mWarning) = + Just + ( maybe emptyMetaDoc mkMeta mWarning + `metaDocAppend` fromMaybe emptyMetaDoc mDoc + ) -- Drop trailing whitespace from @..@ code blocks. Otherwise this: -- @@ -27,8 +30,8 @@ combineDocumentation (Documentation mDoc mWarning) = -- on the final line seems to trigger the extra vertical space. -- docCodeBlock :: DocH mod id -> DocH mod id -docCodeBlock (DocString s) - = DocString (reverse $ dropWhile (`elem` " \t") $ reverse s) -docCodeBlock (DocAppend l r) - = DocAppend l (docCodeBlock r) +docCodeBlock (DocString s) = + DocString (reverse $ dropWhile (`elem` " \t") $ reverse s) +docCodeBlock (DocAppend l r) = + DocAppend l (docCodeBlock r) docCodeBlock d = d diff --git a/haddock-api/src/Haddock/GhcUtils.hs b/haddock-api/src/Haddock/GhcUtils.hs index a16b18ceef..f5713870b9 100644 --- a/haddock-api/src/Haddock/GhcUtils.hs +++ b/haddock-api/src/Haddock/GhcUtils.hs @@ -1,17 +1,22 @@ -{-# LANGUAGE BangPatterns, FlexibleInstances #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeOperators #-} -{-# LANGUAGE RankNTypes #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE BangPatterns #-} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MonadComprehensions #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} {-# OPTIONS_GHC -Wno-incomplete-record-updates #-} {-# OPTIONS_GHC -Wno-redundant-constraints #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} {-# OPTIONS_HADDOCK hide #-} + +----------------------------------------------------------------------------- + ----------------------------------------------------------------------------- + -- | -- Module : Haddock.GhcUtils -- Copyright : (c) David Waern 2006-2009 @@ -22,42 +27,46 @@ -- Portability : portable -- -- Utils for dealing with types from the GHC API ------------------------------------------------------------------------------ module Haddock.GhcUtils where - import Control.Arrow -import Data.Char ( isSpace ) -import Data.Foldable ( toList, foldl' ) -import Data.List.NonEmpty ( NonEmpty ) -import Data.Maybe ( mapMaybe, fromMaybe ) +import Data.Char (isSpace) +import Data.Foldable (foldl', toList) +import Data.List.NonEmpty (NonEmpty) +import Data.Maybe (fromMaybe, mapMaybe) import qualified Data.Set as Set -import Haddock.Types( DocName, DocNameI, XRecCond ) +import Haddock.Types (DocName, DocNameI, XRecCond) import GHC import GHC.Builtin.Names +import GHC.Builtin.Types (liftedRepTy) +import GHC.Core.TyCo.Rep (Type (..)) +import GHC.Core.Type (binderVar, isRuntimeRepVar) import GHC.Data.FastString -import GHC.Driver.Ppr (showPpr ) +import GHC.Driver.Ppr (showPpr) import GHC.Driver.Session import GHC.Types.Name +import GHC.Types.SrcLoc (advanceSrcLoc) +import GHC.Types.Var + ( Specificity + , TyVarBinder + , VarBndr (..) + , isInvisibleForAllTyFlag + , tyVarKind + , updateTyVarKind + ) +import GHC.Types.Var.Env (TyVarEnv, elemVarEnv, emptyVarEnv, extendVarEnv) +import GHC.Types.Var.Set (VarSet, emptyVarSet) import GHC.Utils.FV as FV -import GHC.Utils.Outputable ( Outputable ) -import GHC.Utils.Panic ( panic ) -import GHC.Types.SrcLoc ( advanceSrcLoc ) -import GHC.Types.Var ( Specificity, VarBndr(..), TyVarBinder - , tyVarKind, updateTyVarKind, isInvisibleForAllTyFlag ) -import GHC.Types.Var.Set ( VarSet, emptyVarSet ) -import GHC.Types.Var.Env ( TyVarEnv, extendVarEnv, elemVarEnv, emptyVarEnv ) -import GHC.Core.TyCo.Rep ( Type(..) ) -import GHC.Core.Type ( isRuntimeRepVar, binderVar ) -import GHC.Builtin.Types( liftedRepTy ) - -import GHC.Data.StringBuffer ( StringBuffer ) -import qualified GHC.Data.StringBuffer as S - -import Data.ByteString ( ByteString ) -import qualified Data.ByteString as BS +import GHC.Utils.Outputable (Outputable) +import GHC.Utils.Panic (panic) + +import GHC.Data.StringBuffer (StringBuffer) +import qualified GHC.Data.StringBuffer as S + +import Data.ByteString (ByteString) +import qualified Data.ByteString as BS import qualified Data.ByteString.Internal as BS import GHC.HsToCore.Docs hiding (sigNameNoLoc) @@ -76,42 +85,42 @@ filterLSigNames :: (IdP (GhcPass p) -> Bool) -> LSig (GhcPass p) -> Maybe (LSig filterLSigNames p (L loc sig) = L loc <$> (filterSigNames p sig) filterSigNames :: (IdP (GhcPass p) -> Bool) -> Sig (GhcPass p) -> Maybe (Sig (GhcPass p)) -filterSigNames p orig@(SpecSig _ n _ _) = ifTrueJust (p $ unLoc n) orig -filterSigNames p orig@(InlineSig _ n _) = ifTrueJust (p $ unLoc n) orig +filterSigNames p orig@(SpecSig _ n _ _) = ifTrueJust (p $ unLoc n) orig +filterSigNames p orig@(InlineSig _ n _) = ifTrueJust (p $ unLoc n) orig filterSigNames p (FixSig _ (FixitySig ns_spec ns ty)) = case filter (p . unLoc) ns of - [] -> Nothing + [] -> Nothing filtered -> Just (FixSig noAnn (FixitySig ns_spec filtered ty)) -filterSigNames _ orig@(MinimalSig _ _) = Just orig +filterSigNames _ orig@(MinimalSig _ _) = Just orig filterSigNames p (TypeSig _ ns ty) = case filter (p . unLoc) ns of - [] -> Nothing + [] -> Nothing filtered -> Just (TypeSig noAnn filtered ty) filterSigNames p (ClassOpSig _ is_default ns ty) = case filter (p . unLoc) ns of - [] -> Nothing + [] -> Nothing filtered -> Just (ClassOpSig noAnn is_default filtered ty) filterSigNames p (PatSynSig _ ns ty) = case filter (p . unLoc) ns of - [] -> Nothing + [] -> Nothing filtered -> Just (PatSynSig noAnn filtered ty) -filterSigNames _ _ = Nothing +filterSigNames _ _ = Nothing ifTrueJust :: Bool -> name -> Maybe name -ifTrueJust True = Just +ifTrueJust True = Just ifTrueJust False = const Nothing sigName :: LSig GhcRn -> [IdP GhcRn] sigName (L _ sig) = sigNameNoLoc' emptyOccEnv sig sigNameNoLoc' :: forall pass w. UnXRec pass => w -> Sig pass -> [IdP pass] -sigNameNoLoc' _ (TypeSig _ ns _) = map (unXRec @pass) ns -sigNameNoLoc' _ (ClassOpSig _ _ ns _) = map (unXRec @pass) ns -sigNameNoLoc' _ (PatSynSig _ ns _) = map (unXRec @pass) ns -sigNameNoLoc' _ (SpecSig _ n _ _) = [unXRec @pass n] -sigNameNoLoc' _ (InlineSig _ n _) = [unXRec @pass n] +sigNameNoLoc' _ (TypeSig _ ns _) = map (unXRec @pass) ns +sigNameNoLoc' _ (ClassOpSig _ _ ns _) = map (unXRec @pass) ns +sigNameNoLoc' _ (PatSynSig _ ns _) = map (unXRec @pass) ns +sigNameNoLoc' _ (SpecSig _ n _ _) = [unXRec @pass n] +sigNameNoLoc' _ (InlineSig _ n _) = [unXRec @pass n] sigNameNoLoc' _ (FixSig _ (FixitySig _ ns _)) = map (unXRec @pass) ns -sigNameNoLoc' _ _ = [] +sigNameNoLoc' _ _ = [] -- | Was this signature given by the user? isUserLSig :: forall p. UnXRec p => LSig p -> Bool @@ -136,21 +145,24 @@ dataTupleModule = mkBaseModule (fsLit "Data.Tuple") -- instantiated at DocNameI instead of (GhcPass _). -- | Like 'hsTyVarName' from GHC API, but not instantiated at (GhcPass _) -hsTyVarBndrName :: forall flag n. (XXTyVarBndr n ~ DataConCantHappen, UnXRec n) - => HsTyVarBndr flag n -> IdP n +hsTyVarBndrName + :: forall flag n + . (XXTyVarBndr n ~ DataConCantHappen, UnXRec n) + => HsTyVarBndr flag n + -> IdP n hsTyVarBndrName (UserTyVar _ _ name) = unXRec @n name hsTyVarBndrName (KindedTyVar _ _ name _) = unXRec @n name hsTyVarNameI :: HsTyVarBndr flag DocNameI -> DocName -hsTyVarNameI (UserTyVar _ _ (L _ n)) = n +hsTyVarNameI (UserTyVar _ _ (L _ n)) = n hsTyVarNameI (KindedTyVar _ _ (L _ n) _) = n hsLTyVarNameI :: LHsTyVarBndr flag DocNameI -> DocName hsLTyVarNameI = hsTyVarNameI . unLoc getConNamesI :: ConDecl DocNameI -> NonEmpty (LocatedN DocName) -getConNamesI ConDeclH98 {con_name = name} = pure name -getConNamesI ConDeclGADT {con_names = names} = names +getConNamesI ConDeclH98{con_name = name} = pure name +getConNamesI ConDeclGADT{con_names = names} = names hsSigTypeI :: LHsSigType DocNameI -> LHsType DocNameI hsSigTypeI = sig_body . unLoc @@ -159,191 +171,245 @@ mkEmptySigType :: LHsType GhcRn -> LHsSigType GhcRn -- Dubious, because the implicit binders are empty even -- though the type might have free variables mkEmptySigType lty@(L loc ty) = L loc $ case ty of - HsForAllTy { hst_tele = HsForAllInvis { hsf_invis_bndrs = bndrs } - , hst_body = body } - -> HsSig { sig_ext = noExtField - , sig_bndrs = HsOuterExplicit { hso_xexplicit = noExtField - , hso_bndrs = bndrs } - , sig_body = body } - _ -> HsSig { sig_ext = noExtField - , sig_bndrs = HsOuterImplicit{hso_ximplicit = []} - , sig_body = lty } - -mkHsForAllInvisTeleI :: - [LHsTyVarBndr Specificity DocNameI] -> HsForAllTelescope DocNameI + HsForAllTy + { hst_tele = HsForAllInvis{hsf_invis_bndrs = bndrs} + , hst_body = body + } -> + HsSig + { sig_ext = noExtField + , sig_bndrs = + HsOuterExplicit + { hso_xexplicit = noExtField + , hso_bndrs = bndrs + } + , sig_body = body + } + _ -> + HsSig + { sig_ext = noExtField + , sig_bndrs = HsOuterImplicit{hso_ximplicit = []} + , sig_body = lty + } + +mkHsForAllInvisTeleI + :: [LHsTyVarBndr Specificity DocNameI] -> HsForAllTelescope DocNameI mkHsForAllInvisTeleI invis_bndrs = - HsForAllInvis { hsf_xinvis = noExtField, hsf_invis_bndrs = invis_bndrs } + HsForAllInvis{hsf_xinvis = noExtField, hsf_invis_bndrs = invis_bndrs} mkHsImplicitSigTypeI :: LHsType DocNameI -> HsSigType DocNameI mkHsImplicitSigTypeI body = - HsSig { sig_ext = noExtField - , sig_bndrs = HsOuterImplicit{hso_ximplicit = noExtField} - , sig_body = body } + HsSig + { sig_ext = noExtField + , sig_bndrs = HsOuterImplicit{hso_ximplicit = noExtField} + , sig_body = body + } getGADTConType :: ConDecl DocNameI -> LHsSigType DocNameI -- The full type of a GADT data constructor We really only get this in -- order to pretty-print it, and currently only in Haddock's code. So -- we are cavalier about locations and extensions, hence the -- 'undefined's -getGADTConType (ConDeclGADT { con_bndrs = L _ outer_bndrs - , con_mb_cxt = mcxt, con_g_args = args - , con_res_ty = res_ty }) - = noLocA (HsSig { sig_ext = noExtField - , sig_bndrs = outer_bndrs - , sig_body = theta_ty }) - where - theta_ty | Just theta <- mcxt - = noLocA (HsQualTy { hst_xqual = noAnn, hst_ctxt = theta, hst_body = tau_ty }) - | otherwise - = tau_ty - --- tau_ty :: LHsType DocNameI - tau_ty = case args of - RecConGADT _ flds -> mkFunTy (noLocA (HsRecTy noAnn (unLoc flds))) res_ty - PrefixConGADT _ pos_args -> foldr mkFunTy res_ty (map hsScaledThing pos_args) - - mkFunTy :: LHsType DocNameI -> LHsType DocNameI -> LHsType DocNameI - mkFunTy a b = noLocA (HsFunTy noAnn (HsUnrestrictedArrow noExtField) a b) - -getGADTConType (ConDeclH98 {}) = panic "getGADTConType" - -- Should only be called on ConDeclGADT +getGADTConType + ( ConDeclGADT + { con_bndrs = L _ outer_bndrs + , con_mb_cxt = mcxt + , con_g_args = args + , con_res_ty = res_ty + } + ) = + noLocA + ( HsSig + { sig_ext = noExtField + , sig_bndrs = outer_bndrs + , sig_body = theta_ty + } + ) + where + theta_ty + | Just theta <- mcxt = + noLocA (HsQualTy{hst_xqual = noAnn, hst_ctxt = theta, hst_body = tau_ty}) + | otherwise = + tau_ty + + -- tau_ty :: LHsType DocNameI + tau_ty = case args of + RecConGADT _ flds -> mkFunTy (noLocA (HsRecTy noAnn (unLoc flds))) res_ty + PrefixConGADT _ pos_args -> foldr mkFunTy res_ty (map hsScaledThing pos_args) + + mkFunTy :: LHsType DocNameI -> LHsType DocNameI -> LHsType DocNameI + mkFunTy a b = noLocA (HsFunTy noAnn (HsUnrestrictedArrow noExtField) a b) +getGADTConType (ConDeclH98{}) = panic "getGADTConType" + +-- Should only be called on ConDeclGADT getMainDeclBinderI :: HsDecl DocNameI -> [IdP DocNameI] getMainDeclBinderI (TyClD _ d) = [tcdNameI d] getMainDeclBinderI (ValD _ d) = case collectHsBindBinders CollNoDictBinders d of - [] -> [] - (name:_) -> [name] + [] -> [] + (name : _) -> [name] getMainDeclBinderI (SigD _ d) = sigNameNoLoc' emptyOccEnv d getMainDeclBinderI (ForD _ (ForeignImport _ name _ _)) = [unLoc name] getMainDeclBinderI (ForD _ (ForeignExport _ _ _ _)) = [] getMainDeclBinderI _ = [] familyDeclLNameI :: FamilyDecl DocNameI -> LocatedN DocName -familyDeclLNameI (FamilyDecl { fdLName = n }) = n +familyDeclLNameI (FamilyDecl{fdLName = n}) = n tyClDeclLNameI :: TyClDecl DocNameI -> LocatedN DocName -tyClDeclLNameI (FamDecl { tcdFam = fd }) = familyDeclLNameI fd -tyClDeclLNameI (SynDecl { tcdLName = ln }) = ln -tyClDeclLNameI (DataDecl { tcdLName = ln }) = ln -tyClDeclLNameI (ClassDecl { tcdLName = ln }) = ln +tyClDeclLNameI (FamDecl{tcdFam = fd}) = familyDeclLNameI fd +tyClDeclLNameI (SynDecl{tcdLName = ln}) = ln +tyClDeclLNameI (DataDecl{tcdLName = ln}) = ln +tyClDeclLNameI (ClassDecl{tcdLName = ln}) = ln tcdNameI :: TyClDecl DocNameI -> DocName tcdNameI = unLoc . tyClDeclLNameI addClassContext :: Name -> LHsQTyVars GhcRn -> LSig GhcRn -> LSig GhcRn -- Add the class context to a class-op signature -addClassContext cls tvs0 (L pos (ClassOpSig _ _ lname ltype)) - = L pos (TypeSig noAnn lname (mkEmptyWildCardBndrs (go_sig_ty ltype))) +addClassContext cls tvs0 (L pos (ClassOpSig _ _ lname ltype)) = + L pos (TypeSig noAnn lname (mkEmptyWildCardBndrs (go_sig_ty ltype))) where - go_sig_ty (L loc (HsSig { sig_bndrs = bndrs, sig_body = ty })) - = L loc (HsSig { sig_ext = noExtField - , sig_bndrs = bndrs, sig_body = go_ty ty }) - - go_ty (L loc (HsForAllTy { hst_tele = tele, hst_body = ty })) - = L loc (HsForAllTy { hst_xforall = noExtField - , hst_tele = tele, hst_body = go_ty ty }) - go_ty (L loc (HsQualTy { hst_ctxt = ctxt, hst_body = ty })) - = L loc (HsQualTy { hst_xqual = noExtField - , hst_ctxt = add_ctxt ctxt, hst_body = ty }) - go_ty (L loc ty) - = L loc (HsQualTy { hst_xqual = noExtField - , hst_ctxt = add_ctxt (noLocA []), hst_body = L loc ty }) + go_sig_ty (L loc (HsSig{sig_bndrs = bndrs, sig_body = ty})) = + L + loc + ( HsSig + { sig_ext = noExtField + , sig_bndrs = bndrs + , sig_body = go_ty ty + } + ) + + go_ty (L loc (HsForAllTy{hst_tele = tele, hst_body = ty})) = + L + loc + ( HsForAllTy + { hst_xforall = noExtField + , hst_tele = tele + , hst_body = go_ty ty + } + ) + go_ty (L loc (HsQualTy{hst_ctxt = ctxt, hst_body = ty})) = + L + loc + ( HsQualTy + { hst_xqual = noExtField + , hst_ctxt = add_ctxt ctxt + , hst_body = ty + } + ) + go_ty (L loc ty) = + L + loc + ( HsQualTy + { hst_xqual = noExtField + , hst_ctxt = add_ctxt (noLocA []) + , hst_body = L loc ty + } + ) extra_pred = nlHsTyConApp NotPromoted Prefix cls (lHsQTyVarsToTypes tvs0) add_ctxt (L loc preds) = L loc (extra_pred : preds) - -addClassContext _ _ sig = sig -- E.g. a MinimalSig is fine +addClassContext _ _ sig = sig -- E.g. a MinimalSig is fine lHsQTyVarsToTypes :: LHsQTyVars GhcRn -> [LHsTypeArg GhcRn] -lHsQTyVarsToTypes tvs - = [ HsValArg noExtField $ noLocA (HsTyVar noAnn NotPromoted (noLocA (hsLTyVarName tv))) - | tv <- hsQTvExplicit tvs ] - +lHsQTyVarsToTypes tvs = + [ HsValArg noExtField $ noLocA (HsTyVar noAnn NotPromoted (noLocA (hsLTyVarName tv))) + | tv <- hsQTvExplicit tvs + ] -------------------------------------------------------------------------------- + -- * Making abstract declarations + -------------------------------------------------------------------------------- restrictTo :: [Name] -> LHsDecl GhcRn -> LHsDecl GhcRn restrictTo names (L loc decl) = L loc $ case decl of - TyClD x d | isDataDecl d -> - TyClD x (d { tcdDataDefn = restrictDataDefn names (tcdDataDefn d) }) - TyClD x d | isClassDecl d -> - TyClD x (d { tcdSigs = restrictDecls names (tcdSigs d), - tcdATs = restrictATs names (tcdATs d) }) + TyClD x d + | isDataDecl d -> + TyClD x (d{tcdDataDefn = restrictDataDefn names (tcdDataDefn d)}) + TyClD x d + | isClassDecl d -> + TyClD + x + ( d + { tcdSigs = restrictDecls names (tcdSigs d) + , tcdATs = restrictATs names (tcdATs d) + } + ) _ -> decl restrictDataDefn :: [Name] -> HsDataDefn GhcRn -> HsDataDefn GhcRn -restrictDataDefn names d = d { dd_cons = restrictDataDefnCons names (dd_cons d) } +restrictDataDefn names d = d{dd_cons = restrictDataDefnCons names (dd_cons d)} restrictDataDefnCons :: [Name] -> DataDefnCons (LConDecl GhcRn) -> DataDefnCons (LConDecl GhcRn) -restrictDataDefnCons names = \ case - DataTypeCons is_type_data cons -> DataTypeCons is_type_data (restrictCons names cons) - NewTypeCon con -> maybe (DataTypeCons False []) NewTypeCon $ restrictCons names (Just con) +restrictDataDefnCons names = \case + DataTypeCons is_type_data cons -> DataTypeCons is_type_data (restrictCons names cons) + NewTypeCon con -> maybe (DataTypeCons False []) NewTypeCon $ restrictCons names (Just con) restrictCons :: MonadFail m => [Name] -> m (LConDecl GhcRn) -> m (LConDecl GhcRn) -restrictCons names decls = [ L p d | L p (Just d) <- fmap keep <$> decls ] +restrictCons names decls = [L p d | L p (Just d) <- fmap keep <$> decls] where keep :: ConDecl GhcRn -> Maybe (ConDecl GhcRn) keep d | any (`elem` names) (unLoc <$> getConNames d) = - case d of - ConDeclH98 { con_args = con_args' } -> case con_args' of - PrefixCon {} -> Just d - RecCon fields - | all field_avail (unLoc fields) -> Just d - | otherwise -> Just (d { con_args = PrefixCon [] (field_types $ unLoc fields) }) + case d of + ConDeclH98{con_args = con_args'} -> case con_args' of + PrefixCon{} -> Just d + RecCon fields + | all field_avail (unLoc fields) -> Just d + | otherwise -> Just (d{con_args = PrefixCon [] (field_types $ unLoc fields)}) -- if we have *all* the field names available, then -- keep the record declaration. Otherwise degrade to -- a constructor declaration. This isn't quite right, but -- it's the best we can do. - InfixCon _ _ -> Just d - - ConDeclGADT { con_g_args = con_args' } -> case con_args' of - PrefixConGADT {} -> Just d - RecConGADT _ fields - | all field_avail (unLoc fields) -> Just d - | otherwise -> Just (d { con_g_args = PrefixConGADT noExtField (field_types $ unLoc fields) }) - -- see above + InfixCon _ _ -> Just d + ConDeclGADT{con_g_args = con_args'} -> case con_args' of + PrefixConGADT{} -> Just d + RecConGADT _ fields + | all field_avail (unLoc fields) -> Just d + | otherwise -> Just (d{con_g_args = PrefixConGADT noExtField (field_types $ unLoc fields)}) where - field_avail :: LConDeclField GhcRn -> Bool - field_avail (L _ (ConDeclField _ fs _ _)) - = all (\f -> foExt (unLoc f) `elem` names) fs + -- see above - field_types flds = [ hsUnrestricted t | L _ (ConDeclField _ _ t _) <- flds ] + field_avail :: LConDeclField GhcRn -> Bool + field_avail (L _ (ConDeclField _ fs _ _)) = + all (\f -> foExt (unLoc f) `elem` names) fs + field_types flds = [hsUnrestricted t | L _ (ConDeclField _ _ t _) <- flds] keep _ = Nothing restrictDecls :: [Name] -> [LSig GhcRn] -> [LSig GhcRn] restrictDecls names = mapMaybe (filterLSigNames (`elem` names)) - restrictATs :: [Name] -> [LFamilyDecl GhcRn] -> [LFamilyDecl GhcRn] -restrictATs names ats = [ at | at <- ats , unLoc (fdLName (unLoc at)) `elem` names ] - +restrictATs names ats = [at | at <- ats, unLoc (fdLName (unLoc at)) `elem` names] ------------------------------------------------------------------------------- + -- * Parenthesization + ------------------------------------------------------------------------------- -- | Precedence level (inside the 'HsType' AST). data Precedence - = PREC_TOP -- ^ precedence of 'type' production in GHC's parser - - | PREC_SIG -- ^ explicit type signature - - | PREC_CTX -- ^ Used for single contexts, eg. ctx => type - -- (as opposed to (ctx1, ctx2) => type) - - | PREC_FUN -- ^ precedence of 'btype' production in GHC's parser - -- (used for LH arg of (->)) - - | PREC_OP -- ^ arg of any infix operator - -- (we don't keep have fixity info) - - | PREC_CON -- ^ arg of type application: always parenthesize unless atomic + = -- | precedence of 'type' production in GHC's parser + PREC_TOP + | -- | explicit type signature + PREC_SIG + | -- | Used for single contexts, eg. ctx => type + -- (as opposed to (ctx1, ctx2) => type) + PREC_CTX + | -- | precedence of 'btype' production in GHC's parser + -- (used for LH arg of (->)) + PREC_FUN + | -- | arg of any infix operator + -- (we don't keep have fixity info) + PREC_OP + | -- | arg of type application: always parenthesize unless atomic + PREC_CON deriving (Eq, Ord) -- | Add in extra 'HsParTy' where needed to ensure that what would be printed @@ -351,86 +417,100 @@ data Precedence -- -- We cannot add parens that may be required by fixities because we do not have -- any fixity information to work with in the first place :(. -reparenTypePrec :: forall a. (XRecCond a) - => Precedence -> HsType a -> HsType a +reparenTypePrec + :: forall a + . XRecCond a + => Precedence + -> HsType a + -> HsType a reparenTypePrec = go where - - -- Shorter name for 'reparenType' - go :: Precedence -> HsType a -> HsType a - go _ (HsBangTy x b ty) = HsBangTy x b (reparenLType ty) - go _ (HsTupleTy x con tys) = HsTupleTy x con (map reparenLType tys) - go _ (HsSumTy x tys) = HsSumTy x (map reparenLType tys) - go _ (HsListTy x ty) = HsListTy x (reparenLType ty) - go _ (HsRecTy x flds) = HsRecTy x (map (mapXRec @a reparenConDeclField) flds) - go p (HsDocTy x ty d) = HsDocTy x (goL p ty) d - go _ (HsExplicitListTy x p tys) = HsExplicitListTy x p (map reparenLType tys) - go _ (HsExplicitTupleTy x tys) = HsExplicitTupleTy x (map reparenLType tys) - go p (HsKindSig x ty kind) - = paren p PREC_SIG $ HsKindSig x (goL PREC_SIG ty) (goL PREC_SIG kind) - go p (HsIParamTy x n ty) - = paren p PREC_SIG $ HsIParamTy x n (reparenLType ty) - go p (HsForAllTy x tele ty) - = paren p PREC_CTX $ HsForAllTy x (reparenHsForAllTelescope tele) (reparenLType ty) - go p (HsQualTy x ctxt ty) - = let p' [_] = PREC_CTX - p' _ = PREC_TOP -- parens will get added anyways later... + -- Shorter name for 'reparenType' + go :: Precedence -> HsType a -> HsType a + go _ (HsBangTy x b ty) = HsBangTy x b (reparenLType ty) + go _ (HsTupleTy x con tys) = HsTupleTy x con (map reparenLType tys) + go _ (HsSumTy x tys) = HsSumTy x (map reparenLType tys) + go _ (HsListTy x ty) = HsListTy x (reparenLType ty) + go _ (HsRecTy x flds) = HsRecTy x (map (mapXRec @a reparenConDeclField) flds) + go p (HsDocTy x ty d) = HsDocTy x (goL p ty) d + go _ (HsExplicitListTy x p tys) = HsExplicitListTy x p (map reparenLType tys) + go _ (HsExplicitTupleTy x tys) = HsExplicitTupleTy x (map reparenLType tys) + go p (HsKindSig x ty kind) = + paren p PREC_SIG $ HsKindSig x (goL PREC_SIG ty) (goL PREC_SIG kind) + go p (HsIParamTy x n ty) = + paren p PREC_SIG $ HsIParamTy x n (reparenLType ty) + go p (HsForAllTy x tele ty) = + paren p PREC_CTX $ HsForAllTy x (reparenHsForAllTelescope tele) (reparenLType ty) + go p (HsQualTy x ctxt ty) = + let p' [_] = PREC_CTX + p' _ = PREC_TOP -- parens will get added anyways later... ctxt' = mapXRec @a (\xs -> map (goL (p' xs)) xs) ctxt - in paren p PREC_CTX $ HsQualTy x ctxt' (goL PREC_TOP ty) - go p (HsFunTy x w ty1 ty2) - = paren p PREC_FUN $ HsFunTy x w (goL PREC_FUN ty1) (goL PREC_TOP ty2) - go p (HsAppTy x fun_ty arg_ty) - = paren p PREC_CON $ HsAppTy x (goL PREC_FUN fun_ty) (goL PREC_CON arg_ty) - go p (HsAppKindTy x fun_ty arg_ki) - = paren p PREC_CON $ HsAppKindTy x (goL PREC_FUN fun_ty) (goL PREC_CON arg_ki) - go p (HsOpTy x prom ty1 op ty2) - = paren p PREC_FUN $ HsOpTy x prom (goL PREC_OP ty1) op (goL PREC_OP ty2) - go p (HsParTy _ t) = unXRec @a $ goL p t -- pretend the paren doesn't exist - it will be added back if needed - go _ t@HsTyVar{} = t - go _ t@HsStarTy{} = t - go _ t@HsSpliceTy{} = t - go _ t@HsTyLit{} = t - go _ t@HsWildCardTy{} = t - go _ t@XHsType{} = t - - -- Located variant of 'go' - goL :: Precedence -> LHsType a -> LHsType a - goL ctxt_prec = mapXRec @a (go ctxt_prec) - - -- Optionally wrap a type in parens - paren :: Precedence -- Precedence of context - -> Precedence -- Precedence of top-level operator - -> HsType a -> HsType a -- Wrap in parens if (ctxt >= op) - paren ctxt_prec op_prec | ctxt_prec >= op_prec = HsParTy noAnn . wrapXRec @a - | otherwise = id - + in paren p PREC_CTX $ HsQualTy x ctxt' (goL PREC_TOP ty) + go p (HsFunTy x w ty1 ty2) = + paren p PREC_FUN $ HsFunTy x w (goL PREC_FUN ty1) (goL PREC_TOP ty2) + go p (HsAppTy x fun_ty arg_ty) = + paren p PREC_CON $ HsAppTy x (goL PREC_FUN fun_ty) (goL PREC_CON arg_ty) + go p (HsAppKindTy x fun_ty arg_ki) = + paren p PREC_CON $ HsAppKindTy x (goL PREC_FUN fun_ty) (goL PREC_CON arg_ki) + go p (HsOpTy x prom ty1 op ty2) = + paren p PREC_FUN $ HsOpTy x prom (goL PREC_OP ty1) op (goL PREC_OP ty2) + go p (HsParTy _ t) = unXRec @a $ goL p t -- pretend the paren doesn't exist - it will be added back if needed + go _ t@HsTyVar{} = t + go _ t@HsStarTy{} = t + go _ t@HsSpliceTy{} = t + go _ t@HsTyLit{} = t + go _ t@HsWildCardTy{} = t + go _ t@XHsType{} = t + + -- Located variant of 'go' + goL :: Precedence -> LHsType a -> LHsType a + goL ctxt_prec = mapXRec @a (go ctxt_prec) + + -- Optionally wrap a type in parens + paren + :: Precedence -- Precedence of context + -> Precedence -- Precedence of top-level operator + -> HsType a + -> HsType a -- Wrap in parens if (ctxt >= op) + paren ctxt_prec op_prec + | ctxt_prec >= op_prec = HsParTy noAnn . wrapXRec @a + | otherwise = id -- | Add parenthesis around the types in a 'HsType' (see 'reparenTypePrec') reparenType :: XRecCond a => HsType a -> HsType a reparenType = reparenTypePrec PREC_TOP -- | Add parenthesis around the types in a 'LHsType' (see 'reparenTypePrec') -reparenLType :: forall a. (XRecCond a) => LHsType a -> LHsType a +reparenLType :: forall a. XRecCond a => LHsType a -> LHsType a reparenLType = mapXRec @a reparenType -- | Add parentheses around the types in an 'HsSigType' (see 'reparenTypePrec') -reparenSigType :: forall a. ( XRecCond a ) - => HsSigType a -> HsSigType a +reparenSigType + :: forall a + . XRecCond a + => HsSigType a + -> HsSigType a reparenSigType (HsSig x bndrs body) = HsSig x (reparenOuterTyVarBndrs bndrs) (reparenLType body) reparenSigType v@XHsSigType{} = v -- | Add parentheses around the types in an 'HsOuterTyVarBndrs' (see 'reparenTypePrec') -reparenOuterTyVarBndrs :: forall flag a. ( XRecCond a ) - => HsOuterTyVarBndrs flag a -> HsOuterTyVarBndrs flag a +reparenOuterTyVarBndrs + :: forall flag a + . XRecCond a + => HsOuterTyVarBndrs flag a + -> HsOuterTyVarBndrs flag a reparenOuterTyVarBndrs imp@HsOuterImplicit{} = imp reparenOuterTyVarBndrs (HsOuterExplicit x exp_bndrs) = HsOuterExplicit x (map (mapXRec @(NoGhcTc a) reparenTyVar) exp_bndrs) reparenOuterTyVarBndrs v@XHsOuterTyVarBndrs{} = v -- | Add parentheses around the types in an 'HsForAllTelescope' (see 'reparenTypePrec') -reparenHsForAllTelescope :: forall a. (XRecCond a ) - => HsForAllTelescope a -> HsForAllTelescope a +reparenHsForAllTelescope + :: forall a + . XRecCond a + => HsForAllTelescope a + -> HsForAllTelescope a reparenHsForAllTelescope (HsForAllVis x bndrs) = HsForAllVis x (map (mapXRec @a reparenTyVar) bndrs) reparenHsForAllTelescope (HsForAllInvis x bndrs) = @@ -438,21 +518,21 @@ reparenHsForAllTelescope (HsForAllInvis x bndrs) = reparenHsForAllTelescope v@XHsForAllTelescope{} = v -- | Add parenthesis around the types in a 'HsTyVarBndr' (see 'reparenTypePrec') -reparenTyVar :: (XRecCond a) => HsTyVarBndr flag a -> HsTyVarBndr flag a +reparenTyVar :: XRecCond a => HsTyVarBndr flag a -> HsTyVarBndr flag a reparenTyVar (UserTyVar x flag n) = UserTyVar x flag n reparenTyVar (KindedTyVar x flag n kind) = KindedTyVar x flag n (reparenLType kind) reparenTyVar v@XTyVarBndr{} = v -- | Add parenthesis around the types in a 'ConDeclField' (see 'reparenTypePrec') -reparenConDeclField :: (XRecCond a) => ConDeclField a -> ConDeclField a +reparenConDeclField :: XRecCond a => ConDeclField a -> ConDeclField a reparenConDeclField (ConDeclField x n t d) = ConDeclField x n (reparenLType t) d reparenConDeclField c@XConDeclField{} = c - ------------------------------------------------------------------------------- + -- * Located -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- unL :: GenLocated l a -> a unL (L _ x) = x @@ -464,22 +544,23 @@ mapMA :: Monad m => (a -> m b) -> LocatedAn an a -> m (Located b) mapMA f (L al a) = L (locA al) <$> f a ------------------------------------------------------------------------------- + -- * NamedThing instances -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- instance NamedThing (TyClDecl GhcRn) where getName = tcdName ------------------------------------------------------------------------------- + -- * Subordinates -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- class Parent a where children :: a -> [Name] - instance Parent (ConDecl GhcRn) where children con = case getRecConArgs_maybe con of @@ -488,19 +569,19 @@ instance Parent (ConDecl GhcRn) where instance Parent (TyClDecl GhcRn) where children d - | isDataDecl d = map unLoc $ concatMap (toList . getConNames . unLoc) - $ (dd_cons . tcdDataDefn) d + | isDataDecl d = + map unLoc $ + concatMap (toList . getConNames . unLoc) $ + (dd_cons . tcdDataDefn) d | isClassDecl d = - map (unLoc . fdLName . unLoc) (tcdATs d) ++ - [ unLoc n | L _ (TypeSig _ ns _) <- tcdSigs d, n <- ns ] + map (unLoc . fdLName . unLoc) (tcdATs d) + ++ [unLoc n | L _ (TypeSig _ ns _) <- tcdSigs d, n <- ns] | otherwise = [] - -- | A parent and its children family :: (NamedThing a, Parent a) => a -> (Name, [Name]) family = getName &&& children - familyConDecl :: ConDecl GHC.GhcRn -> [(Name, [Name])] familyConDecl d = zip (toList $ unLoc <$> getConNames d) (repeat $ children d) @@ -508,26 +589,24 @@ familyConDecl d = zip (toList $ unLoc <$> getConNames d) (repeat $ children d) -- child to its grand-children, recursively. families :: TyClDecl GhcRn -> [(Name, [Name])] families d - | isDataDecl d = family d : concatMap (familyConDecl . unLoc) (dd_cons (tcdDataDefn d)) + | isDataDecl d = family d : concatMap (familyConDecl . unLoc) (dd_cons (tcdDataDefn d)) | isClassDecl d = [family d] - | otherwise = [] - + | otherwise = [] -- | A mapping from child to parent parentMap :: TyClDecl GhcRn -> [(Name, Name)] -parentMap d = [ (c, p) | (p, cs) <- families d, c <- cs ] - +parentMap d = [(c, p) | (p, cs) <- families d, c <- cs] -- | The parents of a subordinate in a declaration parents :: Name -> HsDecl GhcRn -> [Name] -parents n (TyClD _ d) = [ p | (c, p) <- parentMap d, c == n ] +parents n (TyClD _ d) = [p | (c, p) <- parentMap d, c == n] parents _ _ = [] - ------------------------------------------------------------------------------- + -- * Utils that work in monads defined by GHC -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- modifySessionDynFlags :: (DynFlags -> DynFlags) -> Ghc () modifySessionDynFlags f = do @@ -535,24 +614,28 @@ modifySessionDynFlags f = do _ <- setSessionDynFlags (f dflags) return () - ------------------------------------------------------------------------------- + -- * DynFlags + ------------------------------------------------------------------------------- -- TODO: use `setOutputDir` from GHC setOutputDir :: FilePath -> DynFlags -> DynFlags setOutputDir dir dynFlags = - dynFlags { objectDir = Just dir - , hiDir = Just dir - , hieDir = Just dir - , stubDir = Just dir - , includePaths = addGlobalInclude (includePaths dynFlags) [dir] - , dumpDir = Just dir - } + dynFlags + { objectDir = Just dir + , hiDir = Just dir + , hieDir = Just dir + , stubDir = Just dir + , includePaths = addGlobalInclude (includePaths dynFlags) [dir] + , dumpDir = Just dir + } ------------------------------------------------------------------------------- + -- * 'StringBuffer' and 'ByteString' + ------------------------------------------------------------------------------- -- We get away with a bunch of these functions because 'StringBuffer' and -- 'ByteString' have almost exactly the same structure. @@ -563,8 +646,8 @@ setOutputDir dir dynFlags = -- /O(n)/ (but optimized into a @memcpy@ by @bytestring@ under the hood) stringBufferFromByteString :: ByteString -> StringBuffer stringBufferFromByteString bs = - let BS.PS fp off len = bs <> BS.pack [0,0,0] - in S.StringBuffer { S.buf = fp, S.len = len - 3, S.cur = off } + let BS.PS fp off len = bs <> BS.pack [0, 0, 0] + in S.StringBuffer{S.buf = fp, S.len = len - 3, S.cur = off} -- | Take the first @n@ /bytes/ of the 'StringBuffer' and put them in a -- 'ByteString'. @@ -580,7 +663,8 @@ takeStringBuffer !n (S.StringBuffer fp _ cur) = BS.PS fp cur n -- /O(1)/ splitStringBuffer :: StringBuffer -> StringBuffer -> ByteString splitStringBuffer buf1 buf2 = takeStringBuffer n buf1 - where n = S.byteDiff buf1 buf2 + where + n = S.byteDiff buf1 buf2 -- | Split the 'StringBuffer' at the next newline (or the end of the buffer). -- Also: initial position is passed in and the updated position is returned. @@ -589,33 +673,35 @@ splitStringBuffer buf1 buf2 = takeStringBuffer n buf1 spanLine :: RealSrcLoc -> StringBuffer -> (ByteString, RealSrcLoc, StringBuffer) spanLine !loc !buf = go loc buf where - - go !l !b - | not (S.atEnd b) - = case S.nextChar b of - ('\n', b') -> (splitStringBuffer buf b', advanceSrcLoc l '\n', b') - (c, b') -> go (advanceSrcLoc l c) b' - | otherwise - = (splitStringBuffer buf b, advanceSrcLoc l '\n', b) + go !l !b + | not (S.atEnd b) = + case S.nextChar b of + ('\n', b') -> (splitStringBuffer buf b', advanceSrcLoc l '\n', b') + (c, b') -> go (advanceSrcLoc l c) b' + | otherwise = + (splitStringBuffer buf b, advanceSrcLoc l '\n', b) -- | Given a start position and a buffer with that start position, split the -- buffer at an end position. -- -- /O(n)/ (but /O(1)/ space) -spanPosition :: RealSrcLoc -- ^ start of buffeer - -> RealSrcLoc -- ^ position until which to take - -> StringBuffer -- ^ buffer from which to take - -> (ByteString, StringBuffer) +spanPosition + :: RealSrcLoc + -- ^ start of buffeer + -> RealSrcLoc + -- ^ position until which to take + -> StringBuffer + -- ^ buffer from which to take + -> (ByteString, StringBuffer) spanPosition !start !end !buf = go start buf where - - go !l !b - | l < end - , not (S.atEnd b) - , (c, b') <- S.nextChar b - = go (advanceSrcLoc l c) b' - | otherwise - = (splitStringBuffer buf b, b) + go !l !b + | l < end + , not (S.atEnd b) + , (c, b') <- S.nextChar b = + go (advanceSrcLoc l c) b' + | otherwise = + (splitStringBuffer buf b, b) -- | Try to parse a line of CPP from the from of the buffer. A \"line\" of CPP -- consists of @@ -630,44 +716,48 @@ spanPosition !start !end !buf = go start buf tryCppLine :: RealSrcLoc -> StringBuffer -> Maybe (ByteString, RealSrcLoc, StringBuffer) tryCppLine !loc !buf = spanSpace (S.prevChar buf '\n' == '\n') loc buf where - - -- Keep consuming space characters until we hit either a @#@ or something - -- else. If we hit a @#@, start parsing CPP - spanSpace !seenNl !l !b - | S.atEnd b - = Nothing - | otherwise - = case S.nextChar b of - ('#' , b') | not (S.atEnd b') - , ('-', b'') <- S.nextChar b' - , ('}', _) <- S.nextChar b'' - -> Nothing -- Edge case exception for @#-}@ - | seenNl - -> Just (spanCppLine (advanceSrcLoc l '#') b') -- parse CPP - | otherwise - -> Nothing -- We didn't see a newline, so this can't be CPP! - - (c , b') | isSpace c -> spanSpace (seenNl || c == '\n') - (advanceSrcLoc l c) b' - | otherwise -> Nothing - - -- Consume a CPP line to its "end" (basically the first line that ends not - -- with a @\@ character) - spanCppLine !l !b - | S.atEnd b - = (splitStringBuffer buf b, l, b) - | otherwise - = case S.nextChar b of - ('\\', b') | not (S.atEnd b') - , ('\n', b'') <- S.nextChar b' - -> spanCppLine (advanceSrcLoc (advanceSrcLoc l '\\') '\n') b'' - - ('\n', b') -> (splitStringBuffer buf b', advanceSrcLoc l '\n', b') - - (c , b') -> spanCppLine (advanceSrcLoc l c) b' + -- Keep consuming space characters until we hit either a @#@ or something + -- else. If we hit a @#@, start parsing CPP + spanSpace !seenNl !l !b + | S.atEnd b = + Nothing + | otherwise = + case S.nextChar b of + ('#', b') + | not (S.atEnd b') + , ('-', b'') <- S.nextChar b' + , ('}', _) <- S.nextChar b'' -> + Nothing -- Edge case exception for @#-}@ + | seenNl -> + Just (spanCppLine (advanceSrcLoc l '#') b') -- parse CPP + | otherwise -> + Nothing -- We didn't see a newline, so this can't be CPP! + (c, b') + | isSpace c -> + spanSpace + (seenNl || c == '\n') + (advanceSrcLoc l c) + b' + | otherwise -> Nothing + + -- Consume a CPP line to its "end" (basically the first line that ends not + -- with a @\@ character) + spanCppLine !l !b + | S.atEnd b = + (splitStringBuffer buf b, l, b) + | otherwise = + case S.nextChar b of + ('\\', b') + | not (S.atEnd b') + , ('\n', b'') <- S.nextChar b' -> + spanCppLine (advanceSrcLoc (advanceSrcLoc l '\\') '\n') b'' + ('\n', b') -> (splitStringBuffer buf b', advanceSrcLoc l '\n', b') + (c, b') -> spanCppLine (advanceSrcLoc l c) b' ------------------------------------------------------------------------------- + -- * Names in a 'Type' + ------------------------------------------------------------------------------- -- | Given a 'Type', return a set of 'Name's coming from the 'TyCon's within @@ -678,29 +768,33 @@ typeNames ty = go ty Set.empty go :: Type -> Set.Set Name -> Set.Set Name go t acc = case t of - TyVarTy {} -> acc - AppTy t1 t2 -> go t2 $ go t1 acc + TyVarTy{} -> acc + AppTy t1 t2 -> go t2 $ go t1 acc FunTy _ _ t1 t2 -> go t2 $ go t1 acc TyConApp tcon args -> foldl' (\s t' -> go t' s) (Set.insert (getName tcon) acc) args ForAllTy bndr t' -> go t' $ go (tyVarKind (binderVar bndr)) acc LitTy _ -> acc CastTy t' _ -> go t' acc - CoercionTy {} -> acc + CoercionTy{} -> acc ------------------------------------------------------------------------------- + -- * Free variables of a 'Type' + ------------------------------------------------------------------------------- -- | Get free type variables in a 'Type' in their order of appearance. -- See [Ordering of implicit variables]. orderedFVs - :: VarSet -- ^ free variables to ignore - -> [Type] -- ^ types to traverse (in order) looking for free variables - -> [TyVar] -- ^ free type variables, in the order they appear in + :: VarSet + -- ^ free variables to ignore + -> [Type] + -- ^ types to traverse (in order) looking for free variables + -> [TyVar] + -- ^ free type variables, in the order they appear in orderedFVs vs tys = reverse . fst $ tyCoFVsOfTypes' tys (const True) vs ([], emptyVarSet) - -- See the "Free variables of types and coercions" section in 'TyCoRep', or -- check out Note [Free variables of types]. The functions in this section -- don't output type variables in the order they first appear in in the 'Type'. @@ -726,31 +820,37 @@ orderedFVs vs tys = -- | Just like 'tyCoFVsOfType', but traverses type variables in reverse order -- of appearance. tyCoFVsOfType' :: Type -> FV -tyCoFVsOfType' (TyVarTy v) a b c = (FV.unitFV v `unionFV` tyCoFVsOfType' (tyVarKind v)) a b c -tyCoFVsOfType' (TyConApp _ tys) a b c = tyCoFVsOfTypes' tys a b c -tyCoFVsOfType' (LitTy {}) a b c = emptyFV a b c -tyCoFVsOfType' (AppTy fun arg) a b c = (tyCoFVsOfType' arg `unionFV` tyCoFVsOfType' fun) a b c -tyCoFVsOfType' (FunTy _ w arg res) a b c = (tyCoFVsOfType' w `unionFV` - tyCoFVsOfType' res `unionFV` - tyCoFVsOfType' arg) a b c -tyCoFVsOfType' (ForAllTy bndr ty) a b c = tyCoFVsBndr' bndr (tyCoFVsOfType' ty) a b c -tyCoFVsOfType' (CastTy ty _) a b c = (tyCoFVsOfType' ty) a b c -tyCoFVsOfType' (CoercionTy _ ) a b c = emptyFV a b c +tyCoFVsOfType' (TyVarTy v) a b c = (FV.unitFV v `unionFV` tyCoFVsOfType' (tyVarKind v)) a b c +tyCoFVsOfType' (TyConApp _ tys) a b c = tyCoFVsOfTypes' tys a b c +tyCoFVsOfType' (LitTy{}) a b c = emptyFV a b c +tyCoFVsOfType' (AppTy fun arg) a b c = (tyCoFVsOfType' arg `unionFV` tyCoFVsOfType' fun) a b c +tyCoFVsOfType' (FunTy _ w arg res) a b c = + ( tyCoFVsOfType' w + `unionFV` tyCoFVsOfType' res + `unionFV` tyCoFVsOfType' arg + ) + a + b + c +tyCoFVsOfType' (ForAllTy bndr ty) a b c = tyCoFVsBndr' bndr (tyCoFVsOfType' ty) a b c +tyCoFVsOfType' (CastTy ty _) a b c = (tyCoFVsOfType' ty) a b c +tyCoFVsOfType' (CoercionTy _) a b c = emptyFV a b c -- | Just like 'tyCoFVsOfTypes', but traverses type variables in reverse order -- of appearance. tyCoFVsOfTypes' :: [Type] -> FV -tyCoFVsOfTypes' (ty:tys) fv_cand in_scope acc = (tyCoFVsOfTypes' tys `unionFV` tyCoFVsOfType' ty) fv_cand in_scope acc -tyCoFVsOfTypes' [] fv_cand in_scope acc = emptyFV fv_cand in_scope acc +tyCoFVsOfTypes' (ty : tys) fv_cand in_scope acc = (tyCoFVsOfTypes' tys `unionFV` tyCoFVsOfType' ty) fv_cand in_scope acc +tyCoFVsOfTypes' [] fv_cand in_scope acc = emptyFV fv_cand in_scope acc -- | Just like 'tyCoFVsBndr', but traverses type variables in reverse order of -- appearance. tyCoFVsBndr' :: TyVarBinder -> FV -> FV tyCoFVsBndr' (Bndr tv _) fvs = FV.delFV tv fvs `unionFV` tyCoFVsOfType' (tyVarKind tv) - ------------------------------------------------------------------------------- + -- * Defaulting RuntimeRep variables + ------------------------------------------------------------------------------- -- | Traverses the type, defaulting type variables of kind 'RuntimeRep' to @@ -762,33 +862,28 @@ defaultRuntimeRepVars = go emptyVarEnv go :: TyVarEnv () -> Type -> Type go subs (ForAllTy (Bndr var flg) ty) | isRuntimeRepVar var - , isInvisibleForAllTyFlag flg - = let subs' = extendVarEnv subs var () - in go subs' ty - | otherwise - = ForAllTy (Bndr (updateTyVarKind (go subs) var) flg) - (go subs ty) - + , isInvisibleForAllTyFlag flg = + let subs' = extendVarEnv subs var () + in go subs' ty + | otherwise = + ForAllTy + (Bndr (updateTyVarKind (go subs) var) flg) + (go subs ty) go subs (TyVarTy tv) - | tv `elemVarEnv` subs - = liftedRepTy - | otherwise - = TyVarTy (updateTyVarKind (go subs) tv) - - go subs (TyConApp tc tc_args) - = TyConApp tc (map (go subs) tc_args) - - go subs (FunTy af w arg res) - = FunTy af (go subs w) (go subs arg) (go subs res) - - go subs (AppTy t u) - = AppTy (go subs t) (go subs u) - - go subs (CastTy x co) - = CastTy (go subs x) co - - go _ ty@(LitTy {}) = ty - go _ ty@(CoercionTy {}) = ty + | tv `elemVarEnv` subs = + liftedRepTy + | otherwise = + TyVarTy (updateTyVarKind (go subs) tv) + go subs (TyConApp tc tc_args) = + TyConApp tc (map (go subs) tc_args) + go subs (FunTy af w arg res) = + FunTy af (go subs w) (go subs arg) (go subs res) + go subs (AppTy t u) = + AppTy (go subs t) (go subs u) + go subs (CastTy x co) = + CastTy (go subs x) co + go _ ty@(LitTy{}) = ty + go _ ty@(CoercionTy{}) = ty fromMaybeContext :: Maybe (LHsContext DocNameI) -> HsContext DocNameI fromMaybeContext mctxt = unLoc $ fromMaybe (noLocA []) mctxt diff --git a/haddock-api/src/Haddock/Interface/AttachInstances.hs b/haddock-api/src/Haddock/Interface/AttachInstances.hs index 9120d293cc..0293afb747 100644 --- a/haddock-api/src/Haddock/Interface/AttachInstances.hs +++ b/haddock-api/src/Haddock/Interface/AttachInstances.hs @@ -1,16 +1,17 @@ -{-# LANGUAGE MagicHash #-} -{-# LANGUAGE BangPatterns #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE BangPatterns #-} -{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MagicHash #-} +{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE TupleSections #-} -{-# LANGUAGE NamedFieldPuns #-} - +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE TypeFamilies #-} {-# OPTIONS_GHC -Wno-incomplete-record-updates #-} {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.Interface.AttachInstances -- Copyright : (c) Simon Marlow 2006, @@ -21,10 +22,8 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------ module Haddock.Interface.AttachInstances (attachInstances, instHead) where - import Haddock.Convert import Haddock.GhcUtils (typeNames) import Haddock.Types @@ -32,43 +31,42 @@ import Haddock.Types import Control.Applicative ((<|>)) import Control.Arrow hiding ((<+>)) import Control.DeepSeq (force) -import Data.Foldable (foldl') +import Data.Foldable (foldl', toList) import Data.List (sortBy) -import qualified Data.Sequence as Seq -import Data.Ord (comparing) -import Data.Maybe ( maybeToList, mapMaybe, fromMaybe ) import qualified Data.Map.Strict as Map +import Data.Maybe (fromMaybe, mapMaybe, maybeToList) +import Data.Ord (comparing) +import qualified Data.Sequence as Seq import qualified Data.Set as Set -import Data.Foldable (toList) -import GHC.Data.FastString (unpackFS) -import GHC.Core.Class +import GHC +import GHC.Builtin.Types (unrestrictedFunTyConName) import GHC.Core (isOrphan) +import GHC.Core.Class +import GHC.Core.Coercion +import GHC.Core.Coercion.Axiom import GHC.Core.FamInstEnv -import GHC import GHC.Core.InstEnv -import GHC.Unit.Module.Env ( moduleSetElts, mkModuleSet ) -import GHC.Unit.State +import GHC.Core.TyCo.Compare (eqType) +import GHC.Core.TyCo.Rep +import GHC.Core.TyCon +import GHC.Data.FastString (unpackFS) +import GHC.Driver.Env.Types +import GHC.HsToCore.Docs +import GHC.Iface.Load +import GHC.Tc.Instance.Family +import GHC.Tc.Utils.Env +import GHC.Tc.Utils.Monad import GHC.Types.Name -import GHC.Types.Name.Set import GHC.Types.Name.Env -import GHC.Types.Unique.Map -import GHC.Utils.Outputable (text, sep, (<+>)) +import GHC.Types.Name.Set import GHC.Types.SrcLoc -import GHC.Core.TyCon -import GHC.Core.TyCo.Rep -import GHC.Builtin.Types( unrestrictedFunTyConName ) +import GHC.Types.Unique.Map import GHC.Types.Var hiding (varName) -import GHC.HsToCore.Docs -import GHC.Driver.Env.Types import GHC.Unit.Env -import GHC.Core.Coercion.Axiom -import GHC.Tc.Utils.Monad -import GHC.Tc.Utils.Env -import GHC.Tc.Instance.Family -import GHC.Iface.Load -import GHC.Core.TyCo.Compare (eqType) -import GHC.Core.Coercion +import GHC.Unit.Module.Env (mkModuleSet, moduleSetElts) +import GHC.Unit.State +import GHC.Utils.Outputable (sep, text, (<+>)) type ExportedNames = Set.Set Name type Modules = Set.Set Module @@ -77,7 +75,6 @@ type ExportInfo = (ExportedNames, Modules) -- Also attaches fixities attachInstances :: ExportInfo -> [Interface] -> InstIfaceMap -> Ghc [Interface] attachInstances expInfo ifaces instIfaceMap = do - -- We need to keep load modules in which we will look for instances. We've -- somewhat arbitrarily decided to load all modules which are available - -- either directly or from a re-export. @@ -85,15 +82,19 @@ attachInstances expInfo ifaces instIfaceMap = do -- See https://github.com/haskell/haddock/issues/469. env <- getSession let mod_to_pkg_conf = moduleNameProvidersMap $ ue_units $ hsc_unit_env env - mods = mkModuleSet [ m - | mod_map <- nonDetEltsUniqMap mod_to_pkg_conf - , ( m - , ModOrigin { fromOrigUnit = fromOrig - , fromExposedReexport = reExp - } - ) <- nonDetUniqMapToList mod_map - , fromOrig == Just True || not (null reExp) - ] + mods = + mkModuleSet + [ m + | mod_map <- nonDetEltsUniqMap mod_to_pkg_conf + , ( m + , ModOrigin + { fromOrigUnit = fromOrig + , fromExposedReexport = reExp + } + ) <- + nonDetUniqMapToList mod_map + , fromOrig == Just True || not (null reExp) + ] mods_to_load = moduleSetElts mods mods_visible = mkModuleSet $ map ifaceMod ifaces @@ -107,69 +108,88 @@ attachInstances expInfo ifaces instIfaceMap = do -- We use Data.Sequence.Seq because we are creating left associated -- mappends. -- cls_index and fam_index below are adapted from GHC.Tc.Module.lookupInsts - let cls_index = Map.fromListWith mappend - [ (n, Seq.singleton ispec) - | ispec <- instEnvElts ie_local ++ instEnvElts ie_global - , instIsVisible mods_visible ispec - , n <- nameSetElemsStable $ orphNamesOfClsInst ispec - ] - fam_index = Map.fromListWith mappend - [ (n, Seq.singleton fispec) - | fispec <- famInstEnvElts home_fie ++ famInstEnvElts pkg_fie - , n <- nameSetElemsStable $ orphNamesOfFamInst fispec - ] - instance_map = mkNameEnv $ - [ (nm, (toList clss, toList fams)) - | (nm, (clss, fams)) <- Map.toList $ Map.unionWith mappend - (fmap (,Seq.empty) cls_index) - (fmap (Seq.empty,) fam_index) - ] + let cls_index = + Map.fromListWith + mappend + [ (n, Seq.singleton ispec) + | ispec <- instEnvElts ie_local ++ instEnvElts ie_global + , instIsVisible mods_visible ispec + , n <- nameSetElemsStable $ orphNamesOfClsInst ispec + ] + fam_index = + Map.fromListWith + mappend + [ (n, Seq.singleton fispec) + | fispec <- famInstEnvElts home_fie ++ famInstEnvElts pkg_fie + , n <- nameSetElemsStable $ orphNamesOfFamInst fispec + ] + instance_map = + mkNameEnv $ + [ (nm, (toList clss, toList fams)) + | (nm, (clss, fams)) <- + Map.toList $ + Map.unionWith + mappend + (fmap (,Seq.empty) cls_index) + (fmap (Seq.empty,) fam_index) + ] pure $ (cls_env{ie_visible = mods_visible}, fam_env, instance_map) let empty_index = (InstEnvs emptyInstEnv emptyInstEnv mods_visible, emptyFamInstEnvs, emptyNameEnv) mapM (attach $ fromMaybe empty_index mb_index) ifaces where -- TODO: take an IfaceMap as input - ifaceMap = Map.fromList [ (ifaceMod i, i) | i <- ifaces ] + ifaceMap = Map.fromList [(ifaceMod i, i) | i <- ifaces] attach (cls_insts, fam_insts, inst_map) iface = do - let getInstDoc = findInstDoc iface ifaceMap instIfaceMap getFixity = findFixity iface ifaceMap instIfaceMap - newItems <- mapM (attachToExportItem cls_insts fam_insts inst_map expInfo getInstDoc getFixity) - (ifaceExportItems iface) + newItems <- + mapM + (attachToExportItem cls_insts fam_insts inst_map expInfo getInstDoc getFixity) + (ifaceExportItems iface) let orphanInstances = attachOrphanInstances expInfo getInstDoc (ifaceInstances iface) fam_insts - return $ iface { ifaceExportItems = newItems - , ifaceOrphanInstances = orphanInstances - } + return $ + iface + { ifaceExportItems = newItems + , ifaceOrphanInstances = orphanInstances + } attachOrphanInstances :: ExportInfo - -> (Name -> Maybe (MDoc Name)) -- ^ how to lookup the doc of an instance - -> [ClsInst] -- ^ a list of orphan instances - -> FamInstEnvs -- ^ all the family instances (that we know of) + -> (Name -> Maybe (MDoc Name)) + -- ^ how to lookup the doc of an instance + -> [ClsInst] + -- ^ a list of orphan instances + -> FamInstEnvs + -- ^ all the family instances (that we know of) -> [DocInstance GhcRn] attachOrphanInstances expInfo getInstDoc cls_instances fam_index = [ (synifyInstHead i famInsts, getInstDoc n, (L (getSrcSpan n) n), nameModule_maybe n) - | let is = [ (instanceSig i, getName i) | i <- cls_instances, isOrphan (is_orphan i) ] - , (i@(_,_,cls,tys), n) <- sortBy (comparing $ first instHead) is + | let is = [(instanceSig i, getName i) | i <- cls_instances, isOrphan (is_orphan i)] + , (i@(_, _, cls, tys), n) <- sortBy (comparing $ first instHead) is , not $ isInstanceHidden expInfo (getName cls) tys , let famInsts = getFamInsts expInfo fam_index getInstDoc cls tys ] attachToExportItem - :: InstEnvs -- ^ all class instances (that we know of) - -> FamInstEnvs -- ^ all the family instances (that we know of) - -> NameEnv ([ClsInst], [FamInst]) -- ^ all instances again, but for looking up instances for data families + :: InstEnvs + -- ^ all class instances (that we know of) + -> FamInstEnvs + -- ^ all the family instances (that we know of) + -> NameEnv ([ClsInst], [FamInst]) + -- ^ all instances again, but for looking up instances for data families -> ExportInfo - -> (Name -> Maybe (MDoc Name)) -- ^ how to lookup the doc of an instance - -> (Name -> Maybe Fixity) -- ^ how to lookup a fixity + -> (Name -> Maybe (MDoc Name)) + -- ^ how to lookup the doc of an instance + -> (Name -> Maybe Fixity) + -- ^ how to lookup a fixity -> ExportItem GhcRn -> Ghc (ExportItem GhcRn) attachToExportItem cls_index fam_index index expInfo getInstDoc getFixity export = case attachFixities export of - ExportDecl e@(ExportD { expDDecl = L eSpan (TyClD _ d) }) -> do + ExportDecl e@(ExportD{expDDecl = L eSpan (TyClD _ d)}) -> do insts <- let nm = tcdName d (cls_instances, fam_instances) = case d of @@ -177,99 +197,105 @@ attachToExportItem cls_index fam_index index expInfo getInstDoc getFixity export ClassDecl{} -> (classNameInstances cls_index nm, familyNameInstances fam_index nm) -- Otherwise, we have to filter through all the instances to see if they mention this -- name. See GHCi :info implementation - _ -> fromMaybe ([],[]) $ lookupNameEnv index nm - - fam_insts = [ ( synFamInst - , getInstDoc n - , spanNameE n synFamInst (L (locA eSpan) (tcdName d)) - , mb_mdl - ) - | i <- sortBy (comparing instFam) fam_instances - , let n = getName i - , not $ isNameHidden expInfo (fi_fam i) - , not $ any (isTypeHidden expInfo) (fi_tys i) - , let opaque = isTypeHidden expInfo (fi_rhs i) - synFamInst = synifyFamInst i opaque - !mb_mdl = force $ nameModule_maybe n - ] - cls_insts = [ ( synClsInst - , getInstDoc n - , spanName n synClsInst (L (locA eSpan) (tcdName d)) - , mb_mdl - ) - | let is = [ (instanceSig i, getName i) | i <- cls_instances ] - , (i@(_,_,cls,tys), n) <- sortBy (comparing $ first instHead) is - , not $ isInstanceHidden expInfo (getName cls) tys - , let synClsInst = synifyInstHead i famInsts - famInsts = getFamInsts expInfo fam_index getInstDoc cls tys - !mb_mdl = force $ nameModule_maybe n - ] - -- fam_insts but with failing type fams filtered out - cleanFamInsts = [ (fi, n, L l r, m) | (Right fi, n, L l (Right r), m) <- fam_insts ] - famInstErrs = [ errm | (Left errm, _, _, _) <- fam_insts ] - in do - let mkBug = (text "haddock-bug:" <+>) . text - putMsgM (sep $ map mkBug famInstErrs) - return $ cls_insts ++ cleanFamInsts - return $ ExportDecl e { expDInstances = insts } + _ -> fromMaybe ([], []) $ lookupNameEnv index nm + + fam_insts = + [ ( synFamInst + , getInstDoc n + , spanNameE n synFamInst (L (locA eSpan) (tcdName d)) + , mb_mdl + ) + | i <- sortBy (comparing instFam) fam_instances + , let n = getName i + , not $ isNameHidden expInfo (fi_fam i) + , not $ any (isTypeHidden expInfo) (fi_tys i) + , let opaque = isTypeHidden expInfo (fi_rhs i) + synFamInst = synifyFamInst i opaque + !mb_mdl = force $ nameModule_maybe n + ] + cls_insts = + [ ( synClsInst + , getInstDoc n + , spanName n synClsInst (L (locA eSpan) (tcdName d)) + , mb_mdl + ) + | let is = [(instanceSig i, getName i) | i <- cls_instances] + , (i@(_, _, cls, tys), n) <- sortBy (comparing $ first instHead) is + , not $ isInstanceHidden expInfo (getName cls) tys + , let synClsInst = synifyInstHead i famInsts + famInsts = getFamInsts expInfo fam_index getInstDoc cls tys + !mb_mdl = force $ nameModule_maybe n + ] + -- fam_insts but with failing type fams filtered out + cleanFamInsts = [(fi, n, L l r, m) | (Right fi, n, L l (Right r), m) <- fam_insts] + famInstErrs = [errm | (Left errm, _, _, _) <- fam_insts] + in do + let mkBug = (text "haddock-bug:" <+>) . text + putMsgM (sep $ map mkBug famInstErrs) + return $ cls_insts ++ cleanFamInsts + return $ ExportDecl e{expDInstances = insts} e -> return e where attachFixities - ( ExportDecl + ( ExportDecl ( e@ExportD { expDDecl = L _ d , expDPats = patsyns , expDSubDocs = subDocs } - ) - ) - = ExportDecl e - { expDFixities = fixities - } - where - fixities :: [(Name, Fixity)] - !fixities = force . Map.toList $ foldl' f Map.empty all_names - - f :: Map.Map Name Fixity -> Name -> Map.Map Name Fixity - f !fs n = Map.alter (<|> getFixity n) n fs - - patsyn_names :: [Name] - patsyn_names = concatMap (getMainDeclBinder emptyOccEnv . fst) patsyns - - all_names :: [Name] - all_names = - getMainDeclBinder emptyOccEnv d - ++ map fst subDocs - ++ patsyn_names - + ) + ) = + ExportDecl + e + { expDFixities = fixities + } + where + fixities :: [(Name, Fixity)] + !fixities = force . Map.toList $ foldl' f Map.empty all_names + + f :: Map.Map Name Fixity -> Name -> Map.Map Name Fixity + f !fs n = Map.alter (<|> getFixity n) n fs + + patsyn_names :: [Name] + patsyn_names = concatMap (getMainDeclBinder emptyOccEnv . fst) patsyns + + all_names :: [Name] + all_names = + getMainDeclBinder emptyOccEnv d + ++ map fst subDocs + ++ patsyn_names attachFixities e = e -- spanName: attach the location to the name that is the same file as the instance location - spanName s (InstHead { ihdClsName = clsn }) (L instL instn) = - let s1 = getSrcSpan s - sn = if srcSpanFileName_maybe s1 == srcSpanFileName_maybe instL - then instn - else clsn - in L (getSrcSpan s) sn + spanName s (InstHead{ihdClsName = clsn}) (L instL instn) = + let s1 = getSrcSpan s + sn = + if srcSpanFileName_maybe s1 == srcSpanFileName_maybe instL + then instn + else clsn + in L (getSrcSpan s) sn -- spanName on Either - spanNameE s (Left e) _ = L (getSrcSpan s) (Left e) + spanNameE s (Left e) _ = L (getSrcSpan s) (Left e) spanNameE s (Right ok) linst = let L l r = spanName s ok linst - in L l (Right r) + in L l (Right r) -substAgrees :: [(TyVar,Type)] -> [(TyVar,Type)] -> Bool +substAgrees :: [(TyVar, Type)] -> [(TyVar, Type)] -> Bool substAgrees xs ys = go xs where go [] = True - go ((v,t1) : zs) = case lookup v ys of + go ((v, t1) : zs) = case lookup v ys of Nothing -> go zs Just t2 -> eqType t1 t2 && go zs getFamInsts :: ExportInfo - -> FamInstEnvs -- ^ all the family instances (that we know of) - -> (Name -> Maybe (MDoc Name)) -- ^ how to lookup the doc of an instance - -> Class -> [Type] + -> FamInstEnvs + -- ^ all the family instances (that we know of) + -> (Name -> Maybe (MDoc Name)) + -- ^ how to lookup the doc of an instance + -> Class + -> [Type] -> [(FamInst, Bool, Maybe (MDoc Name), Located Name, Maybe Module)] getFamInsts expInfo fam_index getInstDoc cls tys = [ (f_i, opaque, getInstDoc f_n, L (getSrcSpan f_n) f_n, nameModule_maybe f_n) @@ -282,12 +308,13 @@ getFamInsts expInfo fam_index getInstDoc cls tys = Just instantiation -> map fim_instance $ lookupFamInstEnv fam_index fam instantiation -- If we don't have a complete instantation, we need to look over all possible instances -- for the family and filter out the ones that don't agree with the typeclass instance - Nothing -> [ f_i - | f_i <- familyInstances fam_index fam - , let co_tvs = tyConTyVars fam - (_, lhs, _) = etaExpandCoAxBranch $ coAxiomSingleBranch $ fi_axiom f_i - , substAgrees (zip co_tvs lhs) tv_env - ] + Nothing -> + [ f_i + | f_i <- familyInstances fam_index fam + , let co_tvs = tyConTyVars fam + (_, lhs, _) = etaExpandCoAxBranch $ coAxiomSingleBranch $ fi_axiom f_i + , substAgrees (zip co_tvs lhs) tv_env + ] , let ax = fi_axiom f_i f_n = co_ax_name ax , not $ isNameHidden expInfo (fi_fam f_i) @@ -298,42 +325,44 @@ getFamInsts expInfo fam_index getInstDoc cls tys = -- | Lookup the doc associated with a certain instance findInstDoc :: Interface -> IfaceMap -> InstIfaceMap -> Name -> Maybe (MDoc Name) findInstDoc iface ifaceMap instIfaceMap = \name -> - (Map.lookup name . ifaceDocMap $ iface) <|> - (Map.lookup name . ifaceDocMap =<< Map.lookup (nameModule name) ifaceMap) <|> - (Map.lookup name . instDocMap =<< Map.lookup (nameModule name) instIfaceMap) + (Map.lookup name . ifaceDocMap $ iface) + <|> (Map.lookup name . ifaceDocMap =<< Map.lookup (nameModule name) ifaceMap) + <|> (Map.lookup name . instDocMap =<< Map.lookup (nameModule name) instIfaceMap) -- | Lookup the fixity associated with a certain name findFixity :: Interface -> IfaceMap -> InstIfaceMap -> Name -> Maybe Fixity findFixity iface ifaceMap instIfaceMap = \name -> - (Map.lookup name . ifaceFixMap $ iface) <|> - (Map.lookup name . ifaceFixMap =<< Map.lookup (nameModule name) ifaceMap) <|> - (Map.lookup name . instFixMap =<< Map.lookup (nameModule name) instIfaceMap) - + (Map.lookup name . ifaceFixMap $ iface) + <|> (Map.lookup name . ifaceFixMap =<< Map.lookup (nameModule name) ifaceMap) + <|> (Map.lookup name . instFixMap =<< Map.lookup (nameModule name) instIfaceMap) -------------------------------------------------------------------------------- -- Collecting and sorting instances -------------------------------------------------------------------------------- instHead :: ([TyVar], [PredType], Class, [Type]) -> ([Int], SName, [SimpleType]) -instHead (_, _, cls, args) - = (map argCount args, SName (className cls), map simplify args) +instHead (_, _, cls, args) = + (map argCount args, SName (className cls), map simplify args) argCount :: Type -> Int -argCount (AppTy t _) = argCount t + 1 +argCount (AppTy t _) = argCount t + 1 argCount (TyConApp _ ts) = length ts argCount (FunTy _ _ _ _) = 2 -argCount (ForAllTy _ t) = argCount t -argCount (CastTy t _) = argCount t +argCount (ForAllTy _ t) = argCount t +argCount (CastTy t _) = argCount t argCount _ = 0 simplify :: Type -> SimpleType -simplify (FunTy _ _ t1 t2) = SimpleType (SName unrestrictedFunTyConName) [simplify t1, simplify t2] +simplify (FunTy _ _ t1 t2) = SimpleType (SName unrestrictedFunTyConName) [simplify t1, simplify t2] simplify (ForAllTy _ t) = simplify t simplify (AppTy t1 t2) = SimpleType s (ts ++ maybeToList (simplify_maybe t2)) - where (SimpleType s ts) = simplify t1 + where + (SimpleType s ts) = simplify t1 simplify (TyVarTy v) = SimpleType (SName (tyVarName v)) [] -simplify (TyConApp tc ts) = SimpleType (SName (tyConName tc)) - (mapMaybe simplify_maybe ts) +simplify (TyConApp tc ts) = + SimpleType + (SName (tyConName tc)) + (mapMaybe simplify_maybe ts) simplify (LitTy (NumTyLit n)) = SimpleIntTyLit n simplify (LitTy (StrTyLit s)) = SimpleStringTyLit (unpackFS s) simplify (LitTy (CharTyLit c)) = SimpleCharTyLit c @@ -341,14 +370,13 @@ simplify (CastTy ty _) = simplify ty simplify (CoercionTy _) = error "simplify:Coercion" simplify_maybe :: Type -> Maybe SimpleType -simplify_maybe (CoercionTy {}) = Nothing -simplify_maybe ty = Just (simplify ty) +simplify_maybe (CoercionTy{}) = Nothing +simplify_maybe ty = Just (simplify ty) -- Used for sorting instFam :: FamInst -> ([Int], SName, [SimpleType], Int, SimpleType) -instFam FamInst { fi_fam = n, fi_tys = ts, fi_rhs = t } - = (map argCount ts, SName n, map simplify ts, argCount t, simplify t) - +instFam FamInst{fi_fam = n, fi_tys = ts, fi_rhs = t} = + (map argCount ts, SName n, map simplify ts, argCount t, simplify t) -------------------------------------------------------------------------------- -- Filtering hidden instances @@ -361,14 +389,14 @@ instFam FamInst { fi_fam = n, fi_tys = ts, fi_rhs = t } -- * and it is not exported by any non-hidden module isNameHidden :: ExportInfo -> Name -> Bool isNameHidden (names, modules) name = - nameModule name `Set.member` modules && - not (name `Set.member` names) + nameModule name `Set.member` modules + && not (name `Set.member` names) -- | We say that an instance is «hidden» iff its class or any (part) -- of its type(s) is hidden. isInstanceHidden :: ExportInfo -> Name -> [Type] -> Bool isInstanceHidden expInfo cls tyNames = - instClassHidden || instTypeHidden + instClassHidden || instTypeHidden where instClassHidden :: Bool instClassHidden = isNameHidden expInfo cls diff --git a/haddock-api/src/Haddock/Interface/Create.hs b/haddock-api/src/Haddock/Interface/Create.hs index 29a457d141..df63ba98f1 100644 --- a/haddock-api/src/Haddock/Interface/Create.hs +++ b/haddock-api/src/Haddock/Interface/Create.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-} {-# LANGUAGE DerivingStrategies #-} @@ -7,6 +6,7 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} @@ -14,7 +14,11 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -Wwarn #-} + +----------------------------------------------------------------------------- + ----------------------------------------------------------------------------- + -- | -- Module : Haddock.Interface.Create -- Copyright : (c) Simon Marlow 2003-2006, @@ -29,16 +33,15 @@ -- This module provides a single function 'createInterface', -- which creates a Haddock 'Interface' from the typechecking -- results 'TypecheckedModule' from GHC. ------------------------------------------------------------------------------ module Haddock.Interface.Create (IfM, runIfM, createInterface1) where +import Documentation.Haddock.Doc import Haddock.Convert (PrintRuntimeReps (..), tyThingToLHsDecl) import Haddock.GhcUtils import Haddock.Interface.LexParseRn import Haddock.Options (Flag (..), modulePackageInfo) import Haddock.Types import Haddock.Utils (replace) -import Documentation.Haddock.Doc import Control.DeepSeq import Control.Monad.State.Strict @@ -51,27 +54,27 @@ import qualified Data.Map.Strict as Map import Data.Maybe (catMaybes, isJust, mapMaybe, maybeToList) import Data.Traversable (for) +import Control.Arrow (first, (&&&)) import GHC hiding (lookupName) -import qualified GHC.Types.Unique.Map as UniqMap +import GHC.Builtin.Names +import GHC.Builtin.Types +import GHC.Builtin.Types.Prim import GHC.Core.ConLike (ConLike (..)) -import GHC.Data.FastString (FastString, unpackFS, bytesFS) +import GHC.Data.FastString (FastString, bytesFS, unpackFS) +import GHC.Driver.Ppr import GHC.HsToCore.Docs hiding (mkMaps) +import GHC.Iface.Syntax import GHC.Types.Avail import GHC.Types.Basic import GHC.Types.Name import GHC.Types.Name.Set +import GHC.Types.SafeHaskell import qualified GHC.Types.SrcLoc as SrcLoc +import qualified GHC.Types.Unique.Map as UniqMap +import GHC.Unit.Module.ModIface import GHC.Unit.State (PackageName (..), UnitState) import qualified GHC.Utils.Outputable as O import GHC.Utils.Panic (pprPanic) -import GHC.Driver.Ppr -import GHC.Unit.Module.ModIface -import GHC.Builtin.Names -import GHC.Builtin.Types -import GHC.Builtin.Types.Prim -import GHC.Types.SafeHaskell -import Control.Arrow ((&&&), first) -import GHC.Iface.Syntax createInterface1 :: MonadIO m @@ -81,28 +84,26 @@ createInterface1 -> ModIface -> IfaceMap -> InstIfaceMap - -> ([ClsInst],[FamInst]) + -> ([ClsInst], [FamInst]) -> IfM m Interface createInterface1 flags unit_state mod_sum mod_iface ifaces inst_ifaces (instances, fam_instances) = do - let ModSummary - { - -- Cached flags from OPTIONS, INCLUDE and LANGUAGE - -- pragmas in the modules source code. Used to infer - -- safety of module. - ms_hspp_opts - , ms_location = ModLocation - { - ml_hie_file - } + { -- Cached flags from OPTIONS, INCLUDE and LANGUAGE + -- pragmas in the modules source code. Used to infer + -- safety of module. + ms_hspp_opts + , ms_location = + ModLocation + { ml_hie_file + } } = mod_sum - dflags = ms_hspp_opts - mdl = mi_module mod_iface + dflags = ms_hspp_opts + mdl = mi_module mod_iface sem_mdl = mi_semantic_module mod_iface - is_sig = isJust (mi_sig_of mod_iface) - safety = getSafeMode (mi_trust mod_iface) + is_sig = isJust (mi_sig_of mod_iface) + safety = getSafeMode (mi_trust mod_iface) (pkg_name_fs, _) = modulePackageInfo unit_state flags (Just mdl) @@ -111,17 +112,19 @@ createInterface1 flags unit_state mod_sum mod_iface ifaces inst_ifaces (instance pkg_name = let unpack (PackageName name) = unpackFS name - in + in fmap unpack pkg_name_fs warnings = mi_warns mod_iface -- See Note [Exporting built-in items] special_exports - | mdl == gHC_PRIM = funAvail - | otherwise = [] - !exportedNames = concatMap availNames - (special_exports <> mi_exports mod_iface) + | mdl == gHC_PRIM = funAvail + | otherwise = [] + !exportedNames = + concatMap + availNames + (special_exports <> mi_exports mod_iface) fixities :: FixMap fixities = mkFixMap exportedNames (mi_fixities mod_iface) @@ -129,11 +132,12 @@ createInterface1 flags unit_state mod_sum mod_iface ifaces inst_ifaces (instance -- This is used for looking up the Name of a default method -- from its OccName. See Note [default method Name] in GHC.Iface.Recomp def_meths_env = mkOccEnv def_meths - def_meths = [ (nameOccName nm, nm) - | (_, IfaceId { ifName = nm }) <- mi_decls mod_iface - , let occ = nameOccName nm - , isDefaultMethodOcc occ - ] + def_meths = + [ (nameOccName nm, nm) + | (_, IfaceId{ifName = nm}) <- mi_decls mod_iface + , let occ = nameOccName nm + , isDefaultMethodOcc occ + ] mod_iface_docs <- case mi_docs mod_iface of Just docs -> pure docs @@ -143,11 +147,15 @@ createInterface1 flags unit_state mod_sum mod_iface ifaces inst_ifaces (instance -- Derive final options to use for haddocking this module doc_opts <- mkDocOpts (docs_haddock_opts mod_iface_docs) flags mdl - let prr | OptPrintRuntimeRep `elem` doc_opts = ShowRuntimeRep - | otherwise = HideRuntimeRep + let prr + | OptPrintRuntimeRep `elem` doc_opts = ShowRuntimeRep + | otherwise = HideRuntimeRep (!info, header_doc) <- - processModuleHeader dflags pkg_name safety + processModuleHeader + dflags + pkg_name + safety (docs_language mod_iface_docs) (docs_extensions mod_iface_docs) (docs_mod_hdr mod_iface_docs) @@ -160,45 +168,47 @@ createInterface1 flags unit_state mod_sum mod_iface ifaces inst_ifaces (instance exportsSinceMap <- mkExportSinceMap dflags pkg_name mod_iface_docs (argMap :: Map Name (Map Int (MDoc Name))) <- do - let docsArgs = Map.fromList $ UniqMap.nonDetUniqMapToList mod_iface_docs.docs_args - (result :: Map Name (IntMap (MDoc Name))) <- - traverse (traverse (processDocStringParas dflags pkg_name)) docsArgs - let result2 = Map.map (\intMap -> Map.fromList $ IM.assocs intMap) result - pure $ result2 + let docsArgs = Map.fromList $ UniqMap.nonDetUniqMapToList mod_iface_docs.docs_args + (result :: Map Name (IntMap (MDoc Name))) <- + traverse (traverse (processDocStringParas dflags pkg_name)) docsArgs + let result2 = Map.map (\intMap -> Map.fromList $ IM.assocs intMap) result + pure $ result2 warningMap <- mkWarningMap dflags warnings exportedNames - let local_instances = filter (nameIsLocalOrFrom sem_mdl) - $ map getName instances - ++ map getName fam_instances - instanceMap = Map.fromList [(l, n) | n <- local_instances, RealSrcSpan l _ <- [getSrcSpan n] ] + let local_instances = + filter (nameIsLocalOrFrom sem_mdl) $ + map getName instances + ++ map getName fam_instances + instanceMap = Map.fromList [(l, n) | n <- local_instances, RealSrcSpan l _ <- [getSrcSpan n]] -- See Note [Exporting built-in items] let builtinTys = DsiSectionHeading 1 (WithHsDocIdentifiers (mkGeneratedHsDocString "Builtin syntax") []) bonus_ds mods - | mdl == gHC_PRIM = [ builtinTys, DsiExports funAvail ] <> mods - | otherwise = mods + | mdl == gHC_PRIM = [builtinTys, DsiExports funAvail] <> mods + | otherwise = mods let -- Warnings in this module and transitive warnings from dependent modules transitiveWarnings :: Map Name (Doc Name) transitiveWarnings = Map.unions (warningMap : map ifaceWarningMap (Map.elems ifaces)) - export_items <- mkExportItems - prr - ifaces - pkg_name - mdl - transitiveWarnings - exportsSinceMap - docMap - argMap - fixities - (docs_named_chunks mod_iface_docs) - (bonus_ds $ docs_structure mod_iface_docs) - inst_ifaces - dflags - def_meths_env + export_items <- + mkExportItems + prr + ifaces + pkg_name + mdl + transitiveWarnings + exportsSinceMap + docMap + argMap + fixities + (docs_named_chunks mod_iface_docs) + (bonus_ds $ docs_structure mod_iface_docs) + inst_ifaces + dflags + def_meths_env let visible_names :: [Name] @@ -214,31 +224,33 @@ createInterface1 flags unit_state mod_sum mod_iface ifaces inst_ifaces (instance coverage :: (Int, Int) !coverage = (haddockable, haddocked) - return $! Interface - { - ifaceMod = mdl - , ifaceIsSig = is_sig - , ifaceHieFile = ml_hie_file - , ifaceInfo = info - , ifaceDoc = Documentation header_doc mod_warning - , ifaceRnDoc = Documentation Nothing Nothing - , ifaceOptions = doc_opts - , ifaceDocMap = docMap - , ifaceArgMap = argMap - , ifaceExportItems = if OptPrune `elem` doc_opts then - pruned_export_items else export_items - , ifaceRnExportItems = [] - , ifaceExports = exportedNames - , ifaceVisibleExports = visible_names - , ifaceFixMap = fixities - , ifaceInstances = instances - , ifaceOrphanInstances = [] -- Filled in attachInstances - , ifaceRnOrphanInstances = [] -- Filled in renameInterfaceRn - , ifaceHaddockCoverage = coverage - , ifaceWarningMap = warningMap - , ifaceDynFlags = dflags - , ifaceDefMeths = def_meths - } + return $! + Interface + { ifaceMod = mdl + , ifaceIsSig = is_sig + , ifaceHieFile = ml_hie_file + , ifaceInfo = info + , ifaceDoc = Documentation header_doc mod_warning + , ifaceRnDoc = Documentation Nothing Nothing + , ifaceOptions = doc_opts + , ifaceDocMap = docMap + , ifaceArgMap = argMap + , ifaceExportItems = + if OptPrune `elem` doc_opts + then pruned_export_items + else export_items + , ifaceRnExportItems = [] + , ifaceExports = exportedNames + , ifaceVisibleExports = visible_names + , ifaceFixMap = fixities + , ifaceInstances = instances + , ifaceOrphanInstances = [] -- Filled in attachInstances + , ifaceRnOrphanInstances = [] -- Filled in renameInterfaceRn + , ifaceHaddockCoverage = coverage + , ifaceWarningMap = warningMap + , ifaceDynFlags = dflags + , ifaceDefMeths = def_meths + } where -- Note [Exporting built-in items] -- @@ -247,19 +259,20 @@ createInterface1 flags unit_state mod_sum mod_iface ifaces inst_ifaces (instance -- it to show up in docs, so we manually patch "GHC.Prim" and "Prelude" -- to have an extra exports for @(->)@ -- - funAvail = [ AvailTC fUNTyConName [fUNTyConName] ] + funAvail = [AvailTC fUNTyConName [fUNTyConName]] ------------------------------------------------------------------------------- -- Export @since annotations ------------------------------------------------------------------------------- mkExportSinceMap - :: forall m. (MonadIO m) + :: forall m + . MonadIO m => DynFlags -> Maybe Package -> Docs -> IfM m (Map Name MetaSince) mkExportSinceMap dflags pkg_name docs = do - Map.unions <$> traverse processExportDoc (UniqMap.nonDetUniqMapToList (docs_exports docs)) + Map.unions <$> traverse processExportDoc (UniqMap.nonDetUniqMapToList (docs_exports docs)) where processExportDoc :: (Name, HsDoc GhcRn) -> IfM m (Map Name MetaSince) processExportDoc (nm, doc) = do @@ -271,7 +284,6 @@ mkExportSinceMap dflags pkg_name docs = do Nothing -> return mempty Just since -> return $ Map.singleton nm since - ------------------------------------------------------------------------------- -- Warnings ------------------------------------------------------------------------------- @@ -291,8 +303,8 @@ mkWarningMap dflags warnings exps = -- resolves to multiple GREs, take the first. case lookupOccEnv_WithFields expsOccEnv occ of (n : _) -> Just (n, w) - [] -> Nothing - in Map.fromList <$> traverse (traverse (parseWarning dflags)) ws' + [] -> Nothing + in Map.fromList <$> traverse (traverse (parseWarning dflags)) ws' _ -> pure Map.empty moduleWarning @@ -301,7 +313,7 @@ moduleWarning -> IfaceWarnings -> IfM m (Maybe (Doc Name)) moduleWarning dflags (IfWarnAll w) = Just <$> parseWarning dflags w -moduleWarning _ _ = pure Nothing +moduleWarning _ _ = pure Nothing parseWarning :: MonadIO m @@ -310,7 +322,7 @@ parseWarning -> IfM m (Doc Name) parseWarning dflags w = case w of IfDeprecatedTxt _ msg -> format "Deprecated: " (map dstToDoc msg) - IfWarningTxt _ _ msg -> format "Warning: " (map dstToDoc msg) + IfWarningTxt _ _ msg -> format "Warning: " (map dstToDoc msg) where dstToDoc :: (IfaceStringLiteral, [Name]) -> HsDoc GhcRn dstToDoc ((IfStringLiteral _ fs), ids) = WithHsDocIdentifiers (fsToDoc fs) (map noLoc ids) @@ -318,8 +330,9 @@ parseWarning dflags w = case w of fsToDoc :: FastString -> HsDocString fsToDoc fs = GeneratedDocString $ HsDocStringChunk (bytesFS fs) - format x bs = DocWarning . DocParagraph . DocAppend (DocString x) - <$> foldrM (\doc rest -> docAppend <$> processDocString dflags doc <*> pure rest) DocEmpty bs + format x bs = + DocWarning . DocParagraph . DocAppend (DocString x) + <$> foldrM (\doc rest -> docAppend <$> processDocString dflags doc <*> pure rest) DocEmpty bs ------------------------------------------------------------------------------- -- Doc options @@ -339,17 +352,18 @@ mkDocOpts mbOpts flags mdl = do mdlStr = moduleString mdl -- Later flags override earlier ones - go os m | m == Flag_HideModule mdlStr = OptHide : os - | m == Flag_ShowModule mdlStr = filter (/= OptHide) os - | m == Flag_ShowAllModules = filter (/= OptHide) os - | m == Flag_ShowExtensions mdlStr = OptShowExtensions : os - | otherwise = os + go os m + | m == Flag_HideModule mdlStr = OptHide : os + | m == Flag_ShowModule mdlStr = filter (/= OptHide) os + | m == Flag_ShowAllModules = filter (/= OptHide) os + | m == Flag_ShowExtensions mdlStr = OptShowExtensions : os + | otherwise = os parseOption :: MonadIO m => String -> IfM m (Maybe DocOption) -parseOption "hide" = return (Just OptHide) -parseOption "prune" = return (Just OptPrune) -parseOption "not-home" = return (Just OptNotHome) -parseOption "show-extensions" = return (Just OptShowExtensions) +parseOption "hide" = return (Just OptHide) +parseOption "prune" = return (Just OptPrune) +parseOption "not-home" = return (Just OptNotHome) +parseOption "show-extensions" = return (Just OptShowExtensions) parseOption "print-explicit-runtime-reps" = return (Just OptPrintRuntimeRep) parseOption other = warn ("Unrecognised option: " ++ other) >> return Nothing @@ -360,11 +374,10 @@ parseOption other = warn ("Unrecognised option: " ++ other) >> return Nothing -- | Extract a map of fixity declarations only mkFixMap :: [Name] -> [(OccName, Fixity)] -> FixMap mkFixMap exps occFixs = - Map.fromList $ flip mapMaybe occFixs $ \(occ, fix_) -> - (,fix_) <$> lookupOccEnv expsOccEnv occ - where - expsOccEnv = mkOccEnv (map (nameOccName &&& id) exps) - + Map.fromList $ flip mapMaybe occFixs $ \(occ, fix_) -> + (,fix_) <$> lookupOccEnv expsOccEnv occ + where + expsOccEnv = mkOccEnv (map (nameOccName &&& id) exps) -- | Build the list of items that will become the documentation, from the -- export list. At this point, the list of ExportItems is in terms of @@ -376,8 +389,8 @@ mkExportItems :: MonadIO m => PrintRuntimeReps -> IfaceMap - -> Maybe Package -- this package - -> Module -- this module + -> Maybe Package -- this package + -> Module -- this module -> WarningMap -> Map Name MetaSince -> DocMap Name @@ -390,74 +403,103 @@ mkExportItems -> OccEnv Name -> IfM m [ExportItem GhcRn] mkExportItems - prr modMap pkgName thisMod warnings exportSinceMap - docMap argMap fixMap namedChunks dsItems - instIfaceMap dflags defMeths = + prr + modMap + pkgName + thisMod + warnings + exportSinceMap + docMap + argMap + fixMap + namedChunks + dsItems + instIfaceMap + dflags + defMeths = concat <$> traverse lookupExport dsItems - where - lookupExport :: MonadIO m => DocStructureItem -> IfM m [ExportItem GhcRn] - lookupExport = \case - DsiSectionHeading lev hsDoc' -> do - doc <- processDocString dflags hsDoc' - pure [ExportGroup lev "" doc] - DsiDocChunk hsDoc' -> do - doc <- processDocStringParas dflags pkgName hsDoc' - pure [ExportDoc doc] - DsiNamedChunkRef ref -> do - case Map.lookup ref namedChunks of - Nothing -> do - warn $ "Cannot find documentation for: $" ++ ref - pure [] - Just hsDoc' -> do - doc <- processDocStringParas dflags pkgName hsDoc' - pure [ExportDoc doc] - DsiExports avails -> - -- TODO: We probably don't need nubAvails here. - -- mkDocStructureFromExportList already uses it. - concat <$> traverse availExport (nubAvails avails) - DsiModExport mod_names avails -> do - -- only consider exporting a module if we are sure we are really - -- exporting the whole module and not some subset. - (unrestricted_mods, remaining_avails) <- unrestrictedModExports dflags thisMod modMap instIfaceMap avails (NE.toList mod_names) - avail_exps <- concat <$> traverse availExport remaining_avails - pure (map ExportModule unrestricted_mods ++ avail_exps) - - availExport :: MonadIO m => AvailInfo -> IfM m [ExportItem GhcRn] - availExport avail = - availExportItem prr modMap thisMod warnings exportSinceMap - docMap argMap fixMap instIfaceMap dflags avail defMeths + where + lookupExport :: MonadIO m => DocStructureItem -> IfM m [ExportItem GhcRn] + lookupExport = \case + DsiSectionHeading lev hsDoc' -> do + doc <- processDocString dflags hsDoc' + pure [ExportGroup lev "" doc] + DsiDocChunk hsDoc' -> do + doc <- processDocStringParas dflags pkgName hsDoc' + pure [ExportDoc doc] + DsiNamedChunkRef ref -> do + case Map.lookup ref namedChunks of + Nothing -> do + warn $ "Cannot find documentation for: $" ++ ref + pure [] + Just hsDoc' -> do + doc <- processDocStringParas dflags pkgName hsDoc' + pure [ExportDoc doc] + DsiExports avails -> + -- TODO: We probably don't need nubAvails here. + -- mkDocStructureFromExportList already uses it. + concat <$> traverse availExport (nubAvails avails) + DsiModExport mod_names avails -> do + -- only consider exporting a module if we are sure we are really + -- exporting the whole module and not some subset. + (unrestricted_mods, remaining_avails) <- unrestrictedModExports dflags thisMod modMap instIfaceMap avails (NE.toList mod_names) + avail_exps <- concat <$> traverse availExport remaining_avails + pure (map ExportModule unrestricted_mods ++ avail_exps) + + availExport :: MonadIO m => AvailInfo -> IfM m [ExportItem GhcRn] + availExport avail = + availExportItem + prr + modMap + thisMod + warnings + exportSinceMap + docMap + argMap + fixMap + instIfaceMap + dflags + avail + defMeths unrestrictedModExports :: MonadIO m => DynFlags - -> Module -- ^ Current Module - -> IfaceMap -- ^ Already created interfaces - -> InstIfaceMap -- ^ Interfaces in other packages + -> Module + -- ^ Current Module + -> IfaceMap + -- ^ Already created interfaces + -> InstIfaceMap + -- ^ Interfaces in other packages -> Avails - -> [ModuleName] -- ^ Modules to be exported + -> [ModuleName] + -- ^ Modules to be exported -> IfM m ([Module], Avails) - -- ^ ( modules exported without restriction - -- , remaining exports not included in any - -- of these modules - -- ) + -- ^ ( modules exported without restriction + -- , remaining exports not included in any + -- of these modules + -- ) unrestrictedModExports dflags thisMod ifaceMap instIfaceMap avails mod_names = do - mods_and_exports <- fmap catMaybes $ for mod_names $ \mod_name -> do - let m_local = mkModule (moduleUnit thisMod) mod_name - case Map.lookup m_local ifaceMap of - -- First lookup locally - Just iface -> pure $ Just (ifaceMod iface, mkNameSet (ifaceExports iface)) - Nothing -> - case Map.lookup mod_name instIfaceMap' of - Just iface -> pure $ Just (instMod iface, mkNameSet (instExports iface)) - Nothing -> do - warn $ - "Warning: " ++ pretty dflags thisMod ++ ": Could not find " ++ - "documentation for exported module: " ++ pretty dflags mod_name - pure Nothing - let unrestricted = filter everythingVisible mods_and_exports - mod_exps = unionNameSets (map snd unrestricted) - remaining = nubAvails (filterAvails (\n -> not (n `elemNameSet` mod_exps)) avails) - pure (map fst unrestricted, remaining) + mods_and_exports <- fmap catMaybes $ for mod_names $ \mod_name -> do + let m_local = mkModule (moduleUnit thisMod) mod_name + case Map.lookup m_local ifaceMap of + -- First lookup locally + Just iface -> pure $ Just (ifaceMod iface, mkNameSet (ifaceExports iface)) + Nothing -> + case Map.lookup mod_name instIfaceMap' of + Just iface -> pure $ Just (instMod iface, mkNameSet (instExports iface)) + Nothing -> do + warn $ + "Warning: " + ++ pretty dflags thisMod + ++ ": Could not find " + ++ "documentation for exported module: " + ++ pretty dflags mod_name + pure Nothing + let unrestricted = filter everythingVisible mods_and_exports + mod_exps = unionNameSets (map snd unrestricted) + remaining = nubAvails (filterAvails (\n -> not (n `elemNameSet` mod_exps)) avails) + pure (map fst unrestricted, remaining) where instIfaceMap' = Map.mapKeys moduleName instIfaceMap all_names = availsToNameSet avails @@ -475,144 +517,166 @@ unrestrictedModExports dflags thisMod ifaceMap instIfaceMap avails mod_names = d isSubsetOf a b = nameSetAll (`elemNameSet` b) a availExportItem - :: forall m. MonadIO m + :: forall m + . MonadIO m => PrintRuntimeReps -> IfaceMap - -> Module -- this module + -> Module -- this module -> WarningMap - -> Map Name MetaSince -- ^ export \@since declarations - -> Map Name (MDoc Name) -- docs (keyed by 'Name's) - -> ArgMap Name -- docs for arguments (keyed by 'Name's) + -> Map Name MetaSince + -- ^ export \@since declarations + -> Map Name (MDoc Name) -- docs (keyed by 'Name's) + -> ArgMap Name -- docs for arguments (keyed by 'Name's) -> FixMap -> InstIfaceMap -> DynFlags -> AvailInfo - -> OccEnv Name -- Default methods + -> OccEnv Name -- Default methods -> IfM m [ExportItem GhcRn] availExportItem - prr modMap thisMod warnings exportSinceMap docMap argMap fixMap instIfaceMap dflags - availInfo defMeths - = + prr + modMap + thisMod + warnings + exportSinceMap + docMap + argMap + fixMap + instIfaceMap + dflags + availInfo + defMeths = declWith availInfo - where - declWith :: AvailInfo -> IfM m [ ExportItem GhcRn ] - declWith avail = do - let t = availName avail - mayDecl <- hiDecl dflags prr t - case mayDecl of - Nothing -> return [ ExportNoDecl t [] ] - Just decl -> do - availExportDecl avail decl =<< do - -- Find docs for decl - let tmod = nameModule t - if tmod == thisMod - then pure (lookupDocs avail warnings docMap argMap defMeths) - else case Map.lookup tmod modMap of - Just iface -> - pure - $ first (applyExportSince exportSinceMap t) - $ lookupDocs avail warnings (ifaceDocMap iface) (ifaceArgMap iface) (mkOccEnv (ifaceDefMeths iface)) - Nothing -> - -- We try to get the subs and docs - -- from the installed .haddock file for that package. - -- TODO: This needs to be more sophisticated to deal - -- with signature inheritance - case Map.lookup (nameModule t) instIfaceMap of - Nothing -> do - warn $ - "Warning: " ++ pretty dflags thisMod ++ - ": Couldn't find .haddock for export " ++ pretty dflags t - let subs_ = availNoDocs avail - pure (noDocForDecl, subs_) - Just instIface -> - pure - $ first (applyExportSince exportSinceMap t) - $ lookupDocs avail warnings (instDocMap instIface) (instArgMap instIface) (mkOccEnv (instDefMeths instIface)) - - -- Tries 'extractDecl' first then falls back to 'hiDecl' if that fails - availDecl :: Name -> LHsDecl GhcRn -> IfM m (LHsDecl GhcRn) - availDecl declName parentDecl = extractDecl prr dflags declName parentDecl >>= \case - Right d -> pure d - Left err -> do - synifiedDeclOpt <- hiDecl dflags prr declName - case synifiedDeclOpt of - Just synifiedDecl -> pure synifiedDecl - Nothing -> pprPanic "availExportItem" (O.text err) - - availExportDecl :: AvailInfo -> LHsDecl GhcRn - -> (DocForDecl Name, [(Name, DocForDecl Name)]) - -> IfM m [ ExportItem GhcRn ] - availExportDecl avail decl (doc, subs) - | availExportsDecl avail = do - extractedDecl <- availDecl (availName avail) decl - - -- bundled pattern synonyms only make sense if the declaration is - -- exported (otherwise there would be nothing to bundle to) - bundledPatSyns <- findBundledPatterns avail - - let - !patSynNames = force $ - concatMap (getMainDeclBinder emptyOccEnv . fst) bundledPatSyns - - !doc' = force doc - !subs' = force subs - - !restrictToNames = force $ fmap fst subs' - - !fixities = force - [ (n, f) - | n <- availName avail : fmap fst subs' ++ patSynNames - , Just f <- [Map.lookup n fixMap] + where + declWith :: AvailInfo -> IfM m [ExportItem GhcRn] + declWith avail = do + let t = availName avail + mayDecl <- hiDecl dflags prr t + case mayDecl of + Nothing -> return [ExportNoDecl t []] + Just decl -> do + availExportDecl avail decl =<< do + -- Find docs for decl + let tmod = nameModule t + if tmod == thisMod + then pure (lookupDocs avail warnings docMap argMap defMeths) + else case Map.lookup tmod modMap of + Just iface -> + pure $ + first (applyExportSince exportSinceMap t) $ + lookupDocs avail warnings (ifaceDocMap iface) (ifaceArgMap iface) (mkOccEnv (ifaceDefMeths iface)) + Nothing -> + -- We try to get the subs and docs + -- from the installed .haddock file for that package. + -- TODO: This needs to be more sophisticated to deal + -- with signature inheritance + case Map.lookup (nameModule t) instIfaceMap of + Nothing -> do + warn $ + "Warning: " + ++ pretty dflags thisMod + ++ ": Couldn't find .haddock for export " + ++ pretty dflags t + let subs_ = availNoDocs avail + pure (noDocForDecl, subs_) + Just instIface -> + pure $ + first (applyExportSince exportSinceMap t) $ + lookupDocs avail warnings (instDocMap instIface) (instArgMap instIface) (mkOccEnv (instDefMeths instIface)) + + -- Tries 'extractDecl' first then falls back to 'hiDecl' if that fails + availDecl :: Name -> LHsDecl GhcRn -> IfM m (LHsDecl GhcRn) + availDecl declName parentDecl = + extractDecl prr dflags declName parentDecl >>= \case + Right d -> pure d + Left err -> do + synifiedDeclOpt <- hiDecl dflags prr declName + case synifiedDeclOpt of + Just synifiedDecl -> pure synifiedDecl + Nothing -> pprPanic "availExportItem" (O.text err) + + availExportDecl + :: AvailInfo + -> LHsDecl GhcRn + -> (DocForDecl Name, [(Name, DocForDecl Name)]) + -> IfM m [ExportItem GhcRn] + availExportDecl avail decl (doc, subs) + | availExportsDecl avail = do + extractedDecl <- availDecl (availName avail) decl + + -- bundled pattern synonyms only make sense if the declaration is + -- exported (otherwise there would be nothing to bundle to) + bundledPatSyns <- findBundledPatterns avail + + let + !patSynNames = + force $ + concatMap (getMainDeclBinder emptyOccEnv . fst) bundledPatSyns + + !doc' = force doc + !subs' = force subs + + !restrictToNames = force $ fmap fst subs' + + !fixities = + force + [ (n, f) + | n <- availName avail : fmap fst subs' ++ patSynNames + , Just f <- [Map.lookup n fixMap] + ] + + return + [ ExportDecl + ExportD + { expDDecl = restrictTo restrictToNames extractedDecl + , expDPats = bundledPatSyns + , expDMbDoc = doc' + , expDSubDocs = subs' + , expDInstances = [] + , expDFixities = fixities + , expDSpliced = False + } + ] + | otherwise = for subs $ \(sub, sub_doc) -> do + extractedDecl <- availDecl sub decl + + let + !fixities = force [(sub, f) | Just f <- [Map.lookup sub fixMap]] + !subDoc = force sub_doc + + return $ + ExportDecl + ExportD + { expDDecl = extractedDecl + , expDPats = [] + , expDMbDoc = subDoc + , expDSubDocs = [] + , expDInstances = [] + , expDFixities = fixities + , expDSpliced = False + } + + findBundledPatterns :: AvailInfo -> IfM m [(HsDecl GhcRn, DocForDecl Name)] + findBundledPatterns avail = do + patsyns <- for constructor_names $ \name -> do + mtyThing <- lookupName name + case mtyThing of + Just (AConLike PatSynCon{}) -> do + export_items <- declWith (Avail name) + pure + [ (unLoc patsyn_decl, patsyn_doc) + | ExportDecl + ExportD + { expDDecl = patsyn_decl + , expDMbDoc = patsyn_doc + } <- + export_items ] - - return - [ ExportDecl ExportD - { expDDecl = restrictTo restrictToNames extractedDecl - , expDPats = bundledPatSyns - , expDMbDoc = doc' - , expDSubDocs = subs' - , expDInstances = [] - , expDFixities = fixities - , expDSpliced = False - } - ] - - | otherwise = for subs $ \(sub, sub_doc) -> do - extractedDecl <- availDecl sub decl - - let - !fixities = force [ (sub, f) | Just f <- [Map.lookup sub fixMap] ] - !subDoc = force sub_doc - - return $ - ExportDecl ExportD - { expDDecl = extractedDecl - , expDPats = [] - , expDMbDoc = subDoc - , expDSubDocs = [] - , expDInstances = [] - , expDFixities = fixities - , expDSpliced = False - } - - findBundledPatterns :: AvailInfo -> IfM m [(HsDecl GhcRn, DocForDecl Name)] - findBundledPatterns avail = do - patsyns <- for constructor_names $ \name -> do - mtyThing <- lookupName name - case mtyThing of - Just (AConLike PatSynCon{}) -> do - export_items <- declWith (Avail name) - pure [ (unLoc patsyn_decl, patsyn_doc) - | ExportDecl ExportD - { expDDecl = patsyn_decl - , expDMbDoc = patsyn_doc - } <- export_items - ] - _ -> pure [] - pure (concat patsyns) - where - constructor_names = - filter isDataConName (availSubordinates avail) + _ -> pure [] + pure (concat patsyns) + where + constructor_names = + filter isDataConName (availSubordinates avail) availSubordinates :: AvailInfo -> [Name] availSubordinates = availSubordinateNames @@ -629,14 +693,13 @@ applyExportSince -> DocForDecl Name applyExportSince exportSinceMap nm (dd, argDoc) | Just since <- Map.lookup nm exportSinceMap = - let dd' = dd { documentationDoc = setMDocSince (documentationDoc dd) } - setMDocSince :: Maybe (MDoc name) -> Maybe (MDoc name) - setMDocSince (Just (MetaDoc meta doc)) = Just $ MetaDoc (meta {_metaSince = Just since}) doc - setMDocSince Nothing = Just $ MetaDoc (Meta {_metaSince = Just since}) DocEmpty - in (dd', argDoc) + let dd' = dd{documentationDoc = setMDocSince (documentationDoc dd)} + setMDocSince :: Maybe (MDoc name) -> Maybe (MDoc name) + setMDocSince (Just (MetaDoc meta doc)) = Just $ MetaDoc (meta{_metaSince = Just since}) doc + setMDocSince Nothing = Just $ MetaDoc (Meta{_metaSince = Just since}) DocEmpty + in (dd', argDoc) applyExportSince _ _ dd = dd - hiDecl :: MonadIO m => DynFlags @@ -652,11 +715,14 @@ hiDecl dflags prr t = do Just x -> case tyThingToLHsDecl prr x of Left m -> (warn $ bugWarn m) >> return Nothing Right (m, t') -> mapM (warn . bugWarn) m >> return (Just $ L (noAnnSrcSpan (nameSrcSpan t)) t') - where - warnLine x = O.text "haddock-bug:" O.<+> O.text x O.<> - O.comma O.<+> O.quotes (O.ppr t) O.<+> - O.text "-- Please report this on Haddock issue tracker!" - bugWarn = showSDoc dflags . warnLine + where + warnLine x = + O.text "haddock-bug:" + O.<+> O.text x + O.<> O.comma + O.<+> O.quotes (O.ppr t) + O.<+> O.text "-- Please report this on Haddock issue tracker!" + bugWarn = showSDoc dflags . warnLine -- | Lookup docs for a declaration from maps. lookupDocs @@ -666,27 +732,30 @@ lookupDocs -> ArgMap Name -> OccEnv Name -> (DocForDecl Name, [(Name, DocForDecl Name)]) - -- ^ documentation for declaration and its subordinates + -- ^ documentation for declaration and its subordinates lookupDocs avail warningMap docMap argMap def_meths_env = let n = availName avail lookupArgDoc x = Map.findWithDefault Map.empty x argMap doc = (lookupDoc n, lookupArgDoc n) subs = availSubordinates avail - def_meths = [ (meth, (lookupDoc meth, lookupArgDoc meth)) - | s <- subs - , let dmOcc = mkDefaultMethodOcc (nameOccName s) - , Just meth <- [lookupOccEnv def_meths_env dmOcc] - , availExportsDecl avail ] - subDocs = [ (s, (lookupDoc s, lookupArgDoc s)) - | s <- subs - ] ++ def_meths - in + def_meths = + [ (meth, (lookupDoc meth, lookupArgDoc meth)) + | s <- subs + , let dmOcc = mkDefaultMethodOcc (nameOccName s) + , Just meth <- [lookupOccEnv def_meths_env dmOcc] + , availExportsDecl avail + ] + subDocs = + [ (s, (lookupDoc s, lookupArgDoc s)) + | s <- subs + ] + ++ def_meths + in (doc, subDocs) where lookupDoc name = Documentation (Map.lookup name docMap) (Map.lookup name warningMap) - -- Note [1]: ------------ -- It is unnecessary to document a subordinate by itself at the top level if @@ -703,7 +772,6 @@ lookupDocs avail warningMap docMap argMap def_meths_env = -- -- (For more information, see Trac #69) - -- | Sometimes the declaration we want to export is not the "main" declaration: -- it might be an individual record selector or a class method. In these -- cases we have to extract the required declaration (and somehow cobble @@ -715,176 +783,224 @@ extractDecl :: MonadIO m => PrintRuntimeReps -> DynFlags - -> Name -- ^ name of the declaration to extract - -> LHsDecl GhcRn -- ^ parent declaration + -> Name + -- ^ name of the declaration to extract + -> LHsDecl GhcRn + -- ^ parent declaration -> IfM m (Either String (LHsDecl GhcRn)) extractDecl prr dflags name decl | name `elem` getMainDeclBinder emptyOccEnv (unLoc decl) = pure $ Right decl - | otherwise = - case unLoc decl of - TyClD _ d@ClassDecl { tcdLName = L _ clsNm - , tcdSigs = clsSigs - , tcdATs = clsATs } -> - let - matchesMethod = - [ lsig - | lsig <- clsSigs - , ClassOpSig _ False _ _ <- pure $ unLoc lsig - -- Note: exclude `default` declarations (see #505) - , name `elem` sigName lsig - ] - - matchesAssociatedType = - [ lfam_decl - | lfam_decl <- clsATs - , name == unLoc (fdLName (unLoc lfam_decl)) - ] - - -- TODO: document fixity - in case (matchesMethod, matchesAssociatedType) of - ([s0], _) -> let tyvar_names = tyClDeclTyVars d - L pos sig = addClassContext clsNm tyvar_names s0 - in pure (Right $ L pos (SigD noExtField sig)) - (_, [L pos fam_decl]) -> pure (Right $ L pos (TyClD noExtField (FamDecl noExtField fam_decl))) - - ([], []) -> do - famInstDeclOpt <- hiDecl dflags prr name - case famInstDeclOpt of - Nothing -> pure $ Left (concat [ "Ambiguous decl for ", getOccString name - , " in class ", getOccString clsNm ]) - Just famInstDecl -> extractDecl prr dflags name famInstDecl - _ -> pure $ Left (concat [ "Ambiguous decl for ", getOccString name - , " in class ", getOccString clsNm ]) - TyClD _ d@DataDecl { tcdLName = L _ dataNm - , tcdDataDefn = HsDataDefn { dd_cons = dataCons } } -> pure $ do - let ty_args = lHsQTyVarsToTypes (tyClDeclTyVars d) - lsig <- if isDataConName name - then extractPatternSyn name dataNm ty_args (toList dataCons) - else extractRecSel name dataNm ty_args (toList dataCons) - pure (SigD noExtField <$> lsig) - - TyClD _ FamDecl {} - | isValName name -> do - famInstOpt <- hiDecl dflags prr name - case famInstOpt of - Just famInst -> extractDecl prr dflags name famInst - Nothing -> pure $ Left ("extractDecl: Unhandled decl for " ++ getOccString name) - - InstD _ (DataFamInstD _ (DataFamInstDecl - (FamEqn { feqn_tycon = L _ n - , feqn_pats = tys - , feqn_rhs = defn }))) -> pure $ - if isDataConName name - then fmap (SigD noExtField) <$> extractPatternSyn name n tys (toList $ dd_cons defn) - else fmap (SigD noExtField) <$> extractRecSel name n tys (toList $ dd_cons defn) - InstD _ (ClsInstD _ ClsInstDecl { cid_datafam_insts = insts }) - | isDataConName name -> - let matches = [ d' | L _ d'@(DataFamInstDecl (FamEqn { feqn_rhs = dd })) <- insts - , name `elem` map unLoc (concatMap (toList . getConNames . unLoc) (dd_cons dd)) - ] - in case matches of - [d0] -> extractDecl prr dflags name (noLocA (InstD noExtField (DataFamInstD noExtField d0))) - _ -> pure $ Left "internal: extractDecl (ClsInstD)" - | otherwise -> - let matches = [ d' | L _ d'@(DataFamInstDecl d ) - <- insts - -- , L _ ConDecl { con_details = RecCon rec } <- toList $ dd_cons (feqn_rhs d) - , Just rec <- toList $ getRecConArgs_maybe . unLoc <$> dd_cons (feqn_rhs d) - , ConDeclField { cd_fld_names = ns } <- map unLoc (unLoc rec) - , L _ n <- ns - , foExt n == name + | otherwise = + case unLoc decl of + TyClD + _ + d@ClassDecl + { tcdLName = L _ clsNm + , tcdSigs = clsSigs + , tcdATs = clsATs + } -> + let + matchesMethod = + [ lsig + | lsig <- clsSigs + , ClassOpSig _ False _ _ <- pure $ unLoc lsig + , -- Note: exclude `default` declarations (see #505) + name `elem` sigName lsig + ] + + matchesAssociatedType = + [ lfam_decl + | lfam_decl <- clsATs + , name == unLoc (fdLName (unLoc lfam_decl)) + ] + in + -- TODO: document fixity + case (matchesMethod, matchesAssociatedType) of + ([s0], _) -> + let tyvar_names = tyClDeclTyVars d + L pos sig = addClassContext clsNm tyvar_names s0 + in pure (Right $ L pos (SigD noExtField sig)) + (_, [L pos fam_decl]) -> pure (Right $ L pos (TyClD noExtField (FamDecl noExtField fam_decl))) + ([], []) -> do + famInstDeclOpt <- hiDecl dflags prr name + case famInstDeclOpt of + Nothing -> + pure $ + Left + ( concat + [ "Ambiguous decl for " + , getOccString name + , " in class " + , getOccString clsNm + ] + ) + Just famInstDecl -> extractDecl prr dflags name famInstDecl + _ -> + pure $ + Left + ( concat + [ "Ambiguous decl for " + , getOccString name + , " in class " + , getOccString clsNm ] - in case matches of - [d0] -> extractDecl prr dflags name (noLocA . InstD noExtField $ DataFamInstD noExtField d0) - _ -> pure $ Left "internal: extractDecl (ClsInstD)" - _ -> pure $ Left ("extractDecl: Unhandled decl for " ++ getOccString name) - -extractPatternSyn :: Name - -> Name - -> [LHsTypeArg GhcRn] -> [LConDecl GhcRn] - -> Either String (LSig GhcRn) + ) + TyClD + _ + d@DataDecl + { tcdLName = L _ dataNm + , tcdDataDefn = HsDataDefn{dd_cons = dataCons} + } -> pure $ do + let ty_args = lHsQTyVarsToTypes (tyClDeclTyVars d) + lsig <- + if isDataConName name + then extractPatternSyn name dataNm ty_args (toList dataCons) + else extractRecSel name dataNm ty_args (toList dataCons) + pure (SigD noExtField <$> lsig) + TyClD _ FamDecl{} + | isValName name -> do + famInstOpt <- hiDecl dflags prr name + case famInstOpt of + Just famInst -> extractDecl prr dflags name famInst + Nothing -> pure $ Left ("extractDecl: Unhandled decl for " ++ getOccString name) + InstD + _ + ( DataFamInstD + _ + ( DataFamInstDecl + ( FamEqn + { feqn_tycon = L _ n + , feqn_pats = tys + , feqn_rhs = defn + } + ) + ) + ) -> + pure $ + if isDataConName name + then fmap (SigD noExtField) <$> extractPatternSyn name n tys (toList $ dd_cons defn) + else fmap (SigD noExtField) <$> extractRecSel name n tys (toList $ dd_cons defn) + InstD _ (ClsInstD _ ClsInstDecl{cid_datafam_insts = insts}) + | isDataConName name -> + let matches = + [ d' | L _ d'@(DataFamInstDecl (FamEqn{feqn_rhs = dd})) <- insts, name `elem` map unLoc (concatMap (toList . getConNames . unLoc) (dd_cons dd)) + ] + in case matches of + [d0] -> extractDecl prr dflags name (noLocA (InstD noExtField (DataFamInstD noExtField d0))) + _ -> pure $ Left "internal: extractDecl (ClsInstD)" + | otherwise -> + let matches = + [ d' + | L _ d'@(DataFamInstDecl d) <- + insts + , -- , L _ ConDecl { con_details = RecCon rec } <- toList $ dd_cons (feqn_rhs d) + Just rec <- toList $ getRecConArgs_maybe . unLoc <$> dd_cons (feqn_rhs d) + , ConDeclField{cd_fld_names = ns} <- map unLoc (unLoc rec) + , L _ n <- ns + , foExt n == name + ] + in case matches of + [d0] -> extractDecl prr dflags name (noLocA . InstD noExtField $ DataFamInstD noExtField d0) + _ -> pure $ Left "internal: extractDecl (ClsInstD)" + _ -> pure $ Left ("extractDecl: Unhandled decl for " ++ getOccString name) + +extractPatternSyn + :: Name + -> Name + -> [LHsTypeArg GhcRn] + -> [LConDecl GhcRn] + -> Either String (LSig GhcRn) extractPatternSyn nm t tvs cons = case filter matches cons of - [] -> Left . O.showSDocOneLine O.defaultSDocContext $ - O.text "constructor pattern " O.<+> O.ppr nm O.<+> O.text "not found in type" O.<+> O.ppr t - con:_ -> pure (extract <$> con) - where - matches :: LConDecl GhcRn -> Bool - matches (L _ con) = nm `elem` (unLoc <$> getConNames con) - extract :: ConDecl GhcRn -> Sig GhcRn - extract con = - let args = - case con of - ConDeclH98 { con_args = con_args' } -> case con_args' of - PrefixCon _ args' -> map hsScaledThing args' - RecCon (L _ fields) -> cd_fld_type . unLoc <$> fields - InfixCon arg1 arg2 -> map hsScaledThing [arg1, arg2] - ConDeclGADT { con_g_args = con_args' } -> case con_args' of - PrefixConGADT _ args' -> map hsScaledThing args' - RecConGADT _ (L _ fields) -> cd_fld_type . unLoc <$> fields - typ = longArrow args (data_ty con) - typ' = - case con of - ConDeclH98 { con_mb_cxt = Just cxt } -> noLocA (HsQualTy noExtField cxt typ) - _ -> typ - typ'' = noLocA (HsQualTy noExtField (noLocA []) typ') - in PatSynSig noAnn [noLocA nm] (mkEmptySigType typ'') - - longArrow :: [LHsType GhcRn] -> LHsType GhcRn -> LHsType GhcRn - longArrow inputs output = foldr (\x y -> noLocA (HsFunTy noExtField (HsUnrestrictedArrow noExtField) x y)) output inputs - - data_ty con - | ConDeclGADT{} <- con = con_res_ty con - | otherwise = foldl' (\x y -> noLocA (mkAppTyArg x y)) (noLocA (HsTyVar noAnn NotPromoted (noLocA t))) tvs - where mkAppTyArg :: LHsType GhcRn -> LHsTypeArg GhcRn -> HsType GhcRn - mkAppTyArg f (HsValArg _ ty) = HsAppTy noExtField f ty - mkAppTyArg f (HsTypeArg _ ki) = HsAppKindTy noExtField f ki - mkAppTyArg f (HsArgPar _) = HsParTy noAnn f - -extractRecSel :: Name -> Name -> [LHsTypeArg GhcRn] -> [LConDecl GhcRn] - -> Either String (LSig GhcRn) -extractRecSel _ _ _ [] = Left "extractRecSel: selector not found" + [] -> + Left . O.showSDocOneLine O.defaultSDocContext $ + O.text "constructor pattern " O.<+> O.ppr nm O.<+> O.text "not found in type" O.<+> O.ppr t + con : _ -> pure (extract <$> con) + where + matches :: LConDecl GhcRn -> Bool + matches (L _ con) = nm `elem` (unLoc <$> getConNames con) + extract :: ConDecl GhcRn -> Sig GhcRn + extract con = + let args = + case con of + ConDeclH98{con_args = con_args'} -> case con_args' of + PrefixCon _ args' -> map hsScaledThing args' + RecCon (L _ fields) -> cd_fld_type . unLoc <$> fields + InfixCon arg1 arg2 -> map hsScaledThing [arg1, arg2] + ConDeclGADT{con_g_args = con_args'} -> case con_args' of + PrefixConGADT _ args' -> map hsScaledThing args' + RecConGADT _ (L _ fields) -> cd_fld_type . unLoc <$> fields + typ = longArrow args (data_ty con) + typ' = + case con of + ConDeclH98{con_mb_cxt = Just cxt} -> noLocA (HsQualTy noExtField cxt typ) + _ -> typ + typ'' = noLocA (HsQualTy noExtField (noLocA []) typ') + in PatSynSig noAnn [noLocA nm] (mkEmptySigType typ'') + + longArrow :: [LHsType GhcRn] -> LHsType GhcRn -> LHsType GhcRn + longArrow inputs output = foldr (\x y -> noLocA (HsFunTy noExtField (HsUnrestrictedArrow noExtField) x y)) output inputs + + data_ty con + | ConDeclGADT{} <- con = con_res_ty con + | otherwise = foldl' (\x y -> noLocA (mkAppTyArg x y)) (noLocA (HsTyVar noAnn NotPromoted (noLocA t))) tvs + where + mkAppTyArg :: LHsType GhcRn -> LHsTypeArg GhcRn -> HsType GhcRn + mkAppTyArg f (HsValArg _ ty) = HsAppTy noExtField f ty + mkAppTyArg f (HsTypeArg _ ki) = HsAppKindTy noExtField f ki + mkAppTyArg f (HsArgPar _) = HsParTy noAnn f +extractRecSel + :: Name + -> Name + -> [LHsTypeArg GhcRn] + -> [LConDecl GhcRn] + -> Either String (LSig GhcRn) +extractRecSel _ _ _ [] = Left "extractRecSel: selector not found" extractRecSel nm t tvs (L _ con : rest) = case getRecConArgs_maybe con of - Just (L _ fields) | ((l,L _ (ConDeclField _ _nn ty _)) : _) <- matching_fields fields -> - pure (L (noAnnSrcSpan l) (TypeSig noAnn [noLocA nm] (mkEmptyWildCardBndrs $ mkEmptySigType (noLocA (HsFunTy noExtField (HsUnrestrictedArrow noExtField) data_ty (getBangType ty)))))) + Just (L _ fields) + | ((l, L _ (ConDeclField _ _nn ty _)) : _) <- matching_fields fields -> + pure (L (noAnnSrcSpan l) (TypeSig noAnn [noLocA nm] (mkEmptyWildCardBndrs $ mkEmptySigType (noLocA (HsFunTy noExtField (HsUnrestrictedArrow noExtField) data_ty (getBangType ty)))))) _ -> extractRecSel nm t tvs rest - where - matching_fields :: [LConDeclField GhcRn] -> [(SrcSpan, LConDeclField GhcRn)] - matching_fields flds = [ (locA l,f) | f@(L _ (ConDeclField _ ns _ _)) <- flds - , L l n <- ns, foExt n == nm ] - data_ty - -- ResTyGADT _ ty <- con_res con = ty - | ConDeclGADT{} <- con = con_res_ty con - | otherwise = foldl' (\x y -> noLocA (mkAppTyArg x y)) (noLocA (HsTyVar noAnn NotPromoted (noLocA t))) tvs - where mkAppTyArg :: LHsType GhcRn -> LHsTypeArg GhcRn -> HsType GhcRn - mkAppTyArg f (HsValArg _ ty) = HsAppTy noExtField f ty - mkAppTyArg f (HsTypeArg _ ki) = HsAppKindTy noExtField f ki - mkAppTyArg f (HsArgPar _) = HsParTy noAnn f + where + matching_fields :: [LConDeclField GhcRn] -> [(SrcSpan, LConDeclField GhcRn)] + matching_fields flds = + [ (locA l, f) | f@(L _ (ConDeclField _ ns _ _)) <- flds, L l n <- ns, foExt n == nm + ] + data_ty + -- ResTyGADT _ ty <- con_res con = ty + | ConDeclGADT{} <- con = con_res_ty con + | otherwise = foldl' (\x y -> noLocA (mkAppTyArg x y)) (noLocA (HsTyVar noAnn NotPromoted (noLocA t))) tvs + where + mkAppTyArg :: LHsType GhcRn -> LHsTypeArg GhcRn -> HsType GhcRn + mkAppTyArg f (HsValArg _ ty) = HsAppTy noExtField f ty + mkAppTyArg f (HsTypeArg _ ki) = HsAppKindTy noExtField f ki + mkAppTyArg f (HsArgPar _) = HsParTy noAnn f -- | Keep export items with docs. pruneExportItems :: [ExportItem GhcRn] -> [ExportItem GhcRn] pruneExportItems = filter hasDoc where - hasDoc (ExportDecl ExportD {expDMbDoc = (Documentation d _, _)}) = isJust d + hasDoc (ExportDecl ExportD{expDMbDoc = (Documentation d _, _)}) = isJust d hasDoc _ = True - mkVisibleNames :: InstMap -> [ExportItem GhcRn] -> [DocOption] -> [Name] mkVisibleNames instMap exports opts | OptHide `elem` opts = [] - | otherwise = let ns = concatMap exportName exports - in seqList ns `seq` ns + | otherwise = + let ns = concatMap exportName exports + in seqList ns `seq` ns where exportName (ExportDecl e@ExportD{}) = name ++ subs ++ patsyns - where subs = map fst (expDSubDocs e) - patsyns = concatMap (getMainDeclBinder emptyOccEnv . fst) (expDPats e) - name = case unLoc $ expDDecl e of - InstD _ d -> maybeToList $ SrcLoc.lookupSrcSpan (getInstLoc d) instMap - decl -> getMainDeclBinder emptyOccEnv decl - exportName ExportNoDecl {} = [] -- we don't count these as visible, since - -- we don't want links to go to them. + where + subs = map fst (expDSubDocs e) + patsyns = concatMap (getMainDeclBinder emptyOccEnv . fst) (expDPats e) + name = case unLoc $ expDDecl e of + InstD _ d -> maybeToList $ SrcLoc.lookupSrcSpan (getInstLoc d) instMap + decl -> getMainDeclBinder emptyOccEnv decl + exportName ExportNoDecl{} = [] -- we don't count these as visible, since + -- we don't want links to go to them. exportName _ = [] seqList :: [a] -> () diff --git a/haddock-api/src/Haddock/Interface/Json.hs b/haddock-api/src/Haddock/Interface/Json.hs index c4cd3b3981..b9abcf9c29 100644 --- a/haddock-api/src/Haddock/Interface/Json.hs +++ b/haddock-api/src/Haddock/Interface/Json.hs @@ -1,64 +1,68 @@ {-# LANGUAGE RecordWildCards #-} -module Haddock.Interface.Json ( - jsonInstalledInterface + +module Haddock.Interface.Json + ( jsonInstalledInterface , jsonInterfaceFile , renderJson ) where import GHC.Types.Fixity -import GHC.Utils.Json -import GHC.Unit.Module import GHC.Types.Name +import GHC.Unit.Module +import GHC.Utils.Json import GHC.Utils.Outputable import Control.Arrow import Data.Map (Map) import qualified Data.Map as Map -import Haddock.Types import Haddock.InterfaceFile +import Haddock.Types jsonInterfaceFile :: InterfaceFile -> JsonDoc jsonInterfaceFile InterfaceFile{..} = - jsonObject [ ("link_env" , jsonMap nameStableString (jsonString . moduleNameString . moduleName) ifLinkEnv) - , ("inst_ifaces", jsonArray (map jsonInstalledInterface ifInstalledIfaces)) - ] + jsonObject + [ ("link_env", jsonMap nameStableString (jsonString . moduleNameString . moduleName) ifLinkEnv) + , ("inst_ifaces", jsonArray (map jsonInstalledInterface ifInstalledIfaces)) + ] jsonInstalledInterface :: InstalledInterface -> JsonDoc jsonInstalledInterface InstalledInterface{..} = jsonObject properties where properties = - [ ("module" , jsonModule instMod) - , ("is_sig" , jsonBool instIsSig) - , ("info" , jsonHaddockModInfo instInfo) - , ("doc_map" , jsonMap nameStableString jsonMDoc instDocMap) - , ("arg_map" , jsonMap nameStableString (jsonMap show jsonMDoc) instArgMap) - , ("exports" , jsonArray (map jsonName instExports)) - , ("visible_exports" , jsonArray (map jsonName instVisibleExports)) - , ("options" , jsonArray (map (jsonString . show) instOptions)) - , ("fix_map" , jsonMap nameStableString jsonFixity instFixMap) + [ ("module", jsonModule instMod) + , ("is_sig", jsonBool instIsSig) + , ("info", jsonHaddockModInfo instInfo) + , ("doc_map", jsonMap nameStableString jsonMDoc instDocMap) + , ("arg_map", jsonMap nameStableString (jsonMap show jsonMDoc) instArgMap) + , ("exports", jsonArray (map jsonName instExports)) + , ("visible_exports", jsonArray (map jsonName instVisibleExports)) + , ("options", jsonArray (map (jsonString . show) instOptions)) + , ("fix_map", jsonMap nameStableString jsonFixity instFixMap) ] jsonHaddockModInfo :: HaddockModInfo Name -> JsonDoc jsonHaddockModInfo HaddockModInfo{..} = - jsonObject [ ("description" , jsonMaybe jsonDoc hmi_description) - , ("copyright" , jsonMaybe jsonString hmi_copyright) - , ("maintainer" , jsonMaybe jsonString hmi_maintainer) - , ("stability" , jsonMaybe jsonString hmi_stability) - , ("protability" , jsonMaybe jsonString hmi_portability) - , ("safety" , jsonMaybe jsonString hmi_safety) - , ("language" , jsonMaybe (jsonString . show) hmi_language) - , ("extensions" , jsonArray (map (jsonString . show) hmi_extensions)) - ] + jsonObject + [ ("description", jsonMaybe jsonDoc hmi_description) + , ("copyright", jsonMaybe jsonString hmi_copyright) + , ("maintainer", jsonMaybe jsonString hmi_maintainer) + , ("stability", jsonMaybe jsonString hmi_stability) + , ("protability", jsonMaybe jsonString hmi_portability) + , ("safety", jsonMaybe jsonString hmi_safety) + , ("language", jsonMaybe (jsonString . show) hmi_language) + , ("extensions", jsonArray (map (jsonString . show) hmi_extensions)) + ] jsonMap :: (a -> String) -> (b -> JsonDoc) -> Map a b -> JsonDoc jsonMap f g = jsonObject . map (f *** g) . Map.toList jsonMDoc :: MDoc Name -> JsonDoc jsonMDoc MetaDoc{..} = - jsonObject [ ("meta", jsonObject [("version", jsonMaybe (jsonString . show . sinceVersion) (_metaSince _meta))]) - , ("document", jsonDoc _doc) - ] + jsonObject + [ ("meta", jsonObject [("version", jsonMaybe (jsonString . show . sinceVersion) (_metaSince _meta))]) + , ("document", jsonDoc _doc) + ] showModName :: Wrap (ModuleName, OccName) -> String showModName = showWrapped (moduleNameString . fst) @@ -66,166 +70,170 @@ showModName = showWrapped (moduleNameString . fst) showName :: Wrap Name -> String showName = showWrapped nameStableString - jsonDoc :: Doc Name -> JsonDoc - -jsonDoc DocEmpty = jsonObject - [ ("tag", jsonString "DocEmpty") ] - -jsonDoc (DocAppend x y) = jsonObject +jsonDoc DocEmpty = + jsonObject + [("tag", jsonString "DocEmpty")] +jsonDoc (DocAppend x y) = + jsonObject [ ("tag", jsonString "DocAppend") , ("first", jsonDoc x) , ("second", jsonDoc y) ] - -jsonDoc (DocString s) = jsonObject +jsonDoc (DocString s) = + jsonObject [ ("tag", jsonString "DocString") , ("string", jsonString s) ] - -jsonDoc (DocParagraph x) = jsonObject +jsonDoc (DocParagraph x) = + jsonObject [ ("tag", jsonString "DocParagraph") , ("document", jsonDoc x) ] - -jsonDoc (DocIdentifier name) = jsonObject +jsonDoc (DocIdentifier name) = + jsonObject [ ("tag", jsonString "DocIdentifier") , ("name", jsonString (showName name)) ] - -jsonDoc (DocIdentifierUnchecked modName) = jsonObject +jsonDoc (DocIdentifierUnchecked modName) = + jsonObject [ ("tag", jsonString "DocIdentifierUnchecked") , ("modName", jsonString (showModName modName)) ] - -jsonDoc (DocModule (ModLink m _l)) = jsonObject +jsonDoc (DocModule (ModLink m _l)) = + jsonObject [ ("tag", jsonString "DocModule") , ("string", jsonString m) ] - -jsonDoc (DocWarning x) = jsonObject +jsonDoc (DocWarning x) = + jsonObject [ ("tag", jsonString "DocWarning") , ("document", jsonDoc x) ] - -jsonDoc (DocEmphasis x) = jsonObject +jsonDoc (DocEmphasis x) = + jsonObject [ ("tag", jsonString "DocEmphasis") , ("document", jsonDoc x) ] - -jsonDoc (DocMonospaced x) = jsonObject +jsonDoc (DocMonospaced x) = + jsonObject [ ("tag", jsonString "DocMonospaced") , ("document", jsonDoc x) ] - -jsonDoc (DocBold x) = jsonObject +jsonDoc (DocBold x) = + jsonObject [ ("tag", jsonString "DocBold") , ("document", jsonDoc x) ] - -jsonDoc (DocUnorderedList xs) = jsonObject +jsonDoc (DocUnorderedList xs) = + jsonObject [ ("tag", jsonString "DocUnorderedList") , ("documents", jsonArray (fmap jsonDoc xs)) ] - -jsonDoc (DocOrderedList xs) = jsonObject +jsonDoc (DocOrderedList xs) = + jsonObject [ ("tag", jsonString "DocOrderedList") , ("items", jsonArray (fmap jsonItem xs)) ] where jsonItem (index, a) = jsonObject [("document", jsonDoc a), ("seq", jsonInt index)] - -jsonDoc (DocDefList xys) = jsonObject +jsonDoc (DocDefList xys) = + jsonObject [ ("tag", jsonString "DocDefList") , ("definitions", jsonArray (fmap jsonDef xys)) ] where jsonDef (x, y) = jsonObject [("document", jsonDoc x), ("y", jsonDoc y)] - -jsonDoc (DocCodeBlock x) = jsonObject +jsonDoc (DocCodeBlock x) = + jsonObject [ ("tag", jsonString "DocCodeBlock") , ("document", jsonDoc x) ] - -jsonDoc (DocHyperlink hyperlink) = jsonObject +jsonDoc (DocHyperlink hyperlink) = + jsonObject [ ("tag", jsonString "DocHyperlink") , ("hyperlink", jsonHyperlink hyperlink) ] where - jsonHyperlink Hyperlink{..} = jsonObject + jsonHyperlink Hyperlink{..} = + jsonObject [ ("hyperlinkUrl", jsonString hyperlinkUrl) , ("hyperlinkLabel", jsonMaybe jsonDoc hyperlinkLabel) ] - -jsonDoc (DocPic picture) = jsonObject +jsonDoc (DocPic picture) = + jsonObject [ ("tag", jsonString "DocPic") , ("picture", jsonPicture picture) ] where - jsonPicture Picture{..} = jsonObject + jsonPicture Picture{..} = + jsonObject [ ("pictureUrl", jsonString pictureUri) , ("pictureLabel", jsonMaybe jsonString pictureTitle) ] - -jsonDoc (DocMathInline s) = jsonObject +jsonDoc (DocMathInline s) = + jsonObject [ ("tag", jsonString "DocMathInline") , ("string", jsonString s) ] - -jsonDoc (DocMathDisplay s) = jsonObject +jsonDoc (DocMathDisplay s) = + jsonObject [ ("tag", jsonString "DocMathDisplay") , ("string", jsonString s) ] - -jsonDoc (DocAName s) = jsonObject +jsonDoc (DocAName s) = + jsonObject [ ("tag", jsonString "DocAName") , ("string", jsonString s) ] - -jsonDoc (DocProperty s) = jsonObject +jsonDoc (DocProperty s) = + jsonObject [ ("tag", jsonString "DocProperty") , ("string", jsonString s) ] - -jsonDoc (DocExamples examples) = jsonObject +jsonDoc (DocExamples examples) = + jsonObject [ ("tag", jsonString "DocExamples") , ("examples", jsonArray (fmap jsonExample examples)) ] where - jsonExample Example{..} = jsonObject + jsonExample Example{..} = + jsonObject [ ("exampleExpression", jsonString exampleExpression) , ("exampleResult", jsonArray (fmap jsonString exampleResult)) ] - -jsonDoc (DocHeader header) = jsonObject +jsonDoc (DocHeader header) = + jsonObject [ ("tag", jsonString "DocHeader") , ("header", jsonHeader header) ] where - jsonHeader Header{..} = jsonObject + jsonHeader Header{..} = + jsonObject [ ("headerLevel", jsonInt headerLevel) , ("headerTitle", jsonDoc headerTitle) ] - -jsonDoc (DocTable table) = jsonObject +jsonDoc (DocTable table) = + jsonObject [ ("tag", jsonString "DocTable") , ("table", jsonTable table) ] where - jsonTable Table{..} = jsonObject + jsonTable Table{..} = + jsonObject [ ("tableHeaderRows", jsonArray (fmap jsonTableRow tableHeaderRows)) , ("tableBodyRows", jsonArray (fmap jsonTableRow tableBodyRows)) ] jsonTableRow TableRow{..} = jsonArray (fmap jsonTableCell tableRowCells) - jsonTableCell TableCell{..} = jsonObject + jsonTableCell TableCell{..} = + jsonObject [ ("tableCellColspan", jsonInt tableCellColspan) , ("tableCellRowspan", jsonInt tableCellRowspan) , ("tableCellContents", jsonDoc tableCellContents) ] - jsonModule :: Module -> JsonDoc jsonModule = JSString . moduleStableString @@ -234,9 +242,10 @@ jsonName = JSString . nameStableString jsonFixity :: Fixity -> JsonDoc jsonFixity (Fixity _ prec dir) = - jsonObject [ ("prec" , jsonInt prec) - , ("direction" , jsonFixityDirection dir) - ] + jsonObject + [ ("prec", jsonInt prec) + , ("direction", jsonFixityDirection dir) + ] jsonFixityDirection :: FixityDirection -> JsonDoc jsonFixityDirection InfixL = jsonString "infixl" diff --git a/haddock-api/src/Haddock/Interface/LexParseRn.hs b/haddock-api/src/Haddock/Interface/LexParseRn.hs index 43b3ab50e7..a366cbfcc9 100644 --- a/haddock-api/src/Haddock/Interface/LexParseRn.hs +++ b/haddock-api/src/Haddock/Interface/LexParseRn.hs @@ -1,8 +1,12 @@ -{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE BangPatterns #-} {-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE ViewPatterns #-} +{-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -Wwarn #-} - ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.Interface.LexParseRn -- Copyright : (c) Isaac Dupree 2009, @@ -12,7 +16,6 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------ module Haddock.Interface.LexParseRn ( processDocString , processDocStringParas @@ -24,14 +27,15 @@ import Control.Arrow import Control.Monad import Control.Monad.State.Strict import Data.Functor -import Data.List ((\\), maximumBy) +import Data.List (maximumBy, (\\)) import Data.Ord import qualified Data.Set as Set import GHC import GHC.Data.EnumSet as EnumSet -import GHC.Data.FastString ( unpackFS ) -import GHC.Driver.Ppr ( showPpr, showSDoc ) +import GHC.Data.FastString (unpackFS) +import GHC.Driver.Ppr (showPpr, showSDoc) import GHC.Driver.Session +import qualified GHC.LanguageExtensions as LangExt import GHC.Parser.PostProcess import GHC.Types.Avail import GHC.Types.Name @@ -42,7 +46,6 @@ import GHC.Utils.Outputable (Outputable) import Haddock.Interface.ParseModuleHeader import Haddock.Parser import Haddock.Types -import qualified GHC.LanguageExtensions as LangExt processDocStringsParas :: MonadIO m @@ -91,28 +94,32 @@ processModuleHeader dflags pkgName safety mayLang extSet mayStr = do (hmi, doc) = parseModuleHeader dflags pkgName str renamer = hsDocRenamer hsDoc !descr <- case hmi_description hmi of - Just hmi_descr -> Just <$> rename dflags renamer hmi_descr - Nothing -> pure Nothing - let hmi' = hmi { hmi_description = descr } - doc' <- overDocF (rename dflags renamer) doc + Just hmi_descr -> Just <$> rename dflags renamer hmi_descr + Nothing -> pure Nothing + let hmi' = hmi{hmi_description = descr} + doc' <- overDocF (rename dflags renamer) doc return (hmi', Just doc') let flags :: [LangExt.Extension] -- We remove the flags implied by the language setting and we display the language instead flags = EnumSet.toList extSet \\ languageExtensions mayLang return - (hmi { hmi_safety = Just $ showPpr dflags safety - , hmi_language = language dflags - , hmi_extensions = flags - } + ( hmi + { hmi_safety = Just $ showPpr dflags safety + , hmi_language = language dflags + , hmi_extensions = flags + } , doc ) where failure = (emptyHaddockModInfo, Nothing) traverseSnd :: (Traversable t, Applicative f) => (a -> f b) -> t (x, a) -> f (t (x, b)) -traverseSnd f = traverse (\(x, a) -> - (\b -> (x, b)) <$> f a) +traverseSnd f = + traverse + ( \(x, a) -> + (\b -> (x, b)) <$> f a + ) -- | Takes a 'GlobalRdrEnv' which (hopefully) contains all the -- definitions and a parsed comment and we attempt to make sense of @@ -136,25 +143,26 @@ rename dflags renamer = rn DocIdentifier i -> do let NsRdrName ns x = unwrap i occ = rdrNameOcc x - let valueNsChoices | isDataOcc occ = isDataConNameSpace - | otherwise = isTermVarOrFieldNameSpace - typeNsChoices | isDataOcc occ = isTcClsNameSpace - | otherwise = isTvNameSpace + let valueNsChoices + | isDataOcc occ = isDataConNameSpace + | otherwise = isTermVarOrFieldNameSpace + typeNsChoices + | isDataOcc occ = isTcClsNameSpace + | otherwise = isTvNameSpace -- Generate the choices for the possible kind of thing this -- is. We narrow down the possibilities with the namespace (if -- there is one). let choices = case ns of - Value -> valueNsChoices - Type -> typeNsChoices - None -> valueNsChoices <||> typeNsChoices + Value -> valueNsChoices + Type -> typeNsChoices + None -> valueNsChoices <||> typeNsChoices case renamer (showPpr dflags x) choices of - [] -> case ns of + [] -> case ns of Type -> outOfScope dflags ns (i $> setRdrNameSpace x tcName) _ -> outOfScope dflags ns (i $> x) [a] -> pure (DocIdentifier $ i $> a) -- There are multiple names available. names -> ambiguous dflags i names - DocWarning dw -> DocWarning <$> rn dw DocEmphasis de -> DocEmphasis <$> rn de DocBold db -> DocBold <$> rn db @@ -187,11 +195,11 @@ rename dflags renamer = rn -- default we pick in 'rename'. outOfScope :: MonadIO m => DynFlags -> Namespace -> Wrap RdrName -> IfM m (Doc a) outOfScope dflags ns x = - case unwrap x of - Unqual occ -> warnAndMonospace (x $> occ) - Qual mdl occ -> pure (DocIdentifierUnchecked (x $> (mdl, occ))) - Orig _ occ -> warnAndMonospace (x $> occ) - Exact name -> warnAndMonospace (x $> name) -- Shouldn't happen since x is out of scope + case unwrap x of + Unqual occ -> warnAndMonospace (x $> occ) + Qual mdl occ -> pure (DocIdentifierUnchecked (x $> (mdl, occ))) + Orig _ occ -> warnAndMonospace (x $> occ) + Exact name -> warnAndMonospace (x $> name) -- Shouldn't happen since x is out of scope where prefix = case ns of @@ -207,9 +215,13 @@ outOfScope dflags ns x = firstWarn <- Set.notMember a' <$> gets ifeOutOfScopeNames when firstWarn $ do warn $ - "Warning: " ++ prefix ++ "'" ++ a' ++ "' is out of scope.\n" ++ - " If you qualify the identifier, haddock can try to link it anyway." - modify' (\env -> env { ifeOutOfScopeNames = Set.insert a' (ifeOutOfScopeNames env) }) + "Warning: " + ++ prefix + ++ "'" + ++ a' + ++ "' is out of scope.\n" + ++ " If you qualify the identifier, haddock can try to link it anyway." + modify' (\env -> env{ifeOutOfScopeNames = Set.insert a' (ifeOutOfScopeNames env)}) pure (monospaced a') monospaced = DocMonospaced . DocString @@ -223,33 +235,38 @@ ambiguous :: MonadIO m => DynFlags -> Wrap NsRdrName - -> [Name] -- ^ More than one @gre@s sharing the same `RdrName` above. + -> [Name] + -- ^ More than one @gre@s sharing the same `RdrName` above. -> IfM m (Doc Name) ambiguous dflags x names = do - let noChildren = map availName (nubAvails (map Avail names)) - dflt = maximumBy (comparing (isLocalName &&& isTyConName)) noChildren - nameStr = showNsRdrName dflags x - msg = "Warning: " ++ nameStr ++ " is ambiguous. It is defined\n" ++ - concatMap (\n -> " * " ++ defnLoc n ++ "\n") names ++ - " You may be able to disambiguate the identifier by qualifying it or\n" ++ - " by specifying the type/value namespace explicitly.\n" ++ - " Defaulting to the one defined " ++ defnLoc dflt + let noChildren = map availName (nubAvails (map Avail names)) + dflt = maximumBy (comparing (isLocalName &&& isTyConName)) noChildren + nameStr = showNsRdrName dflags x + msg = + "Warning: " + ++ nameStr + ++ " is ambiguous. It is defined\n" + ++ concatMap (\n -> " * " ++ defnLoc n ++ "\n") names + ++ " You may be able to disambiguate the identifier by qualifying it or\n" + ++ " by specifying the type/value namespace explicitly.\n" + ++ " Defaulting to the one defined " + ++ defnLoc dflt - -- TODO: Once we have a syntax for namespace qualification (#667) we may also - -- want to emit a warning when an identifier is a data constructor for a type - -- of the same name, but not the only constructor. - -- For example, for @data D = C | D@, someone may want to reference the @D@ - -- constructor. + -- TODO: Once we have a syntax for namespace qualification (#667) we may also + -- want to emit a warning when an identifier is a data constructor for a type + -- of the same name, but not the only constructor. + -- For example, for @data D = C | D@, someone may want to reference the @D@ + -- constructor. - -- If we have already warned for this name, do not warn again - firstWarn <- Set.notMember nameStr <$> gets ifeAmbiguousNames - when (length noChildren > 1 && firstWarn) $ do - warn msg - modify' (\env -> env { ifeAmbiguousNames = Set.insert nameStr (ifeAmbiguousNames env) }) + -- If we have already warned for this name, do not warn again + firstWarn <- Set.notMember nameStr <$> gets ifeAmbiguousNames + when (length noChildren > 1 && firstWarn) $ do + warn msg + modify' (\env -> env{ifeAmbiguousNames = Set.insert nameStr (ifeAmbiguousNames env)}) - pure (DocIdentifier (x $> dflt)) + pure (DocIdentifier (x $> dflt)) where - isLocalName (nameSrcLoc -> RealSrcLoc {}) = True + isLocalName (nameSrcLoc -> RealSrcLoc{}) = True isLocalName _ = False defnLoc = showSDoc dflags . pprNameDefnLoc @@ -266,4 +283,4 @@ hsDocRenamer hsDoc = \s cands -> nameSetElemsStable $ filterNameSet (nameMatches !env = hsDocIds hsDoc nameMatches s ok_ns n = let occ = occName n - in ok_ns (occNameSpace occ) && s == unpackFS (occNameFS occ) + in ok_ns (occNameSpace occ) && s == unpackFS (occNameFS occ) diff --git a/haddock-api/src/Haddock/Interface/ParseModuleHeader.hs b/haddock-api/src/Haddock/Interface/ParseModuleHeader.hs index 3e464fbc18..8b96408aae 100644 --- a/haddock-api/src/Haddock/Interface/ParseModuleHeader.hs +++ b/haddock-api/src/Haddock/Interface/ParseModuleHeader.hs @@ -1,7 +1,10 @@ -{-# OPTIONS_GHC -Wwarn #-} {-# LANGUAGE DeriveFunctor #-} +{-# OPTIONS_GHC -Wwarn #-} ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.Interface.ParseModuleHeader -- Copyright : (c) Simon Marlow 2006, Isaac Dupree 2009 @@ -10,7 +13,6 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------ module Haddock.Interface.ParseModuleHeader (parseModuleHeader) where import Control.Applicative (Alternative (..)) @@ -28,39 +30,41 @@ import Haddock.Types -- any or all may be omitted. parseModuleHeader :: DynFlags -> Maybe Package -> String -> (HaddockModInfo NsRdrName, MDoc NsRdrName) parseModuleHeader dflags pkgName str0 = - let - kvs :: [(String, String)] - str1 :: String - - (kvs, str1) = maybe ([], str0) id $ runP fields str0 - - -- trim whitespaces - trim :: String -> String - trim = dropWhile isSpace . reverse . dropWhile isSpace . reverse - - getKey :: String -> Maybe String - getKey key = fmap trim (lookup key kvs) - - descriptionOpt = getKey "Description" - copyrightOpt = getKey "Copyright" - licenseOpt = getKey "License" - licenceOpt = getKey "Licence" - spdxLicenceOpt = getKey "SPDX-License-Identifier" - maintainerOpt = getKey "Maintainer" - stabilityOpt = getKey "Stability" - portabilityOpt = getKey "Portability" - - in (HaddockModInfo { - hmi_description = parseString dflags <$> descriptionOpt, - hmi_copyright = copyrightOpt, - hmi_license = spdxLicenceOpt <|> licenseOpt <|> licenceOpt, - hmi_maintainer = maintainerOpt, - hmi_stability = stabilityOpt, - hmi_portability = portabilityOpt, - hmi_safety = Nothing, - hmi_language = Nothing, -- set in LexParseRn - hmi_extensions = [] -- also set in LexParseRn - }, parseParas dflags pkgName str1) + let + kvs :: [(String, String)] + str1 :: String + + (kvs, str1) = maybe ([], str0) id $ runP fields str0 + + -- trim whitespaces + trim :: String -> String + trim = dropWhile isSpace . reverse . dropWhile isSpace . reverse + + getKey :: String -> Maybe String + getKey key = fmap trim (lookup key kvs) + + descriptionOpt = getKey "Description" + copyrightOpt = getKey "Copyright" + licenseOpt = getKey "License" + licenceOpt = getKey "Licence" + spdxLicenceOpt = getKey "SPDX-License-Identifier" + maintainerOpt = getKey "Maintainer" + stabilityOpt = getKey "Stability" + portabilityOpt = getKey "Portability" + in + ( HaddockModInfo + { hmi_description = parseString dflags <$> descriptionOpt + , hmi_copyright = copyrightOpt + , hmi_license = spdxLicenceOpt <|> licenseOpt <|> licenceOpt + , hmi_maintainer = maintainerOpt + , hmi_stability = stabilityOpt + , hmi_portability = portabilityOpt + , hmi_safety = Nothing + , hmi_language = Nothing -- set in LexParseRn + , hmi_extensions = [] -- also set in LexParseRn + } + , parseParas dflags pkgName str1 + ) ------------------------------------------------------------------------------- -- Small parser to parse module header. @@ -92,31 +96,31 @@ parseModuleHeader dflags pkgName str0 = -- by looking at the next character in the stream ('curInd'). -- -- Thus we can munch all spaces but only not-spaces which are indented. --- data C = C {-# UNPACK #-} !Int Char -newtype P a = P { unP :: [C] -> Maybe ([C], a) } - deriving Functor +newtype P a = P {unP :: [C] -> Maybe ([C], a)} + deriving (Functor) instance Applicative P where - pure x = P $ \s -> Just (s, x) - (<*>) = ap + pure x = P $ \s -> Just (s, x) + (<*>) = ap instance Monad P where - return = pure - m >>= k = P $ \s0 -> do - (s1, x) <- unP m s0 - unP (k x) s1 + return = pure + m >>= k = P $ \s0 -> do + (s1, x) <- unP m s0 + unP (k x) s1 instance Alternative P where - empty = P $ \_ -> Nothing - a <|> b = P $ \s -> unP a s <|> unP b s + empty = P $ \_ -> Nothing + a <|> b = P $ \s -> unP a s <|> unP b s runP :: P a -> String -> Maybe a runP p input = fmap snd (unP p input') where - input' = concat - [ zipWith C [0..] l ++ [C (length l) '\n'] + input' = + concat + [ zipWith C [0 ..] l ++ [C (length l) '\n'] | l <- lines input ] @@ -126,45 +130,48 @@ runP p input = fmap snd (unP p input') curInd :: P Int curInd = P $ \s -> Just . (,) s $ case s of - [] -> 0 - C i _ : _ -> i + [] -> 0 + C i _ : _ -> i rest :: P String -rest = P $ \cs -> Just ([], [ c | C _ c <- cs ]) +rest = P $ \cs -> Just ([], [c | C _ c <- cs]) munch :: (Int -> Char -> Bool) -> P String munch p = P $ \cs -> - let (xs,ys) = takeWhileMaybe p' cs in Just (ys, xs) + let (xs, ys) = takeWhileMaybe p' cs in Just (ys, xs) where p' (C i c) - | p i c = Just c - | otherwise = Nothing + | p i c = Just c + | otherwise = Nothing munch1 :: (Int -> Char -> Bool) -> P String munch1 p = P $ \s -> case s of - [] -> Nothing - (c:cs) | Just c' <- p' c -> let (xs,ys) = takeWhileMaybe p' cs in Just (ys, c' : xs) - | otherwise -> Nothing + [] -> Nothing + (c : cs) + | Just c' <- p' c -> let (xs, ys) = takeWhileMaybe p' cs in Just (ys, c' : xs) + | otherwise -> Nothing where p' (C i c) - | p i c = Just c - | otherwise = Nothing + | p i c = Just c + | otherwise = Nothing char :: Char -> P Char char c = P $ \s -> case s of - [] -> Nothing - (C _ c' : cs) | c == c' -> Just (cs, c) - | otherwise -> Nothing + [] -> Nothing + (C _ c' : cs) + | c == c' -> Just (cs, c) + | otherwise -> Nothing skipSpaces :: P () skipSpaces = P $ \cs -> Just (dropWhile (\(C _ c) -> isSpace c) cs, ()) takeWhileMaybe :: (a -> Maybe b) -> [a] -> ([b], [a]) -takeWhileMaybe f = go where +takeWhileMaybe f = go + where go xs0@[] = ([], xs0) - go xs0@(x:xs) = case f x of - Just y -> let (ys, zs) = go xs in (y : ys, zs) - Nothing -> ([], xs0) + go xs0@(x : xs) = case f x of + Just y -> let (ys, zs) = go xs in (y : ys, zs) + Nothing -> ([], xs0) ------------------------------------------------------------------------------- -- Fields @@ -172,18 +179,17 @@ takeWhileMaybe f = go where field :: Int -> P (String, String) field i = do - fn <- munch1 $ \_ c -> isAlpha c || c == '-' - skipSpaces - _ <- char ':' - skipSpaces - val <- munch $ \j c -> isSpace c || j > i - return (fn, val) + fn <- munch1 $ \_ c -> isAlpha c || c == '-' + skipSpaces + _ <- char ':' + skipSpaces + val <- munch $ \j c -> isSpace c || j > i + return (fn, val) fields :: P ([(String, String)], String) fields = do - skipSpaces - i <- curInd - fs <- many (field i) - r <- rest - return (fs, r) - + skipSpaces + i <- curInd + fs <- many (field i) + r <- rest + return (fs, r) diff --git a/haddock-api/src/Haddock/Interface/Rename.hs b/haddock-api/src/Haddock/Interface/Rename.hs index 736141659e..f0677995d9 100644 --- a/haddock-api/src/Haddock/Interface/Rename.hs +++ b/haddock-api/src/Haddock/Interface/Rename.hs @@ -1,10 +1,13 @@ -{-# LANGUAGE BangPatterns #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE TypeFamilies #-} ---------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.Interface.Rename -- Copyright : (c) Simon Marlow 2003-2006, @@ -14,21 +17,19 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------ module Haddock.Interface.Rename (renameInterface) where - import Data.Traversable (mapM) import Haddock.Backends.Hoogle (ppExportD) import Haddock.GhcUtils import Haddock.Types -import GHC.Data.Bag (emptyBag) import GHC hiding (NoLink) +import GHC.Builtin.Types (eqTyCon_RDR, tupleDataConName, tupleTyConName) +import GHC.Data.Bag (emptyBag) import GHC.Types.Name -import GHC.Types.Name.Reader (RdrName(Exact)) -import GHC.Builtin.Types (eqTyCon_RDR, tupleTyConName, tupleDataConName) +import GHC.Types.Name.Reader (RdrName (Exact)) import Control.Applicative import Control.DeepSeq (force) @@ -38,8 +39,8 @@ import Control.Monad.Writer.CPS import Data.Foldable (traverse_) import qualified Data.Map.Strict as Map import qualified Data.Set as Set +import GHC.Types.Basic (Boxity (..), TopLevelFlag (..), TupleSort (..)) import Prelude hiding (mapM) -import GHC.Types.Basic ( TopLevelFlag(..), TupleSort(..), Boxity(..) ) -- | Traverse docstrings and ASTs in the Haddock interface, renaming 'Name' to -- 'DocName'. @@ -71,16 +72,16 @@ renameInterface -- this being in the 'Ghc' monad. This could very easily be any 'MonadIO' or -- even pure, depending on the link warnings are reported. renameInterface dflags ignoreSet renamingEnv warnings hoogle iface = do - let (iface', warnedNames) = - runRnM - dflags - mdl - localLinkEnv - warnName - (hoogle && not (OptHide `elem` ifaceOptions iface)) - (renameInterfaceRn iface) - reportMissingLinks mdl warnedNames - return iface' + let (iface', warnedNames) = + runRnM + dflags + mdl + localLinkEnv + warnName + (hoogle && not (OptHide `elem` ifaceOptions iface)) + (renameInterfaceRn iface) + reportMissingLinks mdl warnedNames + return iface' where -- The current module mdl :: Module @@ -91,26 +92,24 @@ renameInterface dflags ignoreSet renamingEnv warnings hoogle iface = do -- renaming env localLinkEnv :: LinkEnv localLinkEnv = foldr f renamingEnv (ifaceVisibleExports iface) - where f name !env = Map.insert name mdl env + where + f name !env = Map.insert name mdl env -- The function used to determine whether we should warn about a name -- which we do not find in the renaming environment warnName name = - -- Warnings must be enabled - warnings - - -- Current module must not be hidden from Haddock + -- Warnings must be enabled + warnings + -- Current module must not be hidden from Haddock && not (OptHide `elem` ifaceOptions iface) - - -- Must be an external name that is not built-in syntax, not a type - -- variable, and not '~' + -- Must be an external name that is not built-in syntax, not a type + -- variable, and not '~' && isExternalName name && not (isBuiltInSyntax name) && not (isTyVarName name) && Exact name /= eqTyCon_RDR - - -- Must not be in the set of ignored symbols for the module or the - -- unqualified ignored symbols + -- Must not be in the set of ignored symbols for the module or the + -- unqualified ignored symbols && not (getOccString name `Set.member` ignoreSet') where -- The set of ignored symbols within the module this name is located @@ -129,11 +128,11 @@ renameInterface dflags ignoreSet renamingEnv warnings hoogle iface = do -- module. reportMissingLinks :: Module -> Set.Set Name -> Ghc () reportMissingLinks mdl names - | Set.null names = return () - | otherwise = - liftIO $ do - putStrLn $ "Warning: " ++ moduleString mdl ++ ": could not find link destinations for: " - traverse_ (putStrLn . ("\t- " ++) . qualifiedName) names + | Set.null names = return () + | otherwise = + liftIO $ do + putStrLn $ "Warning: " ++ moduleString mdl ++ ": could not find link destinations for: " + traverse_ (putStrLn . ("\t- " ++) . qualifiedName) names where qualifiedName :: Name -> String qualifiedName name = moduleString (nameModule name) ++ "." ++ getOccString name @@ -145,28 +144,24 @@ reportMissingLinks mdl names -- | A renaming monad which provides 'MonadReader' access to a renaming -- environment, and 'MonadWriter' access to a 'Set' of names for which link -- warnings should be generated, based on the renaming environment. -newtype RnM a = RnM { unRnM :: ReaderT RnMEnv (Writer (Set.Set Name)) a } +newtype RnM a = RnM {unRnM :: ReaderT RnMEnv (Writer (Set.Set Name)) a} deriving newtype (Functor, Applicative, Monad, MonadReader RnMEnv, MonadWriter (Set.Set Name)) -- | The renaming monad environment. Stores the linking environment (mapping -- names to modules), the link warning predicate, and the current module. data RnMEnv = RnMEnv - { -- | The linking environment (map from names to modules) - rnLinkEnv :: LinkEnv - - -- | Link warning predicate (whether failing to find a link destination - -- for a given name should result in a warning) - , rnWarnName :: (Name -> Bool) - - -- | The current module - , rnModuleString :: String - - -- | Should Hoogle output be generated for this module? - , rnHoogleOutput :: Bool - - -- | GHC Session DynFlags, necessary for Hoogle output generation - , rnDynFlags :: DynFlags - } + { rnLinkEnv :: LinkEnv + -- ^ The linking environment (map from names to modules) + , rnWarnName :: (Name -> Bool) + -- ^ Link warning predicate (whether failing to find a link destination + -- for a given name should result in a warning) + , rnModuleString :: String + -- ^ The current module + , rnHoogleOutput :: Bool + -- ^ Should Hoogle output be generated for this module? + , rnDynFlags :: DynFlags + -- ^ GHC Session DynFlags, necessary for Hoogle output generation + } -- | Run the renamer action in a renaming environment built using the given -- module, link env, and link warning predicate. Returns the renamed value along @@ -174,16 +169,17 @@ data RnMEnv = RnMEnv -- they satisfied the link warning predicate). runRnM :: DynFlags -> Module -> LinkEnv -> (Name -> Bool) -> Bool -> RnM a -> (a, Set.Set Name) runRnM dflags mdl linkEnv warnName hoogleOutput rn = - runWriter $ runReaderT (unRnM rn) rnEnv + runWriter $ runReaderT (unRnM rn) rnEnv where rnEnv :: RnMEnv - rnEnv = RnMEnv - { rnLinkEnv = linkEnv - , rnWarnName = warnName - , rnModuleString = moduleString mdl - , rnHoogleOutput = hoogleOutput - , rnDynFlags = dflags - } + rnEnv = + RnMEnv + { rnLinkEnv = linkEnv + , rnWarnName = warnName + , rnModuleString = moduleString mdl + , rnHoogleOutput = hoogleOutput + , rnDynFlags = dflags + } -------------------------------------------------------------------------------- -- Renaming @@ -193,41 +189,41 @@ runRnM dflags mdl linkEnv warnName hoogleOutput rn = renameInterfaceRn :: Interface -> RnM Interface renameInterfaceRn iface = do exportItems <- renameExportItems (ifaceExportItems iface) - orphans <- mapM renameDocInstance (ifaceOrphanInstances iface) + orphans <- mapM renameDocInstance (ifaceOrphanInstances iface) finalModDoc <- renameDocumentation (ifaceDoc iface) - pure $! iface - { ifaceRnDoc = finalModDoc - - -- The un-renamed export items are not used after renaming - , ifaceRnExportItems = exportItems - , ifaceExportItems = [] - - -- The un-renamed orphan instances are not used after renaming - , ifaceRnOrphanInstances = orphans - , ifaceOrphanInstances = [] - } + pure $! + iface + { ifaceRnDoc = finalModDoc + , -- The un-renamed export items are not used after renaming + ifaceRnExportItems = exportItems + , ifaceExportItems = [] + , -- The un-renamed orphan instances are not used after renaming + ifaceRnOrphanInstances = orphans + , ifaceOrphanInstances = [] + } -- | Lookup a 'Name' in the renaming environment. lookupRn :: Name -> RnM DocName lookupRn name = RnM $ do - linkEnv <- asks rnLinkEnv - case Map.lookup name linkEnv of - Nothing -> return $ Undocumented name - Just mdl -> return $ Documented name mdl + linkEnv <- asks rnLinkEnv + case Map.lookup name linkEnv of + Nothing -> return $ Undocumented name + Just mdl -> return $ Documented name mdl -- | Rename a 'Name' in the renaming environment. This is very similar to -- 'lookupRn', but tracks any names not found in the renaming environment if the -- `rnWarnName` predicate is true. renameName :: Name -> RnM DocName renameName name = do - warnName <- asks rnWarnName - docName <- lookupRn name - case docName of - Undocumented _ -> do - when (warnName name) $ - tell $ Set.singleton name - return docName - _ -> return docName + warnName <- asks rnWarnName + docName <- lookupRn name + case docName of + Undocumented _ -> do + when (warnName name) $ + tell $ + Set.singleton name + return docName + _ -> return docName -- | Rename a located 'Name' in the current renaming environment. renameNameL :: GenLocated l Name -> RnM (GenLocated l DocName) @@ -247,15 +243,15 @@ renameExportItem item = case item of ExportDecl ed@(ExportD decl pats doc subs instances fixities splice) -> do -- If Hoogle output should be generated, generate it RnMEnv{..} <- ask - let !hoogleOut = force $ - if rnHoogleOutput then - ppExportD rnDynFlags ed - else - [] + let !hoogleOut = + force $ + if rnHoogleOutput + then ppExportD rnDynFlags ed + else [] decl' <- renameLDecl decl pats' <- renamePats pats - doc' <- renameDocForDecl doc + doc' <- renameDocForDecl doc subs' <- mapM renameSub subs instances' <- forM instances renameDocInstance fixities' <- forM fixities $ \(name, fixity) -> do @@ -263,12 +259,13 @@ renameExportItem item = case item of return (name', fixity) return $ - ExportDecl RnExportD - { rnExpDExpD = ExportD decl' pats' doc' subs' instances' fixities' splice - , rnExpDHoogle = hoogleOut - } + ExportDecl + RnExportD + { rnExpDExpD = ExportD decl' pats' doc' subs' instances' fixities' splice + , rnExpDHoogle = hoogleOut + } ExportNoDecl x subs -> do - x' <- lookupRn x + x' <- lookupRn x subs' <- mapM lookupRn subs return (ExportNoDecl x' subs') ExportDoc doc -> do @@ -296,10 +293,12 @@ renameLType :: LHsType GhcRn -> RnM (LHsType DocNameI) renameLType = mapM renameType renameLTypeArg :: LHsTypeArg GhcRn -> RnM (LHsTypeArg DocNameI) -renameLTypeArg (HsValArg _ ty) = do { ty' <- renameLType ty - ; return $ HsValArg noExtField ty' } -renameLTypeArg (HsTypeArg _ ki) = do { ki' <- renameLKind ki - ; return $ HsTypeArg noExtField ki' } +renameLTypeArg (HsValArg _ ty) = do + ty' <- renameLType ty + return $ HsValArg noExtField ty' +renameLTypeArg (HsTypeArg _ ki) = do + ki' <- renameLKind ki + return $ HsTypeArg noExtField ki' renameLTypeArg (HsArgPar _) = return $ HsArgPar noExtField renameLSigType :: LHsSigType GhcRn -> RnM (LHsSigType DocNameI) @@ -315,23 +314,27 @@ renameMaybeLKind :: Maybe (LHsKind GhcRn) -> RnM (Maybe (LHsKind DocNameI)) renameMaybeLKind = traverse renameLKind renameFamilyResultSig :: LFamilyResultSig GhcRn -> RnM (LFamilyResultSig DocNameI) -renameFamilyResultSig (L loc (NoSig _)) - = return (L loc (NoSig noExtField)) -renameFamilyResultSig (L loc (KindSig _ ki)) - = do { ki' <- renameLKind ki - ; return (L loc (KindSig noExtField ki')) } -renameFamilyResultSig (L loc (TyVarSig _ bndr)) - = do { bndr' <- renameLTyVarBndr return bndr - ; return (L loc (TyVarSig noExtField bndr')) } +renameFamilyResultSig (L loc (NoSig _)) = + return (L loc (NoSig noExtField)) +renameFamilyResultSig (L loc (KindSig _ ki)) = + do + ki' <- renameLKind ki + return (L loc (KindSig noExtField ki')) +renameFamilyResultSig (L loc (TyVarSig _ bndr)) = + do + bndr' <- renameLTyVarBndr return bndr + return (L loc (TyVarSig noExtField bndr')) renameInjectivityAnn :: LInjectivityAnn GhcRn -> RnM (LInjectivityAnn DocNameI) -renameInjectivityAnn (L loc (InjectivityAnn _ lhs rhs)) - = do { lhs' <- renameNameL lhs - ; rhs' <- mapM renameNameL rhs - ; return (L loc (InjectivityAnn noExtField lhs' rhs')) } - -renameMaybeInjectivityAnn :: Maybe (LInjectivityAnn GhcRn) - -> RnM (Maybe (LInjectivityAnn DocNameI)) +renameInjectivityAnn (L loc (InjectivityAnn _ lhs rhs)) = + do + lhs' <- renameNameL lhs + rhs' <- mapM renameNameL rhs + return (L loc (InjectivityAnn noExtField lhs' rhs')) + +renameMaybeInjectivityAnn + :: Maybe (LInjectivityAnn GhcRn) + -> RnM (Maybe (LInjectivityAnn DocNameI)) renameMaybeInjectivityAnn = traverse renameInjectivityAnn renameArrow :: HsArrow GhcRn -> RnM (HsArrow DocNameI) @@ -341,41 +344,38 @@ renameArrow (HsExplicitMult _ p) = HsExplicitMult noExtField <$> renameLType p renameType :: HsType GhcRn -> RnM (HsType DocNameI) renameType t = case t of - HsForAllTy { hst_tele = tele, hst_body = ltype } -> do - tele' <- renameHsForAllTelescope tele + HsForAllTy{hst_tele = tele, hst_body = ltype} -> do + tele' <- renameHsForAllTelescope tele ltype' <- renameLType ltype - return (HsForAllTy { hst_xforall = noAnn - , hst_tele = tele', hst_body = ltype' }) - - HsQualTy { hst_ctxt = lcontext , hst_body = ltype } -> do + return + ( HsForAllTy + { hst_xforall = noAnn + , hst_tele = tele' + , hst_body = ltype' + } + ) + HsQualTy{hst_ctxt = lcontext, hst_body = ltype} -> do lcontext' <- renameLContext lcontext - ltype' <- renameLType ltype - return (HsQualTy { hst_xqual = noAnn, hst_ctxt = lcontext', hst_body = ltype' }) - + ltype' <- renameLType ltype + return (HsQualTy{hst_xqual = noAnn, hst_ctxt = lcontext', hst_body = ltype'}) HsTyVar _ ip (L l n) -> return . HsTyVar noAnn ip . L l =<< renameName n HsBangTy _ b ltype -> return . HsBangTy noAnn b =<< renameLType ltype - HsStarTy _ isUni -> return (HsStarTy noAnn isUni) - HsAppTy _ a b -> do a' <- renameLType a b' <- renameLType b return (HsAppTy noAnn a' b') - HsAppKindTy _ a b -> do a' <- renameLType a b' <- renameLKind b return (HsAppKindTy noAnn a' b') - HsFunTy _ w a b -> do a' <- renameLType a b' <- renameLType b w' <- renameArrow w return (HsFunTy noAnn w' a' b') - HsListTy _ ty -> return . (HsListTy noAnn) =<< renameLType ty HsIParamTy _ n ty -> liftM (HsIParamTy noAnn n) (renameLType ty) - -- Special-case unary boxed tuples so that they are pretty-printed as -- `Solo x`, not `(x)` HsTupleTy _ HsBoxedOrConstraintTuple [ty] -> do @@ -385,31 +385,24 @@ renameType t = case t of return (HsAppTy noAnn lhs rhs) HsTupleTy _ b ts -> return . HsTupleTy noAnn b =<< mapM renameLType ts HsSumTy _ ts -> HsSumTy noAnn <$> mapM renameLType ts - HsOpTy _ prom a (L loc op) b -> do op' <- renameName op - a' <- renameLType a - b' <- renameLType b + a' <- renameLType a + b' <- renameLType b return (HsOpTy noAnn prom a' (L loc op') b') - HsParTy _ ty -> return . (HsParTy noAnn) =<< renameLType ty - HsKindSig _ ty k -> do ty' <- renameLType ty k' <- renameLKind k return (HsKindSig noAnn ty' k') - HsDocTy _ ty doc -> do ty' <- renameLType ty doc' <- renameLDocHsSyn doc return (HsDocTy noAnn ty' doc') - HsTyLit _ x -> return (HsTyLit noAnn (renameTyLit x)) - - HsRecTy _ a -> HsRecTy noAnn <$> mapM renameConDeclFieldField a - XHsType a -> pure (XHsType a) - HsExplicitListTy _ a b -> HsExplicitListTy noAnn a <$> mapM renameLType b - + HsRecTy _ a -> HsRecTy noAnn <$> mapM renameConDeclFieldField a + XHsType a -> pure (XHsType a) + HsExplicitListTy _ a b -> HsExplicitListTy noAnn a <$> mapM renameLType b -- Special-case unary boxed tuples so that they are pretty-printed as -- `'MkSolo x`, not `'(x)` HsExplicitTupleTy _ [ty] -> do @@ -417,30 +410,33 @@ renameType t = case t of let lhs = noLocA $ HsTyVar noAnn IsPromoted (noLocA name) rhs <- renameLType ty return (HsAppTy noAnn lhs rhs) - HsExplicitTupleTy _ b -> HsExplicitTupleTy noAnn <$> mapM renameLType b - - HsSpliceTy (HsUntypedSpliceTop _ st) _ -> renameType (unLoc st) + HsExplicitTupleTy _ b -> HsExplicitTupleTy noAnn <$> mapM renameLType b + HsSpliceTy (HsUntypedSpliceTop _ st) _ -> renameType (unLoc st) HsSpliceTy (HsUntypedSpliceNested _) _ -> error "renameType: not an top level type splice" - HsWildCardTy _ -> pure (HsWildCardTy noAnn) + HsWildCardTy _ -> pure (HsWildCardTy noAnn) renameTyLit :: HsTyLit GhcRn -> HsTyLit DocNameI renameTyLit t = case t of - HsNumTy _ v -> HsNumTy noExtField v - HsStrTy _ v -> HsStrTy noExtField v + HsNumTy _ v -> HsNumTy noExtField v + HsStrTy _ v -> HsStrTy noExtField v HsCharTy _ v -> HsCharTy noExtField v - renameSigType :: HsSigType GhcRn -> RnM (HsSigType DocNameI) -renameSigType (HsSig { sig_bndrs = bndrs, sig_body = body }) = do +renameSigType (HsSig{sig_bndrs = bndrs, sig_body = body}) = do bndrs' <- renameOuterTyVarBndrs bndrs - body' <- renameLType body - pure $ HsSig { sig_ext = noExtField, sig_bndrs = bndrs', sig_body = body' } + body' <- renameLType body + pure $ HsSig{sig_ext = noExtField, sig_bndrs = bndrs', sig_body = body'} renameLHsQTyVars :: LHsQTyVars GhcRn -> RnM (LHsQTyVars DocNameI) -renameLHsQTyVars (HsQTvs { hsq_explicit = tvs }) - = do { tvs' <- mapM (renameLTyVarBndr renameHsBndrVis) tvs - ; return (HsQTvs { hsq_ext = noExtField - , hsq_explicit = tvs' }) } +renameLHsQTyVars (HsQTvs{hsq_explicit = tvs}) = + do + tvs' <- mapM (renameLTyVarBndr renameHsBndrVis) tvs + return + ( HsQTvs + { hsq_ext = noExtField + , hsq_explicit = tvs' + } + ) renameHsBndrVis :: HsBndrVis GhcRn -> RnM (HsBndrVis DocNameI) renameHsBndrVis (HsBndrRequired _) = return (HsBndrRequired noExtField) @@ -448,21 +444,25 @@ renameHsBndrVis (HsBndrInvisible at) = return (HsBndrInvisible at) renameHsForAllTelescope :: HsForAllTelescope GhcRn -> RnM (HsForAllTelescope DocNameI) renameHsForAllTelescope tele = case tele of - HsForAllVis _ bndrs -> do bndrs' <- mapM (renameLTyVarBndr return) bndrs - pure $ HsForAllVis noExtField bndrs' - HsForAllInvis _ bndrs -> do bndrs' <- mapM (renameLTyVarBndr return) bndrs - pure $ HsForAllInvis noExtField bndrs' + HsForAllVis _ bndrs -> do + bndrs' <- mapM (renameLTyVarBndr return) bndrs + pure $ HsForAllVis noExtField bndrs' + HsForAllInvis _ bndrs -> do + bndrs' <- mapM (renameLTyVarBndr return) bndrs + pure $ HsForAllInvis noExtField bndrs' renameLTyVarBndr :: (flag -> RnM flag') -> LHsTyVarBndr flag GhcRn -> RnM (LHsTyVarBndr flag' DocNameI) -renameLTyVarBndr rn_flag (L loc (UserTyVar _ fl (L l n))) - = do { fl' <- rn_flag fl - ; n' <- renameName n - ; return (L loc (UserTyVar noExtField fl' (L l n'))) } -renameLTyVarBndr rn_flag (L loc (KindedTyVar _ fl (L lv n) kind)) - = do { fl' <- rn_flag fl - ; n' <- renameName n - ; kind' <- renameLKind kind - ; return (L loc (KindedTyVar noExtField fl' (L lv n') kind')) } +renameLTyVarBndr rn_flag (L loc (UserTyVar _ fl (L l n))) = + do + fl' <- rn_flag fl + n' <- renameName n + return (L loc (UserTyVar noExtField fl' (L l n'))) +renameLTyVarBndr rn_flag (L loc (KindedTyVar _ fl (L lv n) kind)) = + do + fl' <- rn_flag fl + n' <- renameName n + kind' <- renameLKind kind + return (L loc (KindedTyVar noExtField fl' (L lv n') kind')) renameLContext :: LocatedC [LHsType GhcRn] -> RnM (LocatedC [LHsType DocNameI]) renameLContext (L loc context) = do @@ -470,31 +470,36 @@ renameLContext (L loc context) = do return (L loc context') renameInstHead :: InstHead GhcRn -> RnM (InstHead DocNameI) -renameInstHead InstHead {..} = do +renameInstHead InstHead{..} = do cname <- renameName ihdClsName types <- mapM renameType ihdTypes itype <- case ihdInstType of - ClassInst { .. } -> ClassInst + ClassInst{..} -> + ClassInst <$> mapM renameType clsiCtx <*> renameLHsQTyVars clsiTyVars <*> mapM renameSig clsiSigs <*> mapM renameDocInstance clsiAssocTys - TypeInst ts -> TypeInst <$> traverse renameType ts - DataInst dd -> DataInst <$> renameTyClD dd - return InstHead - { ihdClsName = cname - , ihdTypes = types - , ihdInstType = itype - } + TypeInst ts -> TypeInst <$> traverse renameType ts + DataInst dd -> DataInst <$> renameTyClD dd + return + InstHead + { ihdClsName = cname + , ihdTypes = types + , ihdInstType = itype + } renameLDecl :: LHsDecl GhcRn -> RnM (LHsDecl DocNameI) renameLDecl (L loc d) = return . L loc =<< renameDecl d renamePats :: [(HsDecl GhcRn, DocForDecl Name)] -> RnM [(HsDecl DocNameI, DocForDecl DocName)] -renamePats = mapM - (\(d,doc) -> do { d' <- renameDecl d - ; doc' <- renameDocForDecl doc - ; return (d',doc')}) +renamePats = + mapM + ( \(d, doc) -> do + d' <- renameDecl d + doc' <- renameDocForDecl doc + return (d', doc') + ) renameDecl :: HsDecl GhcRn -> RnM (HsDecl DocNameI) renameDecl decl = case decl of @@ -520,41 +525,69 @@ renameLThing fn (L loc x) = return . L (locA loc) =<< fn x renameTyClD :: TyClDecl GhcRn -> RnM (TyClDecl DocNameI) renameTyClD d = case d of --- TyFamily flav lname ltyvars kind tckind -> do - FamDecl { tcdFam = decl } -> do + -- TyFamily flav lname ltyvars kind tckind -> do + FamDecl{tcdFam = decl} -> do decl' <- renameFamilyDecl decl - return (FamDecl { tcdFExt = noExtField, tcdFam = decl' }) - - SynDecl { tcdLName = lname, tcdTyVars = tyvars, tcdFixity = fixity, tcdRhs = rhs } -> do - lname' <- renameNameL lname - tyvars' <- renameLHsQTyVars tyvars - rhs' <- renameLType rhs - return (SynDecl { tcdSExt = noExtField, tcdLName = lname', tcdTyVars = tyvars' - , tcdFixity = fixity, tcdRhs = rhs' }) - - DataDecl { tcdLName = lname, tcdTyVars = tyvars, tcdFixity = fixity, tcdDataDefn = defn } -> do - lname' <- renameNameL lname - tyvars' <- renameLHsQTyVars tyvars - defn' <- renameDataDefn defn - return (DataDecl { tcdDExt = noExtField, tcdLName = lname', tcdTyVars = tyvars' - , tcdFixity = fixity, tcdDataDefn = defn' }) - - ClassDecl { tcdCtxt = lcontext, tcdLName = lname, tcdTyVars = ltyvars, tcdFixity = fixity - , tcdFDs = lfundeps, tcdSigs = lsigs, tcdATs = ats, tcdATDefs = at_defs } -> do - lcontext' <- traverse renameLContext lcontext - lname' <- renameNameL lname - ltyvars' <- renameLHsQTyVars ltyvars - lfundeps' <- mapM renameLFunDep lfundeps - lsigs' <- mapM renameLSig lsigs - ats' <- mapM (renameLThing renameFamilyDecl) ats - at_defs' <- mapM (mapM renameTyFamDefltD) at_defs - -- we don't need the default methods or the already collected doc entities - return (ClassDecl { tcdCExt = noExtField - , tcdCtxt = lcontext', tcdLName = lname', tcdTyVars = ltyvars' - , tcdFixity = fixity - , tcdFDs = lfundeps', tcdSigs = lsigs', tcdMeths= emptyBag - , tcdATs = ats', tcdATDefs = at_defs', tcdDocs = [] }) - + return (FamDecl{tcdFExt = noExtField, tcdFam = decl'}) + SynDecl{tcdLName = lname, tcdTyVars = tyvars, tcdFixity = fixity, tcdRhs = rhs} -> do + lname' <- renameNameL lname + tyvars' <- renameLHsQTyVars tyvars + rhs' <- renameLType rhs + return + ( SynDecl + { tcdSExt = noExtField + , tcdLName = lname' + , tcdTyVars = tyvars' + , tcdFixity = fixity + , tcdRhs = rhs' + } + ) + DataDecl{tcdLName = lname, tcdTyVars = tyvars, tcdFixity = fixity, tcdDataDefn = defn} -> do + lname' <- renameNameL lname + tyvars' <- renameLHsQTyVars tyvars + defn' <- renameDataDefn defn + return + ( DataDecl + { tcdDExt = noExtField + , tcdLName = lname' + , tcdTyVars = tyvars' + , tcdFixity = fixity + , tcdDataDefn = defn' + } + ) + ClassDecl + { tcdCtxt = lcontext + , tcdLName = lname + , tcdTyVars = ltyvars + , tcdFixity = fixity + , tcdFDs = lfundeps + , tcdSigs = lsigs + , tcdATs = ats + , tcdATDefs = at_defs + } -> do + lcontext' <- traverse renameLContext lcontext + lname' <- renameNameL lname + ltyvars' <- renameLHsQTyVars ltyvars + lfundeps' <- mapM renameLFunDep lfundeps + lsigs' <- mapM renameLSig lsigs + ats' <- mapM (renameLThing renameFamilyDecl) ats + at_defs' <- mapM (mapM renameTyFamDefltD) at_defs + -- we don't need the default methods or the already collected doc entities + return + ( ClassDecl + { tcdCExt = noExtField + , tcdCtxt = lcontext' + , tcdLName = lname' + , tcdTyVars = ltyvars' + , tcdFixity = fixity + , tcdFDs = lfundeps' + , tcdSigs = lsigs' + , tcdMeths = emptyBag + , tcdATs = ats' + , tcdATDefs = at_defs' + , tcdDocs = [] + } + ) where renameLFunDep :: LHsFunDep GhcRn -> RnM (LHsFunDep DocNameI) renameLFunDep (L loc (FunDep _ xs ys)) = do @@ -565,80 +598,128 @@ renameTyClD d = case d of renameLSig (L loc sig) = return . L (locA loc) =<< renameSig sig renameFamilyDecl :: FamilyDecl GhcRn -> RnM (FamilyDecl DocNameI) -renameFamilyDecl (FamilyDecl { fdInfo = info, fdLName = lname - , fdTyVars = ltyvars - , fdFixity = fixity - , fdResultSig = result - , fdInjectivityAnn = injectivity }) = do - info' <- renameFamilyInfo info - lname' <- renameNameL lname - ltyvars' <- renameLHsQTyVars ltyvars - result' <- renameFamilyResultSig result +renameFamilyDecl + ( FamilyDecl + { fdInfo = info + , fdLName = lname + , fdTyVars = ltyvars + , fdFixity = fixity + , fdResultSig = result + , fdInjectivityAnn = injectivity + } + ) = do + info' <- renameFamilyInfo info + lname' <- renameNameL lname + ltyvars' <- renameLHsQTyVars ltyvars + result' <- renameFamilyResultSig result injectivity' <- renameMaybeInjectivityAnn injectivity - return (FamilyDecl { fdExt = noExtField, fdInfo = info', fdTopLevel = TopLevel - , fdLName = lname' - , fdTyVars = ltyvars' - , fdFixity = fixity - , fdResultSig = result' - , fdInjectivityAnn = injectivity' }) - + return + ( FamilyDecl + { fdExt = noExtField + , fdInfo = info' + , fdTopLevel = TopLevel + , fdLName = lname' + , fdTyVars = ltyvars' + , fdFixity = fixity + , fdResultSig = result' + , fdInjectivityAnn = injectivity' + } + ) renameFamilyInfo :: FamilyInfo GhcRn -> RnM (FamilyInfo DocNameI) -renameFamilyInfo DataFamily = return DataFamily +renameFamilyInfo DataFamily = return DataFamily renameFamilyInfo OpenTypeFamily = return OpenTypeFamily -renameFamilyInfo (ClosedTypeFamily eqns) - = do { eqns' <- mapM (mapM (mapM renameTyFamInstEqn)) eqns - ; return $ ClosedTypeFamily eqns' } +renameFamilyInfo (ClosedTypeFamily eqns) = + do + eqns' <- mapM (mapM (mapM renameTyFamInstEqn)) eqns + return $ ClosedTypeFamily eqns' renameDataDefn :: HsDataDefn GhcRn -> RnM (HsDataDefn DocNameI) -renameDataDefn (HsDataDefn { dd_ctxt = lcontext, dd_cType = cType - , dd_kindSig = k, dd_cons = cons }) = do +renameDataDefn + ( HsDataDefn + { dd_ctxt = lcontext + , dd_cType = cType + , dd_kindSig = k + , dd_cons = cons + } + ) = do lcontext' <- traverse renameLContext lcontext - k' <- renameMaybeLKind k - cons' <- mapM (mapMA renameCon) cons + k' <- renameMaybeLKind k + cons' <- mapM (mapMA renameCon) cons -- I don't think we need the derivings, so we return Nothing - return (HsDataDefn { dd_ext = noExtField - , dd_ctxt = lcontext', dd_cType = cType - , dd_kindSig = k', dd_cons = cons' - , dd_derivs = [] }) + return + ( HsDataDefn + { dd_ext = noExtField + , dd_ctxt = lcontext' + , dd_cType = cType + , dd_kindSig = k' + , dd_cons = cons' + , dd_derivs = [] + } + ) renameCon :: ConDecl GhcRn -> RnM (ConDecl DocNameI) -renameCon decl@(ConDeclH98 { con_name = lname, con_ex_tvs = ltyvars - , con_mb_cxt = lcontext, con_args = details - , con_doc = mbldoc - , con_forall = forall_ }) = do - lname' <- renameNameL lname - ltyvars' <- mapM (renameLTyVarBndr return) ltyvars - lcontext' <- traverse renameLContext lcontext - details' <- renameH98Details details - mbldoc' <- mapM (renameLDocHsSyn) mbldoc - return (decl { con_ext = noExtField, con_name = lname', con_ex_tvs = ltyvars' - , con_mb_cxt = lcontext' - , con_forall = forall_ -- Remove when #18311 is fixed - , con_args = details', con_doc = mbldoc' }) - -renameCon ConDeclGADT { con_names = lnames, con_bndrs = bndrs - , con_mb_cxt = lcontext, con_g_args = details - , con_res_ty = res_ty - , con_doc = mbldoc } = do - lnames' <- mapM renameNameL lnames - bndrs' <- mapM renameOuterTyVarBndrs bndrs - lcontext' <- traverse renameLContext lcontext - details' <- renameGADTDetails details - res_ty' <- renameLType res_ty - mbldoc' <- mapM renameLDocHsSyn mbldoc - return (ConDeclGADT - { con_g_ext = noExtField, con_names = lnames' - , con_bndrs = bndrs' - , con_mb_cxt = lcontext', con_g_args = details' - , con_res_ty = res_ty', con_doc = mbldoc' }) - -renameHsScaled :: HsScaled GhcRn (LHsType GhcRn) - -> RnM (HsScaled DocNameI (LHsType DocNameI)) +renameCon + decl@( ConDeclH98 + { con_name = lname + , con_ex_tvs = ltyvars + , con_mb_cxt = lcontext + , con_args = details + , con_doc = mbldoc + , con_forall = forall_ + } + ) = do + lname' <- renameNameL lname + ltyvars' <- mapM (renameLTyVarBndr return) ltyvars + lcontext' <- traverse renameLContext lcontext + details' <- renameH98Details details + mbldoc' <- mapM (renameLDocHsSyn) mbldoc + return + ( decl + { con_ext = noExtField + , con_name = lname' + , con_ex_tvs = ltyvars' + , con_mb_cxt = lcontext' + , con_forall = forall_ -- Remove when #18311 is fixed + , con_args = details' + , con_doc = mbldoc' + } + ) +renameCon + ConDeclGADT + { con_names = lnames + , con_bndrs = bndrs + , con_mb_cxt = lcontext + , con_g_args = details + , con_res_ty = res_ty + , con_doc = mbldoc + } = do + lnames' <- mapM renameNameL lnames + bndrs' <- mapM renameOuterTyVarBndrs bndrs + lcontext' <- traverse renameLContext lcontext + details' <- renameGADTDetails details + res_ty' <- renameLType res_ty + mbldoc' <- mapM renameLDocHsSyn mbldoc + return + ( ConDeclGADT + { con_g_ext = noExtField + , con_names = lnames' + , con_bndrs = bndrs' + , con_mb_cxt = lcontext' + , con_g_args = details' + , con_res_ty = res_ty' + , con_doc = mbldoc' + } + ) + +renameHsScaled + :: HsScaled GhcRn (LHsType GhcRn) + -> RnM (HsScaled DocNameI (LHsType DocNameI)) renameHsScaled (HsScaled w ty) = HsScaled <$> renameArrow w <*> renameLType ty -renameH98Details :: HsConDeclH98Details GhcRn - -> RnM (HsConDeclH98Details DocNameI) +renameH98Details + :: HsConDeclH98Details GhcRn + -> RnM (HsConDeclH98Details DocNameI) renameH98Details (RecCon (L l fields)) = do fields' <- mapM renameConDeclFieldField fields return (RecCon (L (locA l) fields')) @@ -648,8 +729,9 @@ renameH98Details (InfixCon a b) = do b' <- renameHsScaled b return (InfixCon a' b') -renameGADTDetails :: HsConDeclGADTDetails GhcRn - -> RnM (HsConDeclGADTDetails DocNameI) +renameGADTDetails + :: HsConDeclGADTDetails GhcRn + -> RnM (HsConDeclGADTDetails DocNameI) renameGADTDetails (RecConGADT _ (L l fields)) = do fields' <- mapM renameConDeclFieldField fields return (RecConGADT noExtField (L (locA l) fields')) @@ -658,7 +740,7 @@ renameGADTDetails (PrefixConGADT _ ps) = PrefixConGADT noExtField <$> mapM renam renameConDeclFieldField :: LConDeclField GhcRn -> RnM (LConDeclField DocNameI) renameConDeclFieldField (L l (ConDeclField _ names t doc)) = do names' <- mapM renameLFieldOcc names - t' <- renameLType t + t' <- renameLType t doc' <- mapM renameLDocHsSyn doc return $ L (locA l) (ConDeclField noExtField names' t' doc') @@ -690,7 +772,6 @@ renameSig sig = case sig of -- we have filtered out all other kinds of signatures in Interface.Create _ -> error "expected TypeSig" - renameForD :: ForeignDecl GhcRn -> RnM (ForeignDecl DocNameI) renameForD (ForeignImport _ lname ltype x) = do lname' <- renameNameL lname @@ -707,107 +788,156 @@ renameForI (CImport _ cconv safety mHeader spec) = CImport noExtField cconv safe renameForE :: ForeignExport GhcRn -> ForeignExport DocNameI renameForE (CExport _ spec) = CExport noExtField spec - renameInstD :: InstDecl GhcRn -> RnM (InstDecl DocNameI) -renameInstD (ClsInstD { cid_inst = d }) = do +renameInstD (ClsInstD{cid_inst = d}) = do d' <- renameClsInstD d - return (ClsInstD { cid_d_ext = noExtField, cid_inst = d' }) -renameInstD (TyFamInstD { tfid_inst = d }) = do + return (ClsInstD{cid_d_ext = noExtField, cid_inst = d'}) +renameInstD (TyFamInstD{tfid_inst = d}) = do d' <- renameTyFamInstD d - return (TyFamInstD { tfid_ext = noExtField, tfid_inst = d' }) -renameInstD (DataFamInstD { dfid_inst = d }) = do + return (TyFamInstD{tfid_ext = noExtField, tfid_inst = d'}) +renameInstD (DataFamInstD{dfid_inst = d}) = do d' <- renameDataFamInstD d - return (DataFamInstD { dfid_ext = noExtField, dfid_inst = d' }) + return (DataFamInstD{dfid_ext = noExtField, dfid_inst = d'}) renameDerivD :: DerivDecl GhcRn -> RnM (DerivDecl DocNameI) -renameDerivD (DerivDecl { deriv_type = ty - , deriv_strategy = strat - , deriv_overlap_mode = omode }) = do - ty' <- renameLSigWcType ty - strat' <- mapM (mapM renameDerivStrategy) strat - return (DerivDecl { deriv_ext = noExtField - , deriv_type = ty' - , deriv_strategy = strat' - , deriv_overlap_mode = omode }) +renameDerivD + ( DerivDecl + { deriv_type = ty + , deriv_strategy = strat + , deriv_overlap_mode = omode + } + ) = do + ty' <- renameLSigWcType ty + strat' <- mapM (mapM renameDerivStrategy) strat + return + ( DerivDecl + { deriv_ext = noExtField + , deriv_type = ty' + , deriv_strategy = strat' + , deriv_overlap_mode = omode + } + ) renameDerivStrategy :: DerivStrategy GhcRn -> RnM (DerivStrategy DocNameI) -renameDerivStrategy (StockStrategy a) = pure (StockStrategy a) +renameDerivStrategy (StockStrategy a) = pure (StockStrategy a) renameDerivStrategy (AnyclassStrategy a) = pure (AnyclassStrategy a) -renameDerivStrategy (NewtypeStrategy a) = pure (NewtypeStrategy a) -renameDerivStrategy (ViaStrategy ty) = ViaStrategy <$> renameLSigType ty +renameDerivStrategy (NewtypeStrategy a) = pure (NewtypeStrategy a) +renameDerivStrategy (ViaStrategy ty) = ViaStrategy <$> renameLSigType ty renameClsInstD :: ClsInstDecl GhcRn -> RnM (ClsInstDecl DocNameI) -renameClsInstD (ClsInstDecl { cid_overlap_mode = omode - , cid_poly_ty =ltype, cid_tyfam_insts = lATs - , cid_datafam_insts = lADTs }) = do - ltype' <- renameLSigType ltype - lATs' <- mapM (mapM renameTyFamInstD) lATs - lADTs' <- mapM (mapM renameDataFamInstD) lADTs - return (ClsInstDecl { cid_ext = noExtField, cid_overlap_mode = omode - , cid_poly_ty = ltype', cid_binds = emptyBag - , cid_sigs = [] - , cid_tyfam_insts = lATs', cid_datafam_insts = lADTs' }) - +renameClsInstD + ( ClsInstDecl + { cid_overlap_mode = omode + , cid_poly_ty = ltype + , cid_tyfam_insts = lATs + , cid_datafam_insts = lADTs + } + ) = do + ltype' <- renameLSigType ltype + lATs' <- mapM (mapM renameTyFamInstD) lATs + lADTs' <- mapM (mapM renameDataFamInstD) lADTs + return + ( ClsInstDecl + { cid_ext = noExtField + , cid_overlap_mode = omode + , cid_poly_ty = ltype' + , cid_binds = emptyBag + , cid_sigs = [] + , cid_tyfam_insts = lATs' + , cid_datafam_insts = lADTs' + } + ) renameTyFamInstD :: TyFamInstDecl GhcRn -> RnM (TyFamInstDecl DocNameI) -renameTyFamInstD (TyFamInstDecl { tfid_eqn = eqn }) - = do { eqn' <- renameTyFamInstEqn eqn - ; return (TyFamInstDecl { tfid_xtn = noExtField, tfid_eqn = eqn' }) } +renameTyFamInstD (TyFamInstDecl{tfid_eqn = eqn}) = + do + eqn' <- renameTyFamInstEqn eqn + return (TyFamInstDecl{tfid_xtn = noExtField, tfid_eqn = eqn'}) renameTyFamInstEqn :: TyFamInstEqn GhcRn -> RnM (TyFamInstEqn DocNameI) -renameTyFamInstEqn (FamEqn { feqn_tycon = tc, feqn_bndrs = bndrs - , feqn_pats = pats, feqn_fixity = fixity - , feqn_rhs = rhs }) - = do { tc' <- renameNameL tc - ; bndrs' <- renameOuterTyVarBndrs bndrs - ; pats' <- mapM renameLTypeArg pats - ; rhs' <- renameLType rhs - ; return (FamEqn { feqn_ext = noExtField - , feqn_tycon = tc' - , feqn_bndrs = bndrs' - , feqn_pats = pats' - , feqn_fixity = fixity - , feqn_rhs = rhs' }) } +renameTyFamInstEqn + ( FamEqn + { feqn_tycon = tc + , feqn_bndrs = bndrs + , feqn_pats = pats + , feqn_fixity = fixity + , feqn_rhs = rhs + } + ) = + do + tc' <- renameNameL tc + bndrs' <- renameOuterTyVarBndrs bndrs + pats' <- mapM renameLTypeArg pats + rhs' <- renameLType rhs + return + ( FamEqn + { feqn_ext = noExtField + , feqn_tycon = tc' + , feqn_bndrs = bndrs' + , feqn_pats = pats' + , feqn_fixity = fixity + , feqn_rhs = rhs' + } + ) renameTyFamDefltD :: TyFamDefltDecl GhcRn -> RnM (TyFamDefltDecl DocNameI) renameTyFamDefltD = renameTyFamInstD renameDataFamInstD :: DataFamInstDecl GhcRn -> RnM (DataFamInstDecl DocNameI) -renameDataFamInstD (DataFamInstDecl { dfid_eqn = eqn }) - = do { eqn' <- rename_data_fam_eqn eqn - ; return (DataFamInstDecl { dfid_eqn = eqn' }) } +renameDataFamInstD (DataFamInstDecl{dfid_eqn = eqn}) = + do + eqn' <- rename_data_fam_eqn eqn + return (DataFamInstDecl{dfid_eqn = eqn'}) where rename_data_fam_eqn :: FamEqn GhcRn (HsDataDefn GhcRn) -> RnM (FamEqn DocNameI (HsDataDefn DocNameI)) - rename_data_fam_eqn (FamEqn { feqn_tycon = tc, feqn_bndrs = bndrs - , feqn_pats = pats, feqn_fixity = fixity - , feqn_rhs = defn }) - = do { tc' <- renameNameL tc - ; bndrs' <- renameOuterTyVarBndrs bndrs - ; pats' <- mapM renameLTypeArg pats - ; defn' <- renameDataDefn defn - ; return (FamEqn { feqn_ext = noExtField - , feqn_tycon = tc' - , feqn_bndrs = bndrs' - , feqn_pats = pats' - , feqn_fixity = fixity - , feqn_rhs = defn' }) } - -renameOuterTyVarBndrs :: HsOuterTyVarBndrs flag GhcRn - -> RnM (HsOuterTyVarBndrs flag DocNameI) + rename_data_fam_eqn + ( FamEqn + { feqn_tycon = tc + , feqn_bndrs = bndrs + , feqn_pats = pats + , feqn_fixity = fixity + , feqn_rhs = defn + } + ) = + do + tc' <- renameNameL tc + bndrs' <- renameOuterTyVarBndrs bndrs + pats' <- mapM renameLTypeArg pats + defn' <- renameDataDefn defn + return + ( FamEqn + { feqn_ext = noExtField + , feqn_tycon = tc' + , feqn_bndrs = bndrs' + , feqn_pats = pats' + , feqn_fixity = fixity + , feqn_rhs = defn' + } + ) + +renameOuterTyVarBndrs + :: HsOuterTyVarBndrs flag GhcRn + -> RnM (HsOuterTyVarBndrs flag DocNameI) renameOuterTyVarBndrs (HsOuterImplicit{}) = pure $ HsOuterImplicit{hso_ximplicit = noExtField} renameOuterTyVarBndrs (HsOuterExplicit{hso_bndrs = exp_bndrs}) = HsOuterExplicit noExtField <$> mapM (renameLTyVarBndr return) exp_bndrs -renameWc :: (in_thing -> RnM out_thing) - -> HsWildCardBndrs GhcRn in_thing - -> RnM (HsWildCardBndrs DocNameI out_thing) -renameWc rn_thing (HsWC { hswc_body = thing }) - = do { thing' <- rn_thing thing - ; return (HsWC { hswc_body = thing' - , hswc_ext = noExtField }) } +renameWc + :: (in_thing -> RnM out_thing) + -> HsWildCardBndrs GhcRn in_thing + -> RnM (HsWildCardBndrs DocNameI out_thing) +renameWc rn_thing (HsWC{hswc_body = thing}) = + do + thing' <- rn_thing thing + return + ( HsWC + { hswc_body = thing' + , hswc_ext = noExtField + } + ) renameDocInstance :: DocInstance GhcRn -> RnM (DocInstance DocNameI) renameDocInstance (inst, idoc, L l n, m) = do @@ -817,7 +947,7 @@ renameDocInstance (inst, idoc, L l n, m) = do return (inst', idoc', L l n', m) renameSub :: (Name, DocForDecl Name) -> RnM (DocName, DocForDecl DocName) -renameSub (n,doc) = do +renameSub (n, doc) = do n' <- renameName n doc' <- renameDocForDecl doc return (n', doc') diff --git a/haddock-api/src/Haddock/Interface/RenameType.hs b/haddock-api/src/Haddock/Interface/RenameType.hs index 64b3de7f76..fb6905ce9e 100644 --- a/haddock-api/src/Haddock/Interface/RenameType.hs +++ b/haddock-api/src/Haddock/Interface/RenameType.hs @@ -1,28 +1,27 @@ {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GADTs #-} {-# LANGUAGE Rank2Types #-} +{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE GADTs #-} {-# OPTIONS_GHC -Wno-incomplete-record-updates #-} module Haddock.Interface.RenameType - ( rename - ) where - + ( rename + ) where import Haddock.Types import GHC -import GHC.Types.Name import GHC.Data.FastString +import GHC.Types.Name import Control.Monad.Trans.State import qualified Data.List as List -import Data.Maybe import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map +import Data.Maybe import Data.Set (Set) import qualified Data.Set as Set @@ -38,12 +37,11 @@ import qualified Data.Set as Set -- since it is stored mostly in 'Set', fast comparison of 'FastString' is also -- quite nice. newtype NameRep - = NameRep FastString - deriving (Eq) + = NameRep FastString + deriving (Eq) instance Ord NameRep where - compare (NameRep fs1) (NameRep fs2) = uniqCompareFS fs1 fs2 - + compare (NameRep fs1) (NameRep fs2) = uniqCompareFS fs1 fs2 getNameRep :: NamedThing name => name -> NameRep getNameRep = NameRep . getOccFS @@ -59,7 +57,7 @@ setInternalNameRep (NameRep fs) = setInternalOccName (mkVarOccFS fs) setInternalOccName :: SetName name => OccName -> name -> name setInternalOccName occ name = - setName nname' name + setName nname' name where nname = getName name nname' = mkInternalName (nameUnique nname) occ (nameSrcSpan nname) @@ -76,10 +74,11 @@ rename :: [Name] -> LHsType GhcRn -> LHsType GhcRn rename [] typ = typ rename fv typ = evalState (traverse renameType typ) env where - env = RenameEnv - { rneHeadFVs = Map.fromList $ map mkPair fv - , rneCtx = Map.empty - } + env = + RenameEnv + { rneHeadFVs = Map.fromList $ map mkPair fv + , rneCtx = Map.empty + } mkPair name = (getNameRep name, name) -- | Renaming monad. @@ -90,16 +89,15 @@ data RenameEnv name = RenameEnv , rneCtx :: Map Name name } - renameType :: HsType GhcRn -> Rename (IdP GhcRn) (HsType GhcRn) renameType (HsForAllTy x tele lt) = - HsForAllTy x - <$> renameForAllTelescope tele - <*> renameLType lt + HsForAllTy x + <$> renameForAllTelescope tele + <*> renameLType lt renameType (HsQualTy x lctxt lt) = - HsQualTy x - <$> renameLContext lctxt - <*> renameLType lt + HsQualTy x + <$> renameLContext lctxt + <*> renameLType lt renameType (HsTyVar x ip name) = HsTyVar x ip <$> locatedN renameName name renameType t@(HsStarTy _ _) = pure t renameType (HsAppTy x lf la) = HsAppTy x <$> renameLType lf <*> renameLType la @@ -109,7 +107,7 @@ renameType (HsListTy x lt) = HsListTy x <$> renameLType lt renameType (HsTupleTy x srt lt) = HsTupleTy x srt <$> mapM renameLType lt renameType (HsSumTy x lt) = HsSumTy x <$> mapM renameLType lt renameType (HsOpTy x f la lop lb) = - HsOpTy x <$> pure f <*> renameLType la <*> locatedN renameName lop <*> renameLType lb + HsOpTy x <$> pure f <*> renameLType la <*> locatedN renameName lop <*> renameLType lb renameType (HsParTy x lt) = HsParTy x <$> renameLType lt renameType (HsIParamTy x ip lt) = HsIParamTy x ip <$> renameLType lt renameType (HsKindSig x lt lk) = HsKindSig x <$> renameLType lt <*> pure lk @@ -119,9 +117,9 @@ renameType (HsBangTy x bang lt) = HsBangTy x bang <$> renameLType lt renameType t@(HsRecTy _ _) = pure t renameType t@(XHsType _) = pure t renameType (HsExplicitListTy x ip ltys) = - HsExplicitListTy x ip <$> renameLTypes ltys + HsExplicitListTy x ip <$> renameLTypes ltys renameType (HsExplicitTupleTy x ltys) = - HsExplicitTupleTy x <$> renameLTypes ltys + HsExplicitTupleTy x <$> renameLTypes ltys renameType t@(HsTyLit _ _) = pure t renameType (HsWildCardTy wc) = pure (HsWildCardTy wc) @@ -129,7 +127,6 @@ renameHsArrow :: HsArrow GhcRn -> Rename (IdP GhcRn) (HsArrow GhcRn) renameHsArrow (HsExplicitMult x p) = HsExplicitMult x <$> renameLType p renameHsArrow mult = pure mult - renameLType :: LHsType GhcRn -> Rename (IdP GhcRn) (LHsType GhcRn) renameLType = located renameType @@ -147,8 +144,9 @@ renameLContext (L l ctxt) = do renameContext :: HsContext GhcRn -> Rename (IdP GhcRn) (HsContext GhcRn) renameContext = renameLTypes -renameForAllTelescope :: HsForAllTelescope GhcRn - -> Rename (IdP GhcRn) (HsForAllTelescope GhcRn) +renameForAllTelescope + :: HsForAllTelescope GhcRn + -> Rename (IdP GhcRn) (HsForAllTelescope GhcRn) renameForAllTelescope (HsForAllVis x bndrs) = HsForAllVis x <$> mapM renameLBinder bndrs renameForAllTelescope (HsForAllInvis x bndrs) = @@ -165,51 +163,49 @@ renameLBinder = located renameBinder -- | Core renaming logic. renameName :: SetName name => name -> Rename name name renameName name = do - RenameEnv { .. } <- get - case Map.lookup (getName name) rneCtx of - Nothing - | Just headTv <- Map.lookup (getNameRep name) rneHeadFVs - , headTv /= getName name -> freshName name - Just name' -> return name' - _ -> return name - + RenameEnv{..} <- get + case Map.lookup (getName name) rneCtx of + Nothing + | Just headTv <- Map.lookup (getNameRep name) rneHeadFVs + , headTv /= getName name -> + freshName name + Just name' -> return name' + _ -> return name -- | Generate fresh occurrence name, put it into context and return. freshName :: SetName name => name -> Rename name name freshName name = do - taken <- takenNames - let name' = setInternalNameRep (findFreshName taken rep) name - modify $ \rne -> rne - { rneCtx = Map.insert (getName name) name' (rneCtx rne) } - return name' + taken <- takenNames + let name' = setInternalNameRep (findFreshName taken rep) name + modify $ \rne -> + rne + { rneCtx = Map.insert (getName name) name' (rneCtx rne) + } + return name' where nname = getName name rep = getNameRep nname - takenNames :: NamedThing name => Rename name (Set NameRep) takenNames = do - RenameEnv { .. } <- get - return $ Set.unions [headReps rneHeadFVs, ctxElems rneCtx] + RenameEnv{..} <- get + return $ Set.unions [headReps rneHeadFVs, ctxElems rneCtx] where headReps = Set.fromList . Map.keys ctxElems = Set.fromList . map getNameRep . Map.elems - findFreshName :: Set NameRep -> NameRep -> NameRep findFreshName taken = - fromJust . List.find isFresh . alternativeNames + fromJust . List.find isFresh . alternativeNames where isFresh = not . flip Set.member taken - alternativeNames :: NameRep -> [NameRep] alternativeNames name = - [ stringNameRep $ str ++ show i | i :: Int <- [0..] ] + [stringNameRep $ str ++ show i | i :: Int <- [0 ..]] where str = nameRepString name - located :: Functor f => (a -> f b) -> GenLocated l a -> f (GenLocated l b) located f (L loc e) = L loc <$> f e diff --git a/haddock-api/src/Haddock/InterfaceFile.hs b/haddock-api/src/Haddock/InterfaceFile.hs index d15630508c..fd90dcaf33 100644 --- a/haddock-api/src/Haddock/InterfaceFile.hs +++ b/haddock-api/src/Haddock/InterfaceFile.hs @@ -1,11 +1,15 @@ +{-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-} +{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE BangPatterns #-} -{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE TypeApplications #-} {-# OPTIONS_GHC -fno-warn-orphans #-} + ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.InterfaceFile -- Copyright : (c) David Waern 2006-2009, @@ -17,88 +21,96 @@ -- Portability : portable -- -- Reading and writing the .haddock interface file ------------------------------------------------------------------------------ -module Haddock.InterfaceFile ( - InterfaceFile(..), PackageInfo(..), ifUnitId, ifModule, - PackageInterfaces(..), mkPackageInterfaces, ppPackageInfo, - readInterfaceFile, writeInterfaceFile, - freshNameCache, - binaryInterfaceVersion, binaryInterfaceVersionCompatibility -) where - +module Haddock.InterfaceFile + ( InterfaceFile (..) + , PackageInfo (..) + , ifUnitId + , ifModule + , PackageInterfaces (..) + , mkPackageInterfaces + , ppPackageInfo + , readInterfaceFile + , writeInterfaceFile + , freshNameCache + , binaryInterfaceVersion + , binaryInterfaceVersionCompatibility + ) where import Haddock.Types -import Data.IORef import Data.Function ((&)) -import qualified Data.Map as Map +import Data.IORef import Data.Map (Map) +import qualified Data.Map as Map import Data.Version import Data.Word import Text.ParserCombinators.ReadP (readP_to_S) -import GHC.Iface.Binary (getWithUserData, putSymbolTable) -import GHC.Unit.State -import GHC.Utils.Binary +import GHC hiding (NoLink) import GHC.Data.FastMutInt import GHC.Data.FastString -import GHC hiding (NoLink) +import GHC.Iface.Binary (getWithUserData, putSymbolTable) import GHC.Types.Name.Cache -import GHC.Types.Unique.FM import GHC.Types.Unique +import GHC.Types.Unique.FM +import GHC.Unit.State +import GHC.Utils.Binary -import GHC.Iface.Type (IfaceType, putIfaceType, getIfaceType) +import GHC.Iface.Type (IfaceType, getIfaceType, putIfaceType) import Haddock.Options (Visibility (..)) -data InterfaceFile = InterfaceFile { - ifLinkEnv :: LinkEnv, - -- | Package meta data. Currently it only consist of a package name, which +data InterfaceFile = InterfaceFile + { ifLinkEnv :: LinkEnv + , ifPackageInfo :: PackageInfo + -- ^ Package meta data. Currently it only consist of a package name, which -- is not read from the interface file, but inferred from its name. -- -- issue # - ifPackageInfo :: PackageInfo, - ifInstalledIfaces :: [InstalledInterface] -} + , ifInstalledIfaces :: [InstalledInterface] + } -data PackageInfo = PackageInfo { - piPackageName :: PackageName, - piPackageVersion :: Data.Version.Version -} +data PackageInfo = PackageInfo + { piPackageName :: PackageName + , piPackageVersion :: Data.Version.Version + } ppPackageInfo :: PackageInfo -> String -ppPackageInfo (PackageInfo name version) | version == makeVersion [] - = unpackFS (unPackageName name) +ppPackageInfo (PackageInfo name version) + | version == makeVersion [] = + unpackFS (unPackageName name) ppPackageInfo (PackageInfo name version) = unpackFS (unPackageName name) ++ "-" ++ showVersion version -data PackageInterfaces = PackageInterfaces { - piPackageInfo :: PackageInfo, - piVisibility :: Visibility, - piInstalledInterfaces :: [InstalledInterface] -} +data PackageInterfaces = PackageInterfaces + { piPackageInfo :: PackageInfo + , piVisibility :: Visibility + , piInstalledInterfaces :: [InstalledInterface] + } mkPackageInterfaces :: Visibility -> InterfaceFile -> PackageInterfaces -mkPackageInterfaces piVisibility - InterfaceFile { ifPackageInfo - , ifInstalledIfaces - } = - PackageInterfaces { piPackageInfo = ifPackageInfo - , piVisibility - , piInstalledInterfaces = ifInstalledIfaces - } +mkPackageInterfaces + piVisibility + InterfaceFile + { ifPackageInfo + , ifInstalledIfaces + } = + PackageInterfaces + { piPackageInfo = ifPackageInfo + , piVisibility + , piInstalledInterfaces = ifInstalledIfaces + } ifModule :: InterfaceFile -> Module ifModule if_ = case ifInstalledIfaces if_ of [] -> error "empty InterfaceFile" - iface:_ -> instMod iface + iface : _ -> instMod iface ifUnitId :: InterfaceFile -> Unit ifUnitId if_ = case ifInstalledIfaces if_ of [] -> error "empty InterfaceFile" - iface:_ -> moduleUnit $ instMod iface - + iface : _ -> moduleUnit $ instMod iface binaryInterfaceMagic :: Word32 binaryInterfaceMagic = 0xD0Cface @@ -138,10 +150,8 @@ binaryInterfaceVersionCompatibility = [binaryInterfaceVersion] #error Unsupported GHC version #endif - initBinMemSize :: Int -initBinMemSize = 1024*1024 - +initBinMemSize = 1024 * 1024 writeInterfaceFile :: FilePath -> InterfaceFile -> IO () writeInterfaceFile filename iface = do @@ -164,23 +174,28 @@ writeInterfaceFile filename iface = do -- Make some intial state symtab_next <- newFastMutInt 0 symtab_map <- newIORef emptyUFM - let bin_symtab = BinSymbolTable { - bin_symtab_next = symtab_next, - bin_symtab_map = symtab_map } + let bin_symtab = + BinSymbolTable + { bin_symtab_next = symtab_next + , bin_symtab_map = symtab_map + } dict_next_ref <- newFastMutInt 0 dict_map_ref <- newIORef emptyUFM - let bin_dict = BinDictionary { - bin_dict_next = dict_next_ref, - bin_dict_map = dict_map_ref } + let bin_dict = + BinDictionary + { bin_dict_next = dict_next_ref + , bin_dict_map = dict_map_ref + } iface_type_dict <- initGenericSymbolTable @(Map IfaceType) -- put the main thing - let bh = bh0 - & addWriterToUserData (mkWriter $ putName bin_symtab) - & addWriterToUserData (simpleBindingNameWriter $ mkWriter $ putName bin_symtab) - & addWriterToUserData (mkWriter $ putFastString bin_dict) - & addWriterToUserData (mkWriter $ putGenericSymTab iface_type_dict) + let bh = + bh0 + & addWriterToUserData (mkWriter $ putName bin_symtab) + & addWriterToUserData (simpleBindingNameWriter $ mkWriter $ putName bin_symtab) + & addWriterToUserData (mkWriter $ putFastString bin_dict) + & addWriterToUserData (mkWriter $ putGenericSymTab iface_type_dict) putInterfaceFile_ bh iface -- write the iface type pointer at the front of the file @@ -198,7 +213,7 @@ writeInterfaceFile filename iface = do -- write the symbol table itself symtab_next' <- readFastMutInt symtab_next - symtab_map' <- readIORef symtab_map + symtab_map' <- readIORef symtab_map putSymbolTable bh symtab_next' symtab_map' -- write the dictionary pointer at the fornt of the file @@ -208,17 +223,18 @@ writeInterfaceFile filename iface = do -- write the dictionary itself dict_next <- readFastMutInt dict_next_ref - dict_map <- readIORef dict_map_ref + dict_map <- readIORef dict_map_ref putDictionary bh dict_next dict_map -- and send the result to the file writeBinMem bh filename return () - freshNameCache :: IO NameCache -freshNameCache = initNameCache 'a' -- ?? - [] +freshNameCache = + initNameCache + 'a' -- ?? + [] -- | Read a Haddock (@.haddock@) interface file. Return either an -- 'InterfaceFile' or an error message. @@ -226,10 +242,12 @@ freshNameCache = initNameCache 'a' -- ?? -- This function can be called in two ways. Within a GHC session it will -- update the use and update the session's name cache. Outside a GHC session -- a new empty name cache is used. -readInterfaceFile :: NameCache - -> FilePath - -> Bool -- ^ Disable version check. Can cause runtime crash. - -> IO (Either String InterfaceFile) +readInterfaceFile + :: NameCache + -> FilePath + -> Bool + -- ^ Disable version check. Can cause runtime crash. + -> IO (Either String InterfaceFile) readInterfaceFile name_cache filename bypass_checks = do bh <- readBinMem filename magic <- get bh @@ -242,65 +260,73 @@ readInterfaceFile name_cache filename bypass_checks = do else Right <$> getWithUserData name_cache bh ------------------------------------------------------------------------------- + -- * Symbol table -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- putName :: BinSymbolTable -> WriteBinHandle -> Name -> IO () -putName BinSymbolTable{ - bin_symtab_map = symtab_map_ref, - bin_symtab_next = symtab_next } bh name - = do - symtab_map <- readIORef symtab_map_ref - case lookupUFM symtab_map name of - Just (off,_) -> put_ bh (fromIntegral off :: Word32) - Nothing -> do - off <- readFastMutInt symtab_next - writeFastMutInt symtab_next (off+1) - writeIORef symtab_map_ref - $! addToUFM symtab_map name (off,name) - put_ bh (fromIntegral off :: Word32) - - -data BinSymbolTable = BinSymbolTable { - bin_symtab_next :: !FastMutInt, -- The next index to use - bin_symtab_map :: !(IORef (UniqFM Name (Int,Name))) - -- indexed by Name +putName + BinSymbolTable + { bin_symtab_map = symtab_map_ref + , bin_symtab_next = symtab_next + } + bh + name = + do + symtab_map <- readIORef symtab_map_ref + case lookupUFM symtab_map name of + Just (off, _) -> put_ bh (fromIntegral off :: Word32) + Nothing -> do + off <- readFastMutInt symtab_next + writeFastMutInt symtab_next (off + 1) + writeIORef symtab_map_ref $! + addToUFM symtab_map name (off, name) + put_ bh (fromIntegral off :: Word32) + +data BinSymbolTable = BinSymbolTable + { bin_symtab_next :: !FastMutInt -- The next index to use + , bin_symtab_map :: !(IORef (UniqFM Name (Int, Name))) + -- indexed by Name } - putFastString :: BinDictionary -> WriteBinHandle -> FastString -> IO () -putFastString BinDictionary { bin_dict_next = j_r, - bin_dict_map = out_r} bh f - = do - out <- readIORef out_r - let !unique = getUnique f - case lookupUFM_Directly out unique of - Just (j, _) -> put_ bh (fromIntegral j :: Word32) +putFastString + BinDictionary + { bin_dict_next = j_r + , bin_dict_map = out_r + } + bh + f = + do + out <- readIORef out_r + let !unique = getUnique f + case lookupUFM_Directly out unique of + Just (j, _) -> put_ bh (fromIntegral j :: Word32) Nothing -> do - j <- readFastMutInt j_r - put_ bh (fromIntegral j :: Word32) - writeFastMutInt j_r (j + 1) - writeIORef out_r $! addToUFM_Directly out unique (j, f) - - -data BinDictionary = BinDictionary { - bin_dict_next :: !FastMutInt, -- The next index to use - bin_dict_map :: !(IORef (UniqFM FastString (Int,FastString))) - -- indexed by FastString + j <- readFastMutInt j_r + put_ bh (fromIntegral j :: Word32) + writeFastMutInt j_r (j + 1) + writeIORef out_r $! addToUFM_Directly out unique (j, f) + +data BinDictionary = BinDictionary + { bin_dict_next :: !FastMutInt -- The next index to use + , bin_dict_map :: !(IORef (UniqFM FastString (Int, FastString))) + -- indexed by FastString } ------------------------------------------------------------------------------- + -- * GhcBinary instances -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- instance (Ord k, Binary k, Binary v) => Binary (Map k v) where put_ bh m = put_ bh (Map.toList m) get bh = fmap (Map.fromList) (get bh) instance Binary PackageInfo where - put_ bh PackageInfo { piPackageName, piPackageVersion } = do + put_ bh PackageInfo{piPackageName, piPackageVersion} = do put_ bh (unPackageName piPackageName) put_ bh (showVersion piPackageVersion) get bh = do @@ -318,12 +344,11 @@ instance Binary InterfaceFile where put_ bh ifaces get bh = do - env <- get bh - info <- get bh + env <- get bh + info <- get bh ifaces <- get bh return (InterfaceFile env info ifaces) - putInterfaceFile_ :: WriteBinHandle -> InterfaceFile -> IO () putInterfaceFile_ bh (InterfaceFile env info ifaces) = do put_ bh env @@ -331,327 +356,351 @@ putInterfaceFile_ bh (InterfaceFile env info ifaces) = do put_ bh ifaces instance Binary InstalledInterface where - put_ bh (InstalledInterface modu is_sig info docMap argMap defMeths - exps visExps opts fixMap) = do - put_ bh modu - put_ bh is_sig - put_ bh info - lazyPut bh (docMap, argMap) - put_ bh defMeths - put_ bh exps - put_ bh visExps - put_ bh opts - put_ bh fixMap + put_ + bh + ( InstalledInterface + modu + is_sig + info + docMap + argMap + defMeths + exps + visExps + opts + fixMap + ) = do + put_ bh modu + put_ bh is_sig + put_ bh info + lazyPut bh (docMap, argMap) + put_ bh defMeths + put_ bh exps + put_ bh visExps + put_ bh opts + put_ bh fixMap get bh = do - modu <- get bh - is_sig <- get bh - info <- get bh + modu <- get bh + is_sig <- get bh + info <- get bh ~(docMap, argMap) <- lazyGet bh defMeths <- get bh - exps <- get bh + exps <- get bh visExps <- get bh - opts <- get bh - fixMap <- get bh - return (InstalledInterface modu is_sig info - docMap argMap defMeths exps visExps opts fixMap) + opts <- get bh + fixMap <- get bh + return + ( InstalledInterface + modu + is_sig + info + docMap + argMap + defMeths + exps + visExps + opts + fixMap + ) instance Binary DocOption where - put_ bh OptHide = do - putByte bh 0 - put_ bh OptPrune = do - putByte bh 1 - put_ bh OptIgnoreExports = do - putByte bh 2 - put_ bh OptNotHome = do - putByte bh 3 - put_ bh OptShowExtensions = do - putByte bh 4 - put_ bh OptPrintRuntimeRep = do - putByte bh 5 - get bh = do - h <- getByte bh - case h of - 0 -> do - return OptHide - 1 -> do - return OptPrune - 2 -> do - return OptIgnoreExports - 3 -> do - return OptNotHome - 4 -> do - return OptShowExtensions - 5 -> do - return OptPrintRuntimeRep - n -> fail $ "invalid binary data found: " <> show n + put_ bh OptHide = do + putByte bh 0 + put_ bh OptPrune = do + putByte bh 1 + put_ bh OptIgnoreExports = do + putByte bh 2 + put_ bh OptNotHome = do + putByte bh 3 + put_ bh OptShowExtensions = do + putByte bh 4 + put_ bh OptPrintRuntimeRep = do + putByte bh 5 + get bh = do + h <- getByte bh + case h of + 0 -> do + return OptHide + 1 -> do + return OptPrune + 2 -> do + return OptIgnoreExports + 3 -> do + return OptNotHome + 4 -> do + return OptShowExtensions + 5 -> do + return OptPrintRuntimeRep + n -> fail $ "invalid binary data found: " <> show n instance Binary Example where - put_ bh (Example expression result) = do - put_ bh expression - put_ bh result - get bh = do - expression <- get bh - result <- get bh - return (Example expression result) + put_ bh (Example expression result) = do + put_ bh expression + put_ bh result + get bh = do + expression <- get bh + result <- get bh + return (Example expression result) instance Binary a => Binary (Hyperlink a) where - put_ bh (Hyperlink url label) = do - put_ bh url - put_ bh label - get bh = do - url <- get bh - label <- get bh - return (Hyperlink url label) + put_ bh (Hyperlink url label) = do + put_ bh url + put_ bh label + get bh = do + url <- get bh + label <- get bh + return (Hyperlink url label) instance Binary a => Binary (ModLink a) where - put_ bh (ModLink m label) = do - put_ bh m - put_ bh label - get bh = do - m <- get bh - label <- get bh - return (ModLink m label) + put_ bh (ModLink m label) = do + put_ bh m + put_ bh label + get bh = do + m <- get bh + label <- get bh + return (ModLink m label) instance Binary Picture where - put_ bh (Picture uri title) = do - put_ bh uri - put_ bh title - get bh = do - uri <- get bh - title <- get bh - return (Picture uri title) + put_ bh (Picture uri title) = do + put_ bh uri + put_ bh title + get bh = do + uri <- get bh + title <- get bh + return (Picture uri title) instance Binary a => Binary (Header a) where - put_ bh (Header l t) = do - put_ bh l - put_ bh t - get bh = do - l <- get bh - t <- get bh - return (Header l t) + put_ bh (Header l t) = do + put_ bh l + put_ bh t + get bh = do + l <- get bh + t <- get bh + return (Header l t) instance Binary a => Binary (Table a) where - put_ bh (Table h b) = do - put_ bh h - put_ bh b - get bh = do - h <- get bh - b <- get bh - return (Table h b) + put_ bh (Table h b) = do + put_ bh h + put_ bh b + get bh = do + h <- get bh + b <- get bh + return (Table h b) instance Binary a => Binary (TableRow a) where - put_ bh (TableRow cs) = put_ bh cs - get bh = do - cs <- get bh - return (TableRow cs) + put_ bh (TableRow cs) = put_ bh cs + get bh = do + cs <- get bh + return (TableRow cs) instance Binary a => Binary (TableCell a) where - put_ bh (TableCell i j c) = do - put_ bh i - put_ bh j - put_ bh c - get bh = do - i <- get bh - j <- get bh - c <- get bh - return (TableCell i j c) + put_ bh (TableCell i j c) = do + put_ bh i + put_ bh j + put_ bh c + get bh = do + i <- get bh + j <- get bh + c <- get bh + return (TableCell i j c) instance Binary Meta where - put_ bh (Meta since) = do - put_ bh since - get bh = do - since <- get bh - return (Meta since) + put_ bh (Meta since) = do + put_ bh since + get bh = do + since <- get bh + return (Meta since) instance Binary MetaSince where - put_ bh (MetaSince v p) = do - put_ bh v - put_ bh p - get bh = do - v <- get bh - p <- get bh - return (MetaSince v p) + put_ bh (MetaSince v p) = do + put_ bh v + put_ bh p + get bh = do + v <- get bh + p <- get bh + return (MetaSince v p) instance (Binary mod, Binary id) => Binary (MetaDoc mod id) where - put_ bh MetaDoc { _meta = m, _doc = d } = do + put_ bh MetaDoc{_meta = m, _doc = d} = do put_ bh m put_ bh d get bh = do m <- get bh d <- get bh - return $ MetaDoc { _meta = m, _doc = d } + return $ MetaDoc{_meta = m, _doc = d} instance (Binary mod, Binary id) => Binary (DocH mod id) where - put_ bh DocEmpty = do - putByte bh 0 - put_ bh (DocAppend aa ab) = do - putByte bh 1 - put_ bh aa - put_ bh ab - put_ bh (DocString ac) = do - putByte bh 2 - put_ bh ac - put_ bh (DocParagraph ad) = do - putByte bh 3 - put_ bh ad - put_ bh (DocIdentifier ae) = do - putByte bh 4 - put_ bh ae - put_ bh (DocEmphasis ag) = do - putByte bh 6 - put_ bh ag - put_ bh (DocMonospaced ah) = do - putByte bh 7 - put_ bh ah - put_ bh (DocUnorderedList ai) = do - putByte bh 8 - put_ bh ai - put_ bh (DocOrderedList aj) = do - putByte bh 9 - put_ bh aj - put_ bh (DocDefList ak) = do - putByte bh 10 - put_ bh ak - put_ bh (DocCodeBlock al) = do - putByte bh 11 - put_ bh al - put_ bh (DocHyperlink am) = do - putByte bh 12 - put_ bh am - put_ bh (DocPic x) = do - putByte bh 13 - put_ bh x - put_ bh (DocAName an) = do - putByte bh 14 - put_ bh an - put_ bh (DocExamples ao) = do - putByte bh 15 - put_ bh ao - put_ bh (DocIdentifierUnchecked x) = do - putByte bh 16 - put_ bh x - put_ bh (DocWarning ag) = do - putByte bh 17 - put_ bh ag - put_ bh (DocProperty x) = do - putByte bh 18 - put_ bh x - put_ bh (DocBold x) = do - putByte bh 19 - put_ bh x - put_ bh (DocHeader aa) = do - putByte bh 20 - put_ bh aa - put_ bh (DocMathInline x) = do - putByte bh 21 - put_ bh x - put_ bh (DocMathDisplay x) = do - putByte bh 22 - put_ bh x - put_ bh (DocTable x) = do - putByte bh 23 - put_ bh x - -- See note [The DocModule story] - put_ bh (DocModule af) = do - putByte bh 24 - put_ bh af - - get bh = do - h <- getByte bh - case h of - 0 -> do - return DocEmpty - 1 -> do - aa <- get bh - ab <- get bh - return (DocAppend aa ab) - 2 -> do - ac <- get bh - return (DocString ac) - 3 -> do - ad <- get bh - return (DocParagraph ad) - 4 -> do - ae <- get bh - return (DocIdentifier ae) - -- See note [The DocModule story] - 5 -> do - af <- get bh - return $ DocModule ModLink - { modLinkName = af - , modLinkLabel = Nothing - } - 6 -> do - ag <- get bh - return (DocEmphasis ag) - 7 -> do - ah <- get bh - return (DocMonospaced ah) - 8 -> do - ai <- get bh - return (DocUnorderedList ai) - 9 -> do - aj <- get bh - return (DocOrderedList aj) - 10 -> do - ak <- get bh - return (DocDefList ak) - 11 -> do - al <- get bh - return (DocCodeBlock al) - 12 -> do - am <- get bh - return (DocHyperlink am) - 13 -> do - x <- get bh - return (DocPic x) - 14 -> do - an <- get bh - return (DocAName an) - 15 -> do - ao <- get bh - return (DocExamples ao) - 16 -> do - x <- get bh - return (DocIdentifierUnchecked x) - 17 -> do - ag <- get bh - return (DocWarning ag) - 18 -> do - x <- get bh - return (DocProperty x) - 19 -> do - x <- get bh - return (DocBold x) - 20 -> do - aa <- get bh - return (DocHeader aa) - 21 -> do - x <- get bh - return (DocMathInline x) - 22 -> do - x <- get bh - return (DocMathDisplay x) - 23 -> do - x <- get bh - return (DocTable x) - -- See note [The DocModule story] - 24 -> do - af <- get bh - return (DocModule af) - _ -> error "invalid binary data found in the interface file" + put_ bh DocEmpty = do + putByte bh 0 + put_ bh (DocAppend aa ab) = do + putByte bh 1 + put_ bh aa + put_ bh ab + put_ bh (DocString ac) = do + putByte bh 2 + put_ bh ac + put_ bh (DocParagraph ad) = do + putByte bh 3 + put_ bh ad + put_ bh (DocIdentifier ae) = do + putByte bh 4 + put_ bh ae + put_ bh (DocEmphasis ag) = do + putByte bh 6 + put_ bh ag + put_ bh (DocMonospaced ah) = do + putByte bh 7 + put_ bh ah + put_ bh (DocUnorderedList ai) = do + putByte bh 8 + put_ bh ai + put_ bh (DocOrderedList aj) = do + putByte bh 9 + put_ bh aj + put_ bh (DocDefList ak) = do + putByte bh 10 + put_ bh ak + put_ bh (DocCodeBlock al) = do + putByte bh 11 + put_ bh al + put_ bh (DocHyperlink am) = do + putByte bh 12 + put_ bh am + put_ bh (DocPic x) = do + putByte bh 13 + put_ bh x + put_ bh (DocAName an) = do + putByte bh 14 + put_ bh an + put_ bh (DocExamples ao) = do + putByte bh 15 + put_ bh ao + put_ bh (DocIdentifierUnchecked x) = do + putByte bh 16 + put_ bh x + put_ bh (DocWarning ag) = do + putByte bh 17 + put_ bh ag + put_ bh (DocProperty x) = do + putByte bh 18 + put_ bh x + put_ bh (DocBold x) = do + putByte bh 19 + put_ bh x + put_ bh (DocHeader aa) = do + putByte bh 20 + put_ bh aa + put_ bh (DocMathInline x) = do + putByte bh 21 + put_ bh x + put_ bh (DocMathDisplay x) = do + putByte bh 22 + put_ bh x + put_ bh (DocTable x) = do + putByte bh 23 + put_ bh x + -- See note [The DocModule story] + put_ bh (DocModule af) = do + putByte bh 24 + put_ bh af + get bh = do + h <- getByte bh + case h of + 0 -> do + return DocEmpty + 1 -> do + aa <- get bh + ab <- get bh + return (DocAppend aa ab) + 2 -> do + ac <- get bh + return (DocString ac) + 3 -> do + ad <- get bh + return (DocParagraph ad) + 4 -> do + ae <- get bh + return (DocIdentifier ae) + -- See note [The DocModule story] + 5 -> do + af <- get bh + return $ + DocModule + ModLink + { modLinkName = af + , modLinkLabel = Nothing + } + 6 -> do + ag <- get bh + return (DocEmphasis ag) + 7 -> do + ah <- get bh + return (DocMonospaced ah) + 8 -> do + ai <- get bh + return (DocUnorderedList ai) + 9 -> do + aj <- get bh + return (DocOrderedList aj) + 10 -> do + ak <- get bh + return (DocDefList ak) + 11 -> do + al <- get bh + return (DocCodeBlock al) + 12 -> do + am <- get bh + return (DocHyperlink am) + 13 -> do + x <- get bh + return (DocPic x) + 14 -> do + an <- get bh + return (DocAName an) + 15 -> do + ao <- get bh + return (DocExamples ao) + 16 -> do + x <- get bh + return (DocIdentifierUnchecked x) + 17 -> do + ag <- get bh + return (DocWarning ag) + 18 -> do + x <- get bh + return (DocProperty x) + 19 -> do + x <- get bh + return (DocBold x) + 20 -> do + aa <- get bh + return (DocHeader aa) + 21 -> do + x <- get bh + return (DocMathInline x) + 22 -> do + x <- get bh + return (DocMathDisplay x) + 23 -> do + x <- get bh + return (DocTable x) + -- See note [The DocModule story] + 24 -> do + af <- get bh + return (DocModule af) + _ -> error "invalid binary data found in the interface file" instance Binary name => Binary (HaddockModInfo name) where put_ bh hmi = do put_ bh (hmi_description hmi) - put_ bh (hmi_copyright hmi) - put_ bh (hmi_license hmi) - put_ bh (hmi_maintainer hmi) - put_ bh (hmi_stability hmi) + put_ bh (hmi_copyright hmi) + put_ bh (hmi_license hmi) + put_ bh (hmi_maintainer hmi) + put_ bh (hmi_stability hmi) put_ bh (hmi_portability hmi) - put_ bh (hmi_safety hmi) + put_ bh (hmi_safety hmi) put_ bh (fromEnum <$> hmi_language hmi) put_ bh (map fromEnum $ hmi_extensions hmi) diff --git a/haddock-api/src/Haddock/ModuleTree.hs b/haddock-api/src/Haddock/ModuleTree.hs index d0a39322fa..2bcbaefefb 100644 --- a/haddock-api/src/Haddock/ModuleTree.hs +++ b/haddock-api/src/Haddock/ModuleTree.hs @@ -1,4 +1,7 @@ ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.ModuleTree -- Copyright : (c) Simon Marlow 2003-2006, @@ -8,55 +11,53 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------ -module Haddock.ModuleTree ( ModuleTree(..), mkModuleTree ) where - +module Haddock.ModuleTree (ModuleTree (..), mkModuleTree) where -import Haddock.Types ( MDoc ) +import Haddock.Types (MDoc) -import GHC ( Name ) -import GHC.Unit.Module ( Module, moduleNameString, moduleName, moduleUnit, unitString ) -import GHC.Unit.State ( UnitState, lookupUnit, unitPackageIdString ) +import GHC (Name) +import GHC.Unit.Module (Module, moduleName, moduleNameString, moduleUnit, unitString) +import GHC.Unit.State (UnitState, lookupUnit, unitPackageIdString) import qualified Control.Applicative as A - data ModuleTree = Node String (Maybe Module) (Maybe String) (Maybe String) (Maybe (MDoc Name)) [ModuleTree] - mkModuleTree :: UnitState -> Bool -> [(Module, Maybe (MDoc Name))] -> [ModuleTree] mkModuleTree state showPkgs mods = - foldr fn [] [ (mdl, splitModule mdl, modPkg mdl, modSrcPkg mdl, short) | (mdl, short) <- mods ] + foldr fn [] [(mdl, splitModule mdl, modPkg mdl, modSrcPkg mdl, short) | (mdl, short) <- mods] where - modPkg mod_ | showPkgs = Just (unitString (moduleUnit mod_)) - | otherwise = Nothing - modSrcPkg mod_ | showPkgs = fmap unitPackageIdString - (lookupUnit state (moduleUnit mod_)) - | otherwise = Nothing - fn (m,mod_,pkg,srcPkg,short) = addToTrees mod_ m pkg srcPkg short - + modPkg mod_ + | showPkgs = Just (unitString (moduleUnit mod_)) + | otherwise = Nothing + modSrcPkg mod_ + | showPkgs = + fmap + unitPackageIdString + (lookupUnit state (moduleUnit mod_)) + | otherwise = Nothing + fn (m, mod_, pkg, srcPkg, short) = addToTrees mod_ m pkg srcPkg short addToTrees :: [String] -> Module -> Maybe String -> Maybe String -> Maybe (MDoc Name) -> [ModuleTree] -> [ModuleTree] addToTrees [] _ _ _ _ ts = ts addToTrees ss m pkg srcPkg short [] = mkSubTree ss m pkg srcPkg short -addToTrees (s1:ss) m pkg srcPkg short (t@(Node s2 leaf node_pkg node_srcPkg node_short subs) : ts) - | s1 > s2 = t : addToTrees (s1:ss) m pkg srcPkg short ts - | s1 == s2 = Node s2 (leaf A.<|> (if null ss then Just m else Nothing)) this_pkg this_srcPkg this_short (addToTrees ss m pkg srcPkg short subs) : ts - | otherwise = mkSubTree (s1:ss) m pkg srcPkg short ++ t : ts - where - this_pkg = if null ss then pkg else node_pkg - this_srcPkg = if null ss then srcPkg else node_srcPkg - this_short = if null ss then short else node_short - +addToTrees (s1 : ss) m pkg srcPkg short (t@(Node s2 leaf node_pkg node_srcPkg node_short subs) : ts) + | s1 > s2 = t : addToTrees (s1 : ss) m pkg srcPkg short ts + | s1 == s2 = Node s2 (leaf A.<|> (if null ss then Just m else Nothing)) this_pkg this_srcPkg this_short (addToTrees ss m pkg srcPkg short subs) : ts + | otherwise = mkSubTree (s1 : ss) m pkg srcPkg short ++ t : ts + where + this_pkg = if null ss then pkg else node_pkg + this_srcPkg = if null ss then srcPkg else node_srcPkg + this_short = if null ss then short else node_short mkSubTree :: [String] -> Module -> Maybe String -> Maybe String -> Maybe (MDoc Name) -> [ModuleTree] -mkSubTree [] _ _ _ _ = [] -mkSubTree [s] m pkg srcPkg short = [Node s (Just m) pkg srcPkg short []] -mkSubTree (s:s':ss) m pkg srcPkg short = [Node s Nothing Nothing Nothing Nothing (mkSubTree (s':ss) m pkg srcPkg short)] - +mkSubTree [] _ _ _ _ = [] +mkSubTree [s] m pkg srcPkg short = [Node s (Just m) pkg srcPkg short []] +mkSubTree (s : s' : ss) m pkg srcPkg short = [Node s Nothing Nothing Nothing Nothing (mkSubTree (s' : ss) m pkg srcPkg short)] splitModule :: Module -> [String] splitModule mdl = split (moduleNameString (moduleName mdl)) - where split mod0 = case break (== '.') mod0 of - (s1, '.':s2) -> s1 : split s2 - (s1, _) -> [s1] + where + split mod0 = case break (== '.') mod0 of + (s1, '.' : s2) -> s1 : split s2 + (s1, _) -> [s1] diff --git a/haddock-api/src/Haddock/Options.hs b/haddock-api/src/Haddock/Options.hs index a912eb8c91..cae032a8a9 100644 --- a/haddock-api/src/Haddock/Options.hs +++ b/haddock-api/src/Haddock/Options.hs @@ -1,4 +1,7 @@ ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.Options -- Copyright : (c) Simon Marlow 2003-2006, @@ -11,61 +14,58 @@ -- Portability : portable -- -- Definition of the command line interface of Haddock. ------------------------------------------------------------------------------ -module Haddock.Options ( - parseHaddockOpts, - Flag(..), - Visibility(..), - getUsage, - optTitle, - outputDir, - optContentsUrl, - optIndexUrl, - optCssFile, - optSourceCssFile, - sourceUrls, - wikiUrls, - baseUrl, - optParCount, - optDumpInterfaceFile, - optShowInterfaceFile, - optLaTeXStyle, - optMathjax, - qualification, - sinceQualification, - verbosity, - ghcFlags, - reexportFlags, - readIfaceArgs, - optPackageName, - optPackageVersion, - modulePackageInfo, - ignoredSymbols -) where - - +module Haddock.Options + ( parseHaddockOpts + , Flag (..) + , Visibility (..) + , getUsage + , optTitle + , outputDir + , optContentsUrl + , optIndexUrl + , optCssFile + , optSourceCssFile + , sourceUrls + , wikiUrls + , baseUrl + , optParCount + , optDumpInterfaceFile + , optShowInterfaceFile + , optLaTeXStyle + , optMathjax + , qualification + , sinceQualification + , verbosity + , ghcFlags + , reexportFlags + , readIfaceArgs + , optPackageName + , optPackageVersion + , modulePackageInfo + , ignoredSymbols + ) where + +import Control.Applicative import qualified Data.Char as Char -import Data.List (dropWhileEnd) -import Data.Map (Map) +import Data.List (dropWhileEnd) +import Data.Map (Map) import qualified Data.Map as Map -import Data.Set (Set) +import Data.Set (Set) import qualified Data.Set as Set -import Data.Version -import Control.Applicative -import GHC.Data.FastString -import GHC ( Module, moduleUnit ) -import GHC.Unit.State -import Haddock.Types -import Haddock.Utils -import System.Console.GetOpt +import Data.Version +import GHC (Module, moduleUnit) +import GHC.Data.FastString +import GHC.Unit.State +import Haddock.Types +import Haddock.Utils +import System.Console.GetOpt import qualified Text.ParserCombinators.ReadP as RP - data Flag = Flag_BuiltInThemes | Flag_CSS String --- | Flag_DocBook - | Flag_ReadInterface String + | -- | Flag_DocBook + Flag_ReadInterface String | Flag_DumpInterface String | Flag_ShowInterface String | Flag_Heading String @@ -74,12 +74,12 @@ data Flag | Flag_Lib String | Flag_OutputDir FilePath | Flag_Prologue FilePath - | Flag_SourceBaseURL String - | Flag_SourceModuleURL String - | Flag_SourceEntityURL String + | Flag_SourceBaseURL String + | Flag_SourceModuleURL String + | Flag_SourceEntityURL String | Flag_SourceLEntityURL String - | Flag_WikiBaseURL String - | Flag_BaseURL String + | Flag_WikiBaseURL String + | Flag_BaseURL String | Flag_WikiModuleURL String | Flag_WikiEntityURL String | Flag_LaTeX @@ -123,127 +123,282 @@ data Flag | Flag_TraceArgs deriving (Eq, Show) - options :: Bool -> [OptDescr Flag] options backwardsCompat = - [ - Option ['B'] [] (ReqArg Flag_GhcLibDir "DIR") - "path to a GHC lib dir, to override the default path", - Option ['o'] ["odir"] (ReqArg Flag_OutputDir "DIR") - "directory in which to put the output files", - Option ['l'] ["lib"] (ReqArg Flag_Lib "DIR") - "location of Haddock's auxiliary files", - Option ['i'] ["read-interface"] (ReqArg Flag_ReadInterface "FILE") - "read an interface from FILE", - Option ['D'] ["dump-interface"] (ReqArg Flag_DumpInterface "FILE") - "write the resulting interface to FILE", - Option [] ["show-interface"] (ReqArg Flag_ShowInterface "FILE") - "print the interface in a human readable form", --- Option ['S'] ["docbook"] (NoArg Flag_DocBook) --- "output in DocBook XML", - Option ['h'] ["html"] (NoArg Flag_Html) - "output in HTML (XHTML 1.0)", - Option [] ["latex"] (NoArg Flag_LaTeX) "use experimental LaTeX rendering", - Option [] ["latex-style"] (ReqArg Flag_LaTeXStyle "FILE") "provide your own LaTeX style in FILE", - Option [] ["mathjax"] (ReqArg Flag_Mathjax "URL") "URL FOR mathjax", - Option ['U'] ["use-unicode"] (NoArg Flag_UseUnicode) "use Unicode in HTML output", - Option [] ["hoogle"] (NoArg Flag_Hoogle) - "output for Hoogle; you may want --package-name and --package-version too", - Option [] ["quickjump"] (NoArg Flag_QuickJumpIndex) - "generate an index for interactive documentation navigation", - Option [] ["hyperlinked-source"] (NoArg Flag_HyperlinkedSource) - "generate highlighted and hyperlinked source code (for use with --html)", - Option [] ["source-css"] (ReqArg Flag_SourceCss "FILE") - "use custom CSS file instead of default one in hyperlinked source", - Option [] ["source-base"] (ReqArg Flag_SourceBaseURL "URL") - "URL for a source code link on the contents\nand index pages", - Option ['s'] (if backwardsCompat then ["source", "source-module"] else ["source-module"]) + [ Option + ['B'] + [] + (ReqArg Flag_GhcLibDir "DIR") + "path to a GHC lib dir, to override the default path" + , Option + ['o'] + ["odir"] + (ReqArg Flag_OutputDir "DIR") + "directory in which to put the output files" + , Option + ['l'] + ["lib"] + (ReqArg Flag_Lib "DIR") + "location of Haddock's auxiliary files" + , Option + ['i'] + ["read-interface"] + (ReqArg Flag_ReadInterface "FILE") + "read an interface from FILE" + , Option + ['D'] + ["dump-interface"] + (ReqArg Flag_DumpInterface "FILE") + "write the resulting interface to FILE" + , Option + [] + ["show-interface"] + (ReqArg Flag_ShowInterface "FILE") + "print the interface in a human readable form" + , -- Option ['S'] ["docbook"] (NoArg Flag_DocBook) + -- "output in DocBook XML", + Option + ['h'] + ["html"] + (NoArg Flag_Html) + "output in HTML (XHTML 1.0)" + , Option [] ["latex"] (NoArg Flag_LaTeX) "use experimental LaTeX rendering" + , Option [] ["latex-style"] (ReqArg Flag_LaTeXStyle "FILE") "provide your own LaTeX style in FILE" + , Option [] ["mathjax"] (ReqArg Flag_Mathjax "URL") "URL FOR mathjax" + , Option ['U'] ["use-unicode"] (NoArg Flag_UseUnicode) "use Unicode in HTML output" + , Option + [] + ["hoogle"] + (NoArg Flag_Hoogle) + "output for Hoogle; you may want --package-name and --package-version too" + , Option + [] + ["quickjump"] + (NoArg Flag_QuickJumpIndex) + "generate an index for interactive documentation navigation" + , Option + [] + ["hyperlinked-source"] + (NoArg Flag_HyperlinkedSource) + "generate highlighted and hyperlinked source code (for use with --html)" + , Option + [] + ["source-css"] + (ReqArg Flag_SourceCss "FILE") + "use custom CSS file instead of default one in hyperlinked source" + , Option + [] + ["source-base"] + (ReqArg Flag_SourceBaseURL "URL") + "URL for a source code link on the contents\nand index pages" + , Option + ['s'] + (if backwardsCompat then ["source", "source-module"] else ["source-module"]) (ReqArg Flag_SourceModuleURL "URL") - "URL for a source code link for each module\n(using the %{FILE} or %{MODULE} vars)", - Option [] ["source-entity"] (ReqArg Flag_SourceEntityURL "URL") - "URL for a source code link for each entity\n(using the %{FILE}, %{MODULE}, %{NAME},\n%{KIND} or %{LINE} vars)", - Option [] ["source-entity-line"] (ReqArg Flag_SourceLEntityURL "URL") - "URL for a source code link for each entity.\nUsed if name links are unavailable, eg. for TH splices.", - Option [] ["comments-base"] (ReqArg Flag_WikiBaseURL "URL") - "URL for a comments link on the contents\nand index pages", - Option [] ["base-url"] (ReqArg Flag_BaseURL "URL") - "Base URL for static assets (eg. css, javascript, json files etc.).\nWhen given statis assets will not be copied.", - Option [] ["comments-module"] (ReqArg Flag_WikiModuleURL "URL") - "URL for a comments link for each module\n(using the %{MODULE} var)", - Option [] ["comments-entity"] (ReqArg Flag_WikiEntityURL "URL") - "URL for a comments link for each entity\n(using the %{FILE}, %{MODULE}, %{NAME},\n%{KIND} or %{LINE} vars)", - Option ['c'] ["css", "theme"] (ReqArg Flag_CSS "PATH") - "the CSS file or theme directory to use for HTML output", - Option [] ["built-in-themes"] (NoArg Flag_BuiltInThemes) - "include all the built-in haddock themes", - Option ['p'] ["prologue"] (ReqArg Flag_Prologue "FILE") - "file containing prologue text", - Option ['t'] ["title"] (ReqArg Flag_Heading "TITLE") - "page heading", - Option ['q'] ["qual"] (ReqArg Flag_Qualification "QUAL") - "qualification of names, one of \n'none' (default), 'full', 'local'\n'relative' or 'aliased'", - Option ['?'] ["help"] (NoArg Flag_Help) - "display this help and exit", - Option ['V'] ["version"] (NoArg Flag_Version) - "output version information and exit", - Option [] ["compatible-interface-versions"] (NoArg Flag_CompatibleInterfaceVersions) - "output compatible interface file versions and exit", - Option [] ["interface-version"] (NoArg Flag_InterfaceVersion) - "output interface file version and exit", - Option [] ["bypass-interface-version-check"] (NoArg Flag_BypassInterfaceVersonCheck) - "bypass the interface file version check (dangerous)", - Option ['v'] ["verbosity"] (ReqArg Flag_Verbosity "VERBOSITY") - "set verbosity level", - Option [] ["use-contents"] (ReqArg Flag_UseContents "URL") - "use a separately-generated HTML contents page", - Option [] ["gen-contents"] (NoArg Flag_GenContents) - "generate an HTML contents from specified\ninterfaces", - Option [] ["use-index"] (ReqArg Flag_UseIndex "URL") - "use a separately-generated HTML index", - Option [] ["gen-index"] (NoArg Flag_GenIndex) - "generate an HTML index from specified\ninterfaces", - Option [] ["ignore-all-exports"] (NoArg Flag_IgnoreAllExports) - "behave as if all modules have the\nignore-exports attribute", - Option [] ["hide"] (ReqArg Flag_HideModule "MODULE") - "behave as if MODULE has the hide attribute", - Option [] ["show"] (ReqArg Flag_ShowModule "MODULE") - "behave as if MODULE does not have the hide attribute", - Option [] ["show-all"] (NoArg Flag_ShowAllModules) - "behave as if not modules have the hide attribute", - Option [] ["show-extensions"] (ReqArg Flag_ShowExtensions "MODULE") - "behave as if MODULE has the show-extensions attribute", - Option [] ["optghc"] (ReqArg Flag_OptGhc "OPTION") - "option to be forwarded to GHC", - Option [] ["ghc-version"] (NoArg Flag_GhcVersion) - "output GHC version in numeric format", - Option [] ["print-ghc-path"] (NoArg Flag_PrintGhcPath) - "output path to GHC binary", - Option [] ["print-ghc-libdir"] (NoArg Flag_PrintGhcLibDir) - "output GHC lib dir", - Option ['w'] ["no-warnings"] (NoArg Flag_NoWarnings) "turn off all warnings", - Option [] ["no-tmp-comp-dir"] (NoArg Flag_NoTmpCompDir) - "do not re-direct compilation output to a temporary directory", - Option [] ["pretty-html"] (NoArg Flag_PrettyHtml) - "generate html with newlines and indenting (for use with --html)", - Option [] ["no-print-missing-docs"] (NoArg Flag_NoPrintMissingDocs) - "don't print information about any undocumented entities", - Option [] ["reexport"] (ReqArg Flag_Reexport "MOD") - "reexport the module MOD, adding it to the index", - Option [] ["package-name"] (ReqArg Flag_PackageName "NAME") - "name of the package being documented", - Option [] ["package-version"] (ReqArg Flag_PackageVersion "VERSION") - "version of the package being documented in usual x.y.z.w format", - Option [] ["since-qual"] (ReqArg Flag_SinceQualification "QUAL") - "package qualification of @since, one of\n'always' (default) or 'only-external'", - Option [] ["ignore-link-symbol"] (ReqArg Flag_IgnoreLinkSymbol "SYMBOL") - "name of a symbol which does not trigger a warning in case of link issue", - Option ['j'] [] (OptArg (\count -> Flag_ParCount (fmap read count)) "n") - "load modules in parallel", - Option [] ["trace-args"] (NoArg Flag_TraceArgs) + "URL for a source code link for each module\n(using the %{FILE} or %{MODULE} vars)" + , Option + [] + ["source-entity"] + (ReqArg Flag_SourceEntityURL "URL") + "URL for a source code link for each entity\n(using the %{FILE}, %{MODULE}, %{NAME},\n%{KIND} or %{LINE} vars)" + , Option + [] + ["source-entity-line"] + (ReqArg Flag_SourceLEntityURL "URL") + "URL for a source code link for each entity.\nUsed if name links are unavailable, eg. for TH splices." + , Option + [] + ["comments-base"] + (ReqArg Flag_WikiBaseURL "URL") + "URL for a comments link on the contents\nand index pages" + , Option + [] + ["base-url"] + (ReqArg Flag_BaseURL "URL") + "Base URL for static assets (eg. css, javascript, json files etc.).\nWhen given statis assets will not be copied." + , Option + [] + ["comments-module"] + (ReqArg Flag_WikiModuleURL "URL") + "URL for a comments link for each module\n(using the %{MODULE} var)" + , Option + [] + ["comments-entity"] + (ReqArg Flag_WikiEntityURL "URL") + "URL for a comments link for each entity\n(using the %{FILE}, %{MODULE}, %{NAME},\n%{KIND} or %{LINE} vars)" + , Option + ['c'] + ["css", "theme"] + (ReqArg Flag_CSS "PATH") + "the CSS file or theme directory to use for HTML output" + , Option + [] + ["built-in-themes"] + (NoArg Flag_BuiltInThemes) + "include all the built-in haddock themes" + , Option + ['p'] + ["prologue"] + (ReqArg Flag_Prologue "FILE") + "file containing prologue text" + , Option + ['t'] + ["title"] + (ReqArg Flag_Heading "TITLE") + "page heading" + , Option + ['q'] + ["qual"] + (ReqArg Flag_Qualification "QUAL") + "qualification of names, one of \n'none' (default), 'full', 'local'\n'relative' or 'aliased'" + , Option + ['?'] + ["help"] + (NoArg Flag_Help) + "display this help and exit" + , Option + ['V'] + ["version"] + (NoArg Flag_Version) + "output version information and exit" + , Option + [] + ["compatible-interface-versions"] + (NoArg Flag_CompatibleInterfaceVersions) + "output compatible interface file versions and exit" + , Option + [] + ["interface-version"] + (NoArg Flag_InterfaceVersion) + "output interface file version and exit" + , Option + [] + ["bypass-interface-version-check"] + (NoArg Flag_BypassInterfaceVersonCheck) + "bypass the interface file version check (dangerous)" + , Option + ['v'] + ["verbosity"] + (ReqArg Flag_Verbosity "VERBOSITY") + "set verbosity level" + , Option + [] + ["use-contents"] + (ReqArg Flag_UseContents "URL") + "use a separately-generated HTML contents page" + , Option + [] + ["gen-contents"] + (NoArg Flag_GenContents) + "generate an HTML contents from specified\ninterfaces" + , Option + [] + ["use-index"] + (ReqArg Flag_UseIndex "URL") + "use a separately-generated HTML index" + , Option + [] + ["gen-index"] + (NoArg Flag_GenIndex) + "generate an HTML index from specified\ninterfaces" + , Option + [] + ["ignore-all-exports"] + (NoArg Flag_IgnoreAllExports) + "behave as if all modules have the\nignore-exports attribute" + , Option + [] + ["hide"] + (ReqArg Flag_HideModule "MODULE") + "behave as if MODULE has the hide attribute" + , Option + [] + ["show"] + (ReqArg Flag_ShowModule "MODULE") + "behave as if MODULE does not have the hide attribute" + , Option + [] + ["show-all"] + (NoArg Flag_ShowAllModules) + "behave as if not modules have the hide attribute" + , Option + [] + ["show-extensions"] + (ReqArg Flag_ShowExtensions "MODULE") + "behave as if MODULE has the show-extensions attribute" + , Option + [] + ["optghc"] + (ReqArg Flag_OptGhc "OPTION") + "option to be forwarded to GHC" + , Option + [] + ["ghc-version"] + (NoArg Flag_GhcVersion) + "output GHC version in numeric format" + , Option + [] + ["print-ghc-path"] + (NoArg Flag_PrintGhcPath) + "output path to GHC binary" + , Option + [] + ["print-ghc-libdir"] + (NoArg Flag_PrintGhcLibDir) + "output GHC lib dir" + , Option ['w'] ["no-warnings"] (NoArg Flag_NoWarnings) "turn off all warnings" + , Option + [] + ["no-tmp-comp-dir"] + (NoArg Flag_NoTmpCompDir) + "do not re-direct compilation output to a temporary directory" + , Option + [] + ["pretty-html"] + (NoArg Flag_PrettyHtml) + "generate html with newlines and indenting (for use with --html)" + , Option + [] + ["no-print-missing-docs"] + (NoArg Flag_NoPrintMissingDocs) + "don't print information about any undocumented entities" + , Option + [] + ["reexport"] + (ReqArg Flag_Reexport "MOD") + "reexport the module MOD, adding it to the index" + , Option + [] + ["package-name"] + (ReqArg Flag_PackageName "NAME") + "name of the package being documented" + , Option + [] + ["package-version"] + (ReqArg Flag_PackageVersion "VERSION") + "version of the package being documented in usual x.y.z.w format" + , Option + [] + ["since-qual"] + (ReqArg Flag_SinceQualification "QUAL") + "package qualification of @since, one of\n'always' (default) or 'only-external'" + , Option + [] + ["ignore-link-symbol"] + (ReqArg Flag_IgnoreLinkSymbol "SYMBOL") + "name of a symbol which does not trigger a warning in case of link issue" + , Option + ['j'] + [] + (OptArg (\count -> Flag_ParCount (fmap read count)) "n") + "load modules in parallel" + , Option + [] + ["trace-args"] + (NoArg Flag_TraceArgs) "print the arguments provided for this invocation to stdout" ] - getUsage :: IO String getUsage = do prog <- getProgramName @@ -252,111 +407,105 @@ getUsage = do usageHeader :: String -> String usageHeader prog = "Usage: " ++ prog ++ " [OPTION...] file...\n" - parseHaddockOpts :: [String] -> IO ([Flag], [String]) parseHaddockOpts params = - case getOpt Permute (options True) params of + case getOpt Permute (options True) params of (flags, args, []) -> return (flags, args) - (_, _, errors) -> do + (_, _, errors) -> do usage <- getUsage throwE (concat errors ++ usage) optPackageVersion :: [Flag] -> Maybe Data.Version.Version optPackageVersion flags = - let ver = optLast [ v | Flag_PackageVersion v <- flags ] - in ver >>= fmap fst . optLast . RP.readP_to_S parseVersion + let ver = optLast [v | Flag_PackageVersion v <- flags] + in ver >>= fmap fst . optLast . RP.readP_to_S parseVersion optPackageName :: [Flag] -> Maybe PackageName optPackageName flags = - optLast [ PackageName $ mkFastString n | Flag_PackageName n <- flags ] - + optLast [PackageName $ mkFastString n | Flag_PackageName n <- flags] optTitle :: [Flag] -> Maybe String optTitle flags = case [str | Flag_Heading str <- flags] of [] -> Nothing - (t:_) -> Just t - + (t : _) -> Just t outputDir :: [Flag] -> FilePath outputDir flags = - case [ path | Flag_OutputDir path <- flags ] of - [] -> "." + case [path | Flag_OutputDir path <- flags] of + [] -> "." paths -> last paths - optContentsUrl :: [Flag] -> Maybe String -optContentsUrl flags = optLast [ url | Flag_UseContents url <- flags ] - +optContentsUrl flags = optLast [url | Flag_UseContents url <- flags] optIndexUrl :: [Flag] -> Maybe String -optIndexUrl flags = optLast [ url | Flag_UseIndex url <- flags ] - +optIndexUrl flags = optLast [url | Flag_UseIndex url <- flags] optCssFile :: [Flag] -> Maybe FilePath -optCssFile flags = optLast [ str | Flag_CSS str <- flags ] +optCssFile flags = optLast [str | Flag_CSS str <- flags] optSourceCssFile :: [Flag] -> Maybe FilePath -optSourceCssFile flags = optLast [ str | Flag_SourceCss str <- flags ] +optSourceCssFile flags = optLast [str | Flag_SourceCss str <- flags] sourceUrls :: [Flag] -> (Maybe String, Maybe String, Maybe String, Maybe String) sourceUrls flags = - (optLast [str | Flag_SourceBaseURL str <- flags] - ,optLast [str | Flag_SourceModuleURL str <- flags] - ,optLast [str | Flag_SourceEntityURL str <- flags] - ,optLast [str | Flag_SourceLEntityURL str <- flags]) - + ( optLast [str | Flag_SourceBaseURL str <- flags] + , optLast [str | Flag_SourceModuleURL str <- flags] + , optLast [str | Flag_SourceEntityURL str <- flags] + , optLast [str | Flag_SourceLEntityURL str <- flags] + ) wikiUrls :: [Flag] -> (Maybe String, Maybe String, Maybe String) wikiUrls flags = - (optLast [str | Flag_WikiBaseURL str <- flags] - ,optLast [str | Flag_WikiModuleURL str <- flags] - ,optLast [str | Flag_WikiEntityURL str <- flags]) - + ( optLast [str | Flag_WikiBaseURL str <- flags] + , optLast [str | Flag_WikiModuleURL str <- flags] + , optLast [str | Flag_WikiEntityURL str <- flags] + ) baseUrl :: [Flag] -> Maybe String baseUrl flags = optLast [str | Flag_BaseURL str <- flags] optDumpInterfaceFile :: [Flag] -> Maybe FilePath -optDumpInterfaceFile flags = optLast [ str | Flag_DumpInterface str <- flags ] +optDumpInterfaceFile flags = optLast [str | Flag_DumpInterface str <- flags] optShowInterfaceFile :: [Flag] -> Maybe FilePath -optShowInterfaceFile flags = optLast [ str | Flag_ShowInterface str <- flags ] +optShowInterfaceFile flags = optLast [str | Flag_ShowInterface str <- flags] optLaTeXStyle :: [Flag] -> Maybe String -optLaTeXStyle flags = optLast [ str | Flag_LaTeXStyle str <- flags ] +optLaTeXStyle flags = optLast [str | Flag_LaTeXStyle str <- flags] optMathjax :: [Flag] -> Maybe String -optMathjax flags = optLast [ str | Flag_Mathjax str <- flags ] +optMathjax flags = optLast [str | Flag_Mathjax str <- flags] optParCount :: [Flag] -> Maybe (Maybe Int) -optParCount flags = optLast [ n | Flag_ParCount n <- flags ] +optParCount flags = optLast [n | Flag_ParCount n <- flags] qualification :: [Flag] -> Either String QualOption qualification flags = - case map (map Char.toLower) [ str | Flag_Qualification str <- flags ] of - [] -> Right OptNoQual - ["none"] -> Right OptNoQual - ["full"] -> Right OptFullQual - ["local"] -> Right OptLocalQual - ["relative"] -> Right OptRelativeQual - [arg] -> Left $ "unknown qualification type " ++ show arg - _:_ -> Left "qualification option given multiple times" + case map (map Char.toLower) [str | Flag_Qualification str <- flags] of + [] -> Right OptNoQual + ["none"] -> Right OptNoQual + ["full"] -> Right OptFullQual + ["local"] -> Right OptLocalQual + ["relative"] -> Right OptRelativeQual + [arg] -> Left $ "unknown qualification type " ++ show arg + _ : _ -> Left "qualification option given multiple times" sinceQualification :: [Flag] -> Either String SinceQual sinceQualification flags = - case map (map Char.toLower) [ str | Flag_SinceQualification str <- flags ] of - [] -> Right Always - ["always"] -> Right Always - ["external"] -> Right External - [arg] -> Left $ "unknown since-qualification type " ++ show arg - _:_ -> Left "since-qualification option given multiple times" + case map (map Char.toLower) [str | Flag_SinceQualification str <- flags] of + [] -> Right Always + ["always"] -> Right Always + ["external"] -> Right External + [arg] -> Left $ "unknown since-qualification type " ++ show arg + _ : _ -> Left "since-qualification option given multiple times" verbosity :: [Flag] -> Verbosity verbosity flags = - case [ str | Flag_Verbosity str <- flags ] of - [] -> Normal - x:_ -> case parseVerbosity x of + case [str | Flag_Verbosity str <- flags] of + [] -> Normal + x : _ -> case parseVerbosity x of Left e -> throwE e Right v -> v @@ -371,7 +520,7 @@ verbosity flags = -- occurances of that name from any module. ignoredSymbols :: [Flag] -> Map (Maybe String) (Set String) ignoredSymbols flags = - foldr addToMap Map.empty [ splitSymbol symbol | Flag_IgnoreLinkSymbol symbol <- flags ] + foldr addToMap Map.empty [splitSymbol symbol | Flag_IgnoreLinkSymbol symbol <- flags] where -- Split a symbol into its module name and unqualified name, producing -- 'Nothing' for the module name if the given symbol is already unqualified @@ -379,11 +528,9 @@ ignoredSymbols flags = splitSymbol s = -- Drop the longest suffix not containing a '.' character case dropWhileEnd (/= '.') s of - -- If the longest suffix is empty, there was no '.'. -- Assume it is an unqualified name (no module string). "" -> (Nothing, s) - -- If the longest suffix is not empty, there was a '.'. -- Assume it is a qualified name. `s'` will be the module string followed -- by the last '.', e.g. "Data.List.", so take `init s'` as the module @@ -397,59 +544,59 @@ ignoredSymbols flags = addToMap (m, name) symbs = Map.insertWith (Set.union) m (Set.singleton name) symbs ghcFlags :: [Flag] -> [String] -ghcFlags flags = [ option | Flag_OptGhc option <- flags ] +ghcFlags flags = [option | Flag_OptGhc option <- flags] reexportFlags :: [Flag] -> [String] -reexportFlags flags = [ option | Flag_Reexport option <- flags ] +reexportFlags flags = [option | Flag_Reexport option <- flags] data Visibility = Visible | Hidden deriving (Eq, Show) readIfaceArgs :: [Flag] -> [(DocPaths, Visibility, FilePath)] -readIfaceArgs flags = [ parseIfaceOption s | Flag_ReadInterface s <- flags ] +readIfaceArgs flags = [parseIfaceOption s | Flag_ReadInterface s <- flags] where parseIfaceOption :: String -> (DocPaths, Visibility, FilePath) parseIfaceOption str = - case break (==',') str of - (fpath, ',':rest) -> - case break (==',') rest of - (src, ',':rest') -> + case break (== ',') str of + (fpath, ',' : rest) -> + case break (== ',') rest of + (src, ',' : rest') -> let src' = case src of "" -> Nothing - _ -> Just src - in - case break (==',') rest' of - (visibility, ',':file) | visibility == "hidden" -> - ((fpath, src'), Hidden, file) - | otherwise -> - ((fpath, src'), Visible, file) - (file, _) -> - ((fpath, src'), Visible, file) + _ -> Just src + in case break (== ',') rest' of + (visibility, ',' : file) + | visibility == "hidden" -> + ((fpath, src'), Hidden, file) + | otherwise -> + ((fpath, src'), Visible, file) + (file, _) -> + ((fpath, src'), Visible, file) (file, _) -> ((fpath, Nothing), Visible, file) (file, _) -> (("", Nothing), Visible, file) - -- | Like 'listToMaybe' but returns the last element instead of the first. optLast :: [a] -> Maybe a optLast [] = Nothing optLast xs = Just (last xs) - -- | This function has a potential to return 'Nothing' because package name and -- versions can no longer reliably be extracted in all cases: if the package is -- not installed yet then this info is no longer available. -- -- The @--package-name@ and @--package-version@ Haddock flags allow the user to -- specify this information manually and it is returned here if present. -modulePackageInfo :: UnitState - -> [Flag] -- ^ Haddock flags are checked as they may contain - -- the package name or version provided by the user - -- which we prioritise - -> Maybe Module - -> (Maybe PackageName, Maybe Data.Version.Version) +modulePackageInfo + :: UnitState + -> [Flag] + -- ^ Haddock flags are checked as they may contain + -- the package name or version provided by the user + -- which we prioritise + -> Maybe Module + -> (Maybe PackageName, Maybe Data.Version.Version) modulePackageInfo _unit_state _flags Nothing = (Nothing, Nothing) modulePackageInfo unit_state flags (Just modu) = - ( optPackageName flags <|> fmap unitPackageName pkgDb + ( optPackageName flags <|> fmap unitPackageName pkgDb , optPackageVersion flags <|> fmap unitPackageVersion pkgDb ) where diff --git a/haddock-api/src/Haddock/Parser.hs b/haddock-api/src/Haddock/Parser.hs index 850fdf7f85..e3edfc2246 100644 --- a/haddock-api/src/Haddock/Parser.hs +++ b/haddock-api/src/Haddock/Parser.hs @@ -7,26 +7,25 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable - -module Haddock.Parser ( parseParas - , parseString - , parseIdent - ) where +module Haddock.Parser + ( parseParas + , parseString + , parseIdent + ) where import qualified Documentation.Haddock.Parser as P import Documentation.Haddock.Types import Haddock.Types -import GHC.Driver.Session ( DynFlags ) +import GHC.Data.FastString (fsLit) +import GHC.Data.StringBuffer (stringToStringBuffer) import GHC.Driver.Config.Parser (initParserOpts) -import GHC.Data.FastString ( fsLit ) -import GHC.Parser.Lexer ( initParserState, unP, ParseResult(POk, PFailed) ) -import GHC.Parser ( parseIdentifier ) -import GHC.Types.Name.Occurrence ( occNameString ) -import GHC.Types.Name.Reader ( RdrName(..) ) -import GHC.Types.SrcLoc ( mkRealSrcLoc, GenLocated(..) ) -import GHC.Data.StringBuffer ( stringToStringBuffer ) - +import GHC.Driver.Session (DynFlags) +import GHC.Parser (parseIdentifier) +import GHC.Parser.Lexer (ParseResult (PFailed, POk), initParserState, unP) +import GHC.Types.Name.Occurrence (occNameString) +import GHC.Types.Name.Reader (RdrName (..)) +import GHC.Types.SrcLoc (GenLocated (..), mkRealSrcLoc) parseParas :: DynFlags -> Maybe Package -> String -> MetaDoc mod (Wrap NsRdrName) parseParas d p = overDoc (P.overIdentifier (parseIdent d)) . P.parseParas p @@ -41,16 +40,18 @@ parseIdent dflags ns str0 = -- Guards against things like 'Q.--', 'Q.case', etc. -- See https://github.com/haskell/haddock/issues/952 and Trac #14109 | Qual _ occ <- name - , PFailed{} <- unP parseIdentifier (pstate (occNameString occ)) - -> Nothing - | otherwise - -> Just (wrap (NsRdrName ns name)) + , PFailed{} <- unP parseIdentifier (pstate (occNameString occ)) -> + Nothing + | otherwise -> + Just (wrap (NsRdrName ns name)) PFailed{} -> Nothing where realSrcLc = mkRealSrcLoc (fsLit "") 0 0 pstate str = initParserState (initParserOpts dflags) (stringToStringBuffer str) realSrcLc - (wrap,str1) = case str0 of - '(' : s@(c : _) | c /= ',', c /= ')' -- rule out tuple names - -> (Parenthesized, init s) - '`' : s@(_ : _) -> (Backticked, init s) - _ -> (Unadorned, str0) + (wrap, str1) = case str0 of + '(' : s@(c : _) + | c /= ',' + , c /= ')' -> -- rule out tuple names + (Parenthesized, init s) + '`' : s@(_ : _) -> (Backticked, init s) + _ -> (Unadorned, str0) diff --git a/haddock-api/src/Haddock/Types.hs b/haddock-api/src/Haddock/Types.hs index 997ebb24a9..91795b908b 100644 --- a/haddock-api/src/Haddock/Types.hs +++ b/haddock-api/src/Haddock/Types.hs @@ -1,24 +1,27 @@ -{-# LANGUAGE BangPatterns #-} -{-# LANGUAGE ConstraintKinds #-} -{-# LANGUAGE CPP #-} -{-# LANGUAGE DeriveDataTypeable #-} -{-# LANGUAGE DeriveTraversable #-} -{-# LANGUAGE DerivingStrategies #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE CPP #-} +{-# LANGUAGE ConstraintKinds #-} +{-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE DeriveTraversable #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE OverloadedRecordDot #-} -{-# LANGUAGE PartialTypeSignatures #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeOperators #-} -{-# LANGUAGE UndecidableInstances #-} -- Note [Pass sensitive types] - +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE OverloadedRecordDot #-} +{-# LANGUAGE PartialTypeSignatures #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} +-- Note [Pass sensitive types] +{-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-} ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.Types -- Copyright : (c) Simon Marlow 2003-2006, @@ -32,28 +35,28 @@ -- -- Types that are commonly used through-out Haddock. Some of the most -- important types are defined here, like 'Interface' and 'DocName'. ------------------------------------------------------------------------------ -module Haddock.Types ( - module Haddock.Types - , HsDocString, LHsDocString - , Fixity(..) +module Haddock.Types + ( module Haddock.Types + , HsDocString + , LHsDocString + , Fixity (..) , module Documentation.Haddock.Types - ) where + ) where import Control.DeepSeq import Control.Exception (throw) import Control.Monad.Catch import Control.Monad.State.Strict -import Data.Typeable (Typeable) -import Data.Map (Map) import Data.Data (Data) +import Data.Map (Map) import qualified Data.Set as Set +import Data.Typeable (Typeable) import Documentation.Haddock.Types import qualified GHC.Data.Strict as Strict -import GHC.Types.Fixity (Fixity(..)) +import GHC.Types.Fixity (Fixity (..)) import GHC.Types.Name (stableNameCmp) -import GHC.Types.Name.Reader (RdrName(..)) -import GHC.Types.SrcLoc (BufSpan(..), BufPos(..)) +import GHC.Types.Name.Reader (RdrName (..)) +import GHC.Types.SrcLoc (BufPos (..), BufSpan (..)) import GHC.Types.Var (Specificity) import GHC @@ -63,24 +66,26 @@ import GHC.Types.Name.Occurrence import GHC.Utils.Outputable ----------------------------------------------------------------------------- --- * Convenient synonyms ------------------------------------------------------------------------------ +-- * Convenient synonyms -type IfaceMap = Map Module Interface -type InstIfaceMap = Map Module InstalledInterface -- TODO: rename -type DocMap a = Map Name (MDoc a) -type ArgMap a = Map Name (Map Int (MDoc a)) -type SubMap = Map Name [Name] -type DeclMap = Map Name DeclMapEntry -type InstMap = Map RealSrcSpan Name -type FixMap = Map Name Fixity -type DocPaths = (FilePath, Maybe FilePath) -- paths to HTML and sources -type WarningMap = Map Name (Doc Name) +----------------------------------------------------------------------------- +type IfaceMap = Map Module Interface +type InstIfaceMap = Map Module InstalledInterface -- TODO: rename +type DocMap a = Map Name (MDoc a) +type ArgMap a = Map Name (Map Int (MDoc a)) +type SubMap = Map Name [Name] +type DeclMap = Map Name DeclMapEntry +type InstMap = Map RealSrcSpan Name +type FixMap = Map Name Fixity +type DocPaths = (FilePath, Maybe FilePath) -- paths to HTML and sources +type WarningMap = Map Name (Doc Name) ----------------------------------------------------------------------------- + -- * Interfaces and Interface creation + ----------------------------------------------------------------------------- -- | 'Interface' holds all information used to render a single Haddock page. @@ -89,118 +94,92 @@ type WarningMap = Map Name (Doc Name) -- that are only used to create the final record, and that are not used by the -- backends. data Interface = Interface - { - -- | The module behind this interface. - ifaceMod :: !Module - - -- | Is this a signature? - , ifaceIsSig :: !Bool - - -- | Textual information about the module. - , ifaceInfo :: !(HaddockModInfo Name) - - -- | Documentation header. - , ifaceDoc :: !(Documentation Name) - - -- | Documentation header with cross-reference information. - , ifaceRnDoc :: !(Documentation DocName) - - -- | Haddock options for this module (prune, ignore-exports, etc). - , ifaceOptions :: [DocOption] - - -- | Documentation of declarations originating from the module (including - -- subordinates). - , ifaceDocMap :: !(DocMap Name) - , ifaceArgMap :: !(ArgMap Name) - - -- | The names of all the default methods for classes defined in this module - , ifaceDefMeths :: !([(OccName, Name)]) - - , ifaceFixMap :: !(Map Name Fixity) - - , ifaceExportItems :: [ExportItem GhcRn] - , ifaceRnExportItems :: [ExportItem DocNameI] - - -- | All names exported by the module. - , ifaceExports :: [Name] - - -- | All \"visible\" names exported by the module. - -- A visible name is a name that will show up in the documentation of the - -- module. - -- - -- Names from modules that are entirely re-exported don't count as visible. - , ifaceVisibleExports :: [Name] - - -- | Instances exported by the module. - , ifaceInstances :: [ClsInst] - - -- | Orphan instances - , ifaceOrphanInstances :: [DocInstance GhcRn] + { ifaceMod :: !Module + -- ^ The module behind this interface. + , ifaceIsSig :: !Bool + -- ^ Is this a signature? + , ifaceInfo :: !(HaddockModInfo Name) + -- ^ Textual information about the module. + , ifaceDoc :: !(Documentation Name) + -- ^ Documentation header. + , ifaceRnDoc :: !(Documentation DocName) + -- ^ Documentation header with cross-reference information. + , ifaceOptions :: [DocOption] + -- ^ Haddock options for this module (prune, ignore-exports, etc). + , ifaceDocMap :: !(DocMap Name) + -- ^ Documentation of declarations originating from the module (including + -- subordinates). + , ifaceArgMap :: !(ArgMap Name) + , ifaceDefMeths :: !([(OccName, Name)]) + -- ^ The names of all the default methods for classes defined in this module + , ifaceFixMap :: !(Map Name Fixity) + , ifaceExportItems :: [ExportItem GhcRn] + , ifaceRnExportItems :: [ExportItem DocNameI] + , ifaceExports :: [Name] + -- ^ All names exported by the module. + , ifaceVisibleExports :: [Name] + -- ^ All \"visible\" names exported by the module. + -- A visible name is a name that will show up in the documentation of the + -- module. + -- + -- Names from modules that are entirely re-exported don't count as visible. + , ifaceInstances :: [ClsInst] + -- ^ Instances exported by the module. + , ifaceOrphanInstances :: [DocInstance GhcRn] + -- ^ Orphan instances , ifaceRnOrphanInstances :: [DocInstance DocNameI] - - -- | The number of haddockable and haddocked items in the module, as a - -- tuple. Haddockable items are the exports and the module itself. , ifaceHaddockCoverage :: (Int, Int) - - -- | Warnings for things defined in this module. + -- ^ The number of haddockable and haddocked items in the module, as a + -- tuple. Haddockable items are the exports and the module itself. , ifaceWarningMap :: WarningMap - - -- | Tokenized source code of module (available if Haddock is invoked with - -- source generation flag). - , ifaceHieFile :: !FilePath + -- ^ Warnings for things defined in this module. + , ifaceHieFile :: !FilePath + -- ^ Tokenized source code of module (available if Haddock is invoked with + -- source generation flag). , ifaceDynFlags :: !DynFlags } -- | A subset of the fields of 'Interface' that we store in the interface -- files. data InstalledInterface = InstalledInterface - { - -- | The module represented by this interface. - instMod :: Module - - -- | Is this a signature? - , instIsSig :: Bool - - -- | Textual information about the module. - , instInfo :: HaddockModInfo Name - - -- | Documentation of declarations originating from the module (including - -- subordinates). - , instDocMap :: DocMap Name - - , instArgMap :: ArgMap Name - - -- | The names of all the default methods for classes defined in this module - , instDefMeths :: [(OccName,Name)] - - -- | All names exported by this module. - , instExports :: [Name] - - -- | All \"visible\" names exported by the module. - -- A visible name is a name that will show up in the documentation of the - -- module. - , instVisibleExports :: [Name] - - -- | Haddock options for this module (prune, ignore-exports, etc). - , instOptions :: [DocOption] - - , instFixMap :: Map Name Fixity + { instMod :: Module + -- ^ The module represented by this interface. + , instIsSig :: Bool + -- ^ Is this a signature? + , instInfo :: HaddockModInfo Name + -- ^ Textual information about the module. + , instDocMap :: DocMap Name + -- ^ Documentation of declarations originating from the module (including + -- subordinates). + , instArgMap :: ArgMap Name + , instDefMeths :: [(OccName, Name)] + -- ^ The names of all the default methods for classes defined in this module + , instExports :: [Name] + -- ^ All names exported by this module. + , instVisibleExports :: [Name] + -- ^ All \"visible\" names exported by the module. + -- A visible name is a name that will show up in the documentation of the + -- module. + , instOptions :: [DocOption] + -- ^ Haddock options for this module (prune, ignore-exports, etc). + , instFixMap :: Map Name Fixity } -- | Convert an 'Interface' to an 'InstalledInterface' toInstalledIface :: Interface -> InstalledInterface -toInstalledIface interface = InstalledInterface - { instMod = interface.ifaceMod - , instIsSig = interface.ifaceIsSig - , instInfo = interface.ifaceInfo - , instDocMap = interface.ifaceDocMap - , instArgMap = interface.ifaceArgMap - , instExports = interface.ifaceExports - , instVisibleExports = interface.ifaceVisibleExports - , instOptions = interface.ifaceOptions - , instFixMap = interface.ifaceFixMap - , instDefMeths = interface.ifaceDefMeths - } +toInstalledIface interface = + InstalledInterface + { instMod = interface.ifaceMod + , instIsSig = interface.ifaceIsSig + , instInfo = interface.ifaceInfo + , instDocMap = interface.ifaceDocMap + , instArgMap = interface.ifaceArgMap + , instExports = interface.ifaceExports + , instVisibleExports = interface.ifaceVisibleExports + , instOptions = interface.ifaceOptions + , instFixMap = interface.ifaceFixMap + , instDefMeths = interface.ifaceDefMeths + } -- | A monad in which we create Haddock interfaces. Not to be confused with -- `GHC.Tc.Types.IfM` which is used to write GHC interfaces. @@ -208,13 +187,13 @@ toInstalledIface interface = InstalledInterface -- In the past `createInterface` was running in the `Ghc` monad but proved hard -- to sustain as soon as we moved over for Haddock to be a plugin. Also abstracting -- over the Ghc specific clarifies where side effects happen. -newtype IfM m a = IfM { unIfM :: StateT (IfEnv m) m a } +newtype IfM m a = IfM {unIfM :: StateT (IfEnv m) m a} -deriving newtype instance Functor m => Functor (IfM m) +deriving newtype instance Functor m => Functor (IfM m) deriving newtype instance (Monad m, Applicative m) => Applicative (IfM m) -deriving newtype instance Monad m => Monad (IfM m) -deriving newtype instance MonadIO m => MonadIO (IfM m) -deriving newtype instance Monad m => MonadState (IfEnv m) (IfM m) +deriving newtype instance Monad m => Monad (IfM m) +deriving newtype instance MonadIO m => MonadIO (IfM m) +deriving newtype instance Monad m => MonadState (IfEnv m) (IfM m) -- | Interface creation environment. The name sets are used primarily during -- processing of doc strings to avoid emitting the same type of warning for the @@ -222,35 +201,32 @@ deriving newtype instance Monad m => MonadState (IfEnv m) (IfM -- nubbing the list of warning messages after accumulation. This new approach -- was implemented to avoid the nubbing of potentially large lists of strings. data IfEnv m = IfEnv - { - -- | Lookup names in the environment. - ifeLookupName :: Name -> m (Maybe TyThing) - - -- | Names which we have warned about for being out of scope + { ifeLookupName :: Name -> m (Maybe TyThing) + -- ^ Lookup names in the environment. , ifeOutOfScopeNames :: !(Set.Set String) - - -- | Names which we have warned about for being ambiguous - , ifeAmbiguousNames :: !(Set.Set String) + -- ^ Names which we have warned about for being out of scope + , ifeAmbiguousNames :: !(Set.Set String) + -- ^ Names which we have warned about for being ambiguous } -- | Run an `IfM` action. runIfM - :: (Monad m) - -- | Lookup a global name in the current session. Used in cases - -- where declarations don't + :: Monad m => (Name -> m (Maybe TyThing)) - -- | The action to run. + -- ^ Lookup a global name in the current session. Used in cases + -- where declarations don't -> IfM m a - -- | Result and accumulated error/warning messages. + -- ^ The action to run. -> m a + -- ^ Result and accumulated error/warning messages. runIfM lookup_name action = do let - if_env = IfEnv - { - ifeLookupName = lookup_name - , ifeOutOfScopeNames = Set.empty - , ifeAmbiguousNames = Set.empty - } + if_env = + IfEnv + { ifeLookupName = lookup_name + , ifeOutOfScopeNames = Set.empty + , ifeAmbiguousNames = Set.empty + } evalStateT (unIfM action) if_env -- | Look up a name in the current environment @@ -264,42 +240,34 @@ warn :: MonadIO m => String -> IfM m () warn msg = liftIO $ putStrLn msg ----------------------------------------------------------------------------- + -- * Export items & declarations ------------------------------------------------------------------------------ +----------------------------------------------------------------------------- data ExportItem name - - -- | An exported declaration. - = ExportDecl (XExportDecl name) - - -- | An exported entity for which we have no documentation (perhaps because it - -- resides in another package). - | ExportNoDecl + = -- | An exported declaration. + ExportDecl (XExportDecl name) + | -- | An exported entity for which we have no documentation (perhaps because it + -- resides in another package). + ExportNoDecl { expItemName :: !(IdP name) - - -- | Subordinate names. , expItemSubs :: [IdP name] + -- ^ Subordinate names. } - - -- | A section heading. - | ExportGroup - { - -- | Section level (1, 2, 3, ...). - expItemSectionLevel :: !Int - - -- | Section id (for hyperlinks). + | -- | A section heading. + ExportGroup + { expItemSectionLevel :: !Int + -- ^ Section level (1, 2, 3, ...). , expItemSectionId :: !String - - -- | Section heading text. + -- ^ Section id (for hyperlinks). , expItemSectionText :: !(Doc (IdP name)) + -- ^ Section heading text. } - - -- | Some documentation. - | ExportDoc !(MDoc (IdP name)) - - -- | A cross-reference to another module. - | ExportModule !Module + | -- | Some documentation. + ExportDoc !(MDoc (IdP name)) + | -- | A cross-reference to another module. + ExportModule !Module -- | A type family mapping a name type index to types of export declarations. -- The pre-renaming type index ('GhcRn') is mapped to the type of export @@ -308,38 +276,31 @@ data ExportItem name -- ('DocNameI') is mapped to the type of export declarations which do include -- Hoogle output ('RnExportD'). type family XExportDecl x where - XExportDecl GhcRn = ExportD GhcRn + XExportDecl GhcRn = ExportD GhcRn XExportDecl DocNameI = RnExportD -- | Represents an export declaration that Haddock has discovered to be exported -- from a module. The @name@ index indicated whether the declaration has been -- renamed such that each 'Name' points to it's optimal link destination. data ExportD name = ExportD - { - -- | A declaration. - expDDecl :: !(LHsDecl name) - - -- | Bundled patterns for a data type declaration - , expDPats :: [(HsDecl name, DocForDecl (IdP name))] - - -- | Maybe a doc comment, and possibly docs for arguments (if this - -- decl is a function or type-synonym). - , expDMbDoc :: !(DocForDecl (IdP name)) - - -- | Subordinate names, possibly with documentation. - , expDSubDocs :: [(IdP name, DocForDecl (IdP name))] - - -- | Instances relevant to this declaration, possibly with - -- documentation. - , expDInstances :: [DocInstance name] - - -- | Fixity decls relevant to this declaration (including subordinates). - , expDFixities :: [(IdP name, Fixity)] - - -- | Whether the ExportD is from a TH splice or not, for generating - -- the appropriate type of Source link. - , expDSpliced :: !Bool - } + { expDDecl :: !(LHsDecl name) + -- ^ A declaration. + , expDPats :: [(HsDecl name, DocForDecl (IdP name))] + -- ^ Bundled patterns for a data type declaration + , expDMbDoc :: !(DocForDecl (IdP name)) + -- ^ Maybe a doc comment, and possibly docs for arguments (if this + -- decl is a function or type-synonym). + , expDSubDocs :: [(IdP name, DocForDecl (IdP name))] + -- ^ Subordinate names, possibly with documentation. + , expDInstances :: [DocInstance name] + -- ^ Instances relevant to this declaration, possibly with + -- documentation. + , expDFixities :: [(IdP name, Fixity)] + -- ^ Fixity decls relevant to this declaration (including subordinates). + , expDSpliced :: !Bool + -- ^ Whether the ExportD is from a TH splice or not, for generating + -- the appropriate type of Source link. + } -- | Represents export declarations that have undergone renaming such that every -- 'Name' in the declaration points to an optimal link destination. Since Hoogle @@ -348,20 +309,19 @@ data ExportD name = ExportD -- enabled and the module is not hidden in the generated documentation using the -- @{-# OPTIONS_HADDOCK hide #-}@ pragma. data RnExportD = RnExportD - { - -- | The renamed export declaration - rnExpDExpD :: !(ExportD DocNameI) - - -- | If Hoogle textbase (textual database) output is enabled, the text - -- output lines for this declaration. If Hoogle output is not enabled, the - -- list will be empty. - , rnExpDHoogle :: [String] - } + { rnExpDExpD :: !(ExportD DocNameI) + -- ^ The renamed export declaration + , rnExpDHoogle :: [String] + -- ^ If Hoogle textbase (textual database) output is enabled, the text + -- output lines for this declaration. If Hoogle output is not enabled, the + -- list will be empty. + } data Documentation name = Documentation - { documentationDoc :: Maybe (MDoc name) + { documentationDoc :: Maybe (MDoc name) , documentationWarning :: Maybe (Doc name) - } deriving Functor + } + deriving (Functor) instance NFData name => NFData (Documentation name) where rnf (Documentation d w) = d `deepseq` w `deepseq` () @@ -369,6 +329,7 @@ instance NFData name => NFData (Documentation name) where -- | Arguments and result are indexed by Int, zero-based from the left, -- because that's the easiest to use when recursing over types. type FnArgsDoc name = Map Int (MDoc name) + type DocForDecl name = (Documentation name, FnArgsDoc name) noDocForDecl :: DocForDecl name @@ -386,12 +347,12 @@ noDocForDecl = (Documentation Nothing Nothing, mempty) -- in the map, which is unnecessary and very problematic for overall memory -- usage. data DeclMapEntry - = EValD !SrcSpan - | EOther (LHsDecl GhcRn) + = EValD !SrcSpan + | EOther (LHsDecl GhcRn) instance Semigroup DeclMapEntry where - (EValD _) <> e = e - e <> _ = e + (EValD _) <> e = e + e <> _ = e -- | Transform a declaration into a 'DeclMapEntry'. If it is a 'ValD' -- declaration, only the source location will be noted (since that is all we @@ -399,12 +360,13 @@ instance Semigroup DeclMapEntry where -- signatures are handled). Otherwise, the entire declaration will be kept. toDeclMapEntry :: LHsDecl GhcRn -> DeclMapEntry toDeclMapEntry (L l (ValD _ _)) = EValD (locA l) -toDeclMapEntry d = EOther d +toDeclMapEntry d = EOther d ----------------------------------------------------------------------------- + -- * Cross-referencing ------------------------------------------------------------------------------ +----------------------------------------------------------------------------- -- | Type of environment used to cross-reference identifiers in the syntax. type LinkEnv = Map Name Module @@ -420,13 +382,13 @@ instance NFData NsRdrName where -- | Extends 'Name' with cross-reference information. data DocName - = Documented Name Module - -- ^ This thing is part of the (existing or resulting) - -- documentation. The 'Module' is the preferred place - -- in the documentation to refer to. - | Undocumented Name - -- ^ This thing is not part of the (existing or resulting) - -- documentation, as far as Haddock knows. + = -- | This thing is part of the (existing or resulting) + -- documentation. The 'Module' is the preferred place + -- in the documentation to refer to. + Documented Name Module + | -- | This thing is not part of the (existing or resulting) + -- documentation, as far as Haddock knows. + Undocumented Name deriving (Eq, Data) data DocNameI @@ -454,41 +416,39 @@ instance OutputableBndr DocName where pprInfixOcc = pprInfixOcc . getName class NamedThing name => SetName name where - - setName :: Name -> name -> name - + setName :: Name -> name -> name instance SetName Name where - - setName name' _ = name' - + setName name' _ = name' instance SetName DocName where - - setName name' (Documented _ mdl) = Documented name' mdl - setName name' (Undocumented _) = Undocumented name' + setName name' (Documented _ mdl) = Documented name' mdl + setName name' (Undocumented _) = Undocumented name' -- | Adds extra "wrapper" information to a name. -- -- This is to work around the fact that most name types in GHC ('Name', 'RdrName', -- 'OccName', ...) don't include backticks or parens. data Wrap n - = Unadorned { unwrap :: n } -- ^ don't do anything to the name - | Parenthesized { unwrap :: n } -- ^ add parentheses around the name - | Backticked { unwrap :: n } -- ^ add backticks around the name + = -- | don't do anything to the name + Unadorned {unwrap :: n} + | -- | add parentheses around the name + Parenthesized {unwrap :: n} + | -- | add backticks around the name + Backticked {unwrap :: n} deriving (Show, Functor, Foldable, Traversable) instance NFData n => NFData (Wrap n) where rnf w = case w of - Unadorned n -> rnf n + Unadorned n -> rnf n Parenthesized n -> rnf n - Backticked n -> rnf n + Backticked n -> rnf n -- | Useful for debugging instance Outputable n => Outputable (Wrap n) where - ppr (Unadorned n) = ppr n - ppr (Parenthesized n) = hcat [ char '(', ppr n, char ')' ] - ppr (Backticked n) = hcat [ char '`', ppr n, char '`' ] + ppr (Unadorned n) = ppr n + ppr (Parenthesized n) = hcat [char '(', ppr n, char ')'] + ppr (Backticked n) = hcat [char '`', ppr n, char '`'] showWrapped :: (a -> String) -> Wrap a -> String showWrapped f (Unadorned n) = f n @@ -496,17 +456,18 @@ showWrapped f (Parenthesized n) = "(" ++ f n ++ ")" showWrapped f (Backticked n) = "`" ++ f n ++ "`" instance HasOccName DocName where - - occName = occName . getName + occName = occName . getName ----------------------------------------------------------------------------- + -- * Instances + ----------------------------------------------------------------------------- -- | Stable name for stable comparisons. GHC's `Name` uses unstable -- ordering based on their `Unique`'s. newtype SName = SName Name - deriving newtype NFData + deriving newtype (NFData) instance Eq SName where SName n1 == SName n2 = n1 `stableNameCmp` n2 == EQ @@ -518,19 +479,20 @@ instance Ord SName where -- in Haddock output) and unifying special tycons with normal ones. -- For the benefit of the user (looks nice and predictable) and the -- tests (which prefer output to be deterministic). -data SimpleType = SimpleType SName [SimpleType] - | SimpleIntTyLit Integer - | SimpleStringTyLit String - | SimpleCharTyLit Char - deriving (Eq,Ord) +data SimpleType + = SimpleType SName [SimpleType] + | SimpleIntTyLit Integer + | SimpleStringTyLit String + | SimpleCharTyLit Char + deriving (Eq, Ord) instance NFData SimpleType where rnf st = case st of - SimpleType sn sts -> sn `deepseq` sts `deepseq` () - SimpleIntTyLit i -> rnf i + SimpleType sn sts -> sn `deepseq` sts `deepseq` () + SimpleIntTyLit i -> rnf i SimpleStringTyLit s -> rnf s - SimpleCharTyLit c -> rnf c + SimpleCharTyLit c -> rnf c -- | The three types of instances data InstType name @@ -540,18 +502,22 @@ data InstType name , clsiSigs :: [Sig name] , clsiAssocTys :: [DocInstance name] } - | TypeInst (Maybe (HsType name)) -- ^ Body (right-hand side) - | DataInst (TyClDecl name) -- ^ Data constructors - -instance (OutputableBndrId p) - => Outputable (InstType (GhcPass p)) where - ppr (ClassInst { .. }) = text "ClassInst" + | -- | Body (right-hand side) + TypeInst (Maybe (HsType name)) + | -- | Data constructors + DataInst (TyClDecl name) + +instance + OutputableBndrId p + => Outputable (InstType (GhcPass p)) + where + ppr (ClassInst{..}) = + text "ClassInst" <+> ppr clsiCtx <+> ppr clsiTyVars <+> ppr clsiSigs - ppr (TypeInst a) = text "TypeInst" <+> ppr a - ppr (DataInst a) = text "DataInst" <+> ppr a - + ppr (TypeInst a) = text "TypeInst" <+> ppr a + ppr (DataInst a) = text "DataInst" <+> ppr a -- | An instance head that may have documentation and a source location. type DocInstance name = (InstHead name, Maybe (MDoc (IdP name)), Located (IdP name), Maybe Module) @@ -559,33 +525,30 @@ type DocInstance name = (InstHead name, Maybe (MDoc (IdP name)), Located (IdP na -- | The head of an instance. Consists of a class name, a list of type -- parameters (which may be annotated with kinds), and an instance type data InstHead name = InstHead - { ihdClsName :: IdP name - , ihdTypes :: [HsType name] - , ihdInstType :: InstType name - } - + { ihdClsName :: IdP name + , ihdTypes :: [HsType name] + , ihdInstType :: InstType name + } -- | An instance origin information. -- -- This is used primarily in HTML backend to generate unique instance -- identifiers (for expandable sections). data InstOrigin name - = OriginClass name - | OriginData name - | OriginFamily name - + = OriginClass name + | OriginData name + | OriginFamily name instance NamedThing name => NamedThing (InstOrigin name) where - - getName (OriginClass name) = getName name - getName (OriginData name) = getName name - getName (OriginFamily name) = getName name - + getName (OriginClass name) = getName name + getName (OriginData name) = getName name + getName (OriginFamily name) = getName name ----------------------------------------------------------------------------- + -- * Documentation comments ------------------------------------------------------------------------------ +----------------------------------------------------------------------------- type LDoc id = Located (Doc id) @@ -603,33 +566,35 @@ instance NFData Meta where instance NFData id => NFData (MDoc id) where rnf (MetaDoc m d) = m `deepseq` d `deepseq` () -instance (NFData a, NFData mod) - => NFData (DocH mod a) where +instance + (NFData a, NFData mod) + => NFData (DocH mod a) + where rnf doc = case doc of - DocEmpty -> () - DocAppend a b -> a `deepseq` b `deepseq` () - DocString a -> a `deepseq` () - DocParagraph a -> a `deepseq` () - DocIdentifier a -> a `deepseq` () - DocIdentifierUnchecked a -> a `deepseq` () - DocModule a -> a `deepseq` () - DocWarning a -> a `deepseq` () - DocEmphasis a -> a `deepseq` () - DocBold a -> a `deepseq` () - DocMonospaced a -> a `deepseq` () - DocUnorderedList a -> a `deepseq` () - DocOrderedList a -> a `deepseq` () - DocDefList a -> a `deepseq` () - DocCodeBlock a -> a `deepseq` () - DocHyperlink a -> a `deepseq` () - DocPic a -> a `deepseq` () - DocMathInline a -> a `deepseq` () - DocMathDisplay a -> a `deepseq` () - DocAName a -> a `deepseq` () - DocProperty a -> a `deepseq` () - DocExamples a -> a `deepseq` () - DocHeader a -> a `deepseq` () - DocTable a -> a `deepseq` () + DocEmpty -> () + DocAppend a b -> a `deepseq` b `deepseq` () + DocString a -> a `deepseq` () + DocParagraph a -> a `deepseq` () + DocIdentifier a -> a `deepseq` () + DocIdentifierUnchecked a -> a `deepseq` () + DocModule a -> a `deepseq` () + DocWarning a -> a `deepseq` () + DocEmphasis a -> a `deepseq` () + DocBold a -> a `deepseq` () + DocMonospaced a -> a `deepseq` () + DocUnorderedList a -> a `deepseq` () + DocOrderedList a -> a `deepseq` () + DocDefList a -> a `deepseq` () + DocCodeBlock a -> a `deepseq` () + DocHyperlink a -> a `deepseq` () + DocPic a -> a `deepseq` () + DocMathInline a -> a `deepseq` () + DocMathDisplay a -> a `deepseq` () + DocAName a -> a `deepseq` () + DocProperty a -> a `deepseq` () + DocExamples a -> a `deepseq` () + DocHeader a -> a `deepseq` () + DocTable a -> a `deepseq` () #if !MIN_VERSION_ghc(8,0,2) -- These were added to GHC itself in 8.0.2 @@ -654,84 +619,93 @@ instance NFData Example where rnf (Example a b) = a `deepseq` b `deepseq` () instance NFData id => NFData (Table id) where - rnf (Table h b) = h `deepseq` b `deepseq` () + rnf (Table h b) = h `deepseq` b `deepseq` () instance NFData id => NFData (TableRow id) where - rnf (TableRow cs) = cs `deepseq` () + rnf (TableRow cs) = cs `deepseq` () instance NFData id => NFData (TableCell id) where - rnf (TableCell i j c) = i `deepseq` j `deepseq` c `deepseq` () + rnf (TableCell i j c) = i `deepseq` j `deepseq` c `deepseq` () exampleToString :: Example -> String exampleToString (Example expression result) = - ">>> " ++ expression ++ "\n" ++ unlines result + ">>> " ++ expression ++ "\n" ++ unlines result instance NFData name => NFData (HaddockModInfo name) where rnf (HaddockModInfo{..}) = - hmi_description - `deepseq` hmi_copyright - `deepseq` hmi_license - `deepseq` hmi_maintainer - `deepseq` hmi_stability - `deepseq` hmi_portability - `deepseq` hmi_safety - `deepseq` hmi_language - `deepseq` hmi_extensions - `deepseq` () + hmi_description `deepseq` + hmi_copyright `deepseq` + hmi_license `deepseq` + hmi_maintainer `deepseq` + hmi_stability `deepseq` + hmi_portability `deepseq` + hmi_safety `deepseq` + hmi_language `deepseq` + hmi_extensions `deepseq` + () instance NFData LangExt.Extension data HaddockModInfo name = HaddockModInfo { hmi_description :: Maybe (Doc name) - , hmi_copyright :: Maybe String - , hmi_license :: Maybe String - , hmi_maintainer :: Maybe String - , hmi_stability :: Maybe String + , hmi_copyright :: Maybe String + , hmi_license :: Maybe String + , hmi_maintainer :: Maybe String + , hmi_stability :: Maybe String , hmi_portability :: Maybe String - , hmi_safety :: Maybe String - , hmi_language :: Maybe Language - , hmi_extensions :: [LangExt.Extension] + , hmi_safety :: Maybe String + , hmi_language :: Maybe Language + , hmi_extensions :: [LangExt.Extension] } emptyHaddockModInfo :: HaddockModInfo a -emptyHaddockModInfo = HaddockModInfo - { hmi_description = Nothing - , hmi_copyright = Nothing - , hmi_license = Nothing - , hmi_maintainer = Nothing - , hmi_stability = Nothing - , hmi_portability = Nothing - , hmi_safety = Nothing - , hmi_language = Nothing - , hmi_extensions = [] - } - +emptyHaddockModInfo = + HaddockModInfo + { hmi_description = Nothing + , hmi_copyright = Nothing + , hmi_license = Nothing + , hmi_maintainer = Nothing + , hmi_stability = Nothing + , hmi_portability = Nothing + , hmi_safety = Nothing + , hmi_language = Nothing + , hmi_extensions = [] + } ----------------------------------------------------------------------------- + -- * Options ------------------------------------------------------------------------------ +----------------------------------------------------------------------------- -- | Source-level options for controlling the documentation. data DocOption - = OptHide -- ^ This module should not appear in the docs. + = -- | This module should not appear in the docs. + OptHide | OptPrune - | OptIgnoreExports -- ^ Pretend everything is exported. - | OptNotHome -- ^ Not the best place to get docs for things - -- exported by this module. - | OptShowExtensions -- ^ Render enabled extensions for this module. - | OptPrintRuntimeRep -- ^ Render runtime reps for this module (see - -- the GHC @-fprint-explicit-runtime-reps@ flag) + | -- | Pretend everything is exported. + OptIgnoreExports + | -- | Not the best place to get docs for things + -- exported by this module. + OptNotHome + | -- | Render enabled extensions for this module. + OptShowExtensions + | -- | Render runtime reps for this module (see + -- the GHC @-fprint-explicit-runtime-reps@ flag) + OptPrintRuntimeRep deriving (Eq, Show) - -- | Option controlling how to qualify names data QualOption - = OptNoQual -- ^ Never qualify any names. - | OptFullQual -- ^ Qualify all names fully. - | OptLocalQual -- ^ Qualify all imported names fully. - | OptRelativeQual -- ^ Like local, but strip module prefix - -- from modules in the same hierarchy. + = -- | Never qualify any names. + OptNoQual + | -- | Qualify all names fully. + OptFullQual + | -- | Qualify all imported names fully. + OptLocalQual + | -- | Like local, but strip module prefix + -- from modules in the same hierarchy. + OptRelativeQual data Qualification = NoQual @@ -743,15 +717,15 @@ makeContentsQual :: QualOption -> Qualification makeContentsQual qual = case qual of OptNoQual -> NoQual - _ -> FullQual + _ -> FullQual makeModuleQual :: QualOption -> Module -> Qualification makeModuleQual qual mdl = case qual of - OptLocalQual -> LocalQual mdl - OptRelativeQual -> RelativeQual mdl - OptFullQual -> FullQual - OptNoQual -> NoQual + OptLocalQual -> LocalQual mdl + OptRelativeQual -> RelativeQual mdl + OptFullQual -> FullQual + OptNoQual -> NoQual -- | Whether to hide empty contexts -- Since pattern synonyms have two contexts with different semantics, it is @@ -763,11 +737,14 @@ data HideEmptyContexts -- | When to qualify @since@ annotations with their package data SinceQual = Always - | External -- ^ only qualify when the thing being annotated is from - -- an external package + | -- | only qualify when the thing being annotated is from + -- an external package + External ----------------------------------------------------------------------------- + -- * Renaming + ----------------------------------------------------------------------------- -- | Renames an identifier. @@ -776,18 +753,20 @@ data SinceQual type Renamer = String -> (NameSpace -> Bool) -> [Name] ----------------------------------------------------------------------------- + -- * Error handling + ----------------------------------------------------------------------------- -- | Haddock's own exception type. data HaddockException = HaddockException String | WithContext [String] SomeException - deriving Typeable + deriving (Typeable) instance Show HaddockException where show (HaddockException str) = str - show (WithContext ctxts se) = unlines $ ["While " ++ ctxt ++ ":\n" | ctxt <- reverse ctxts] ++ [show se] + show (WithContext ctxts se) = unlines $ ["While " ++ ctxt ++ ":\n" | ctxt <- reverse ctxts] ++ [show se] throwE :: String -> a instance Exception HaddockException @@ -795,15 +774,18 @@ throwE str = throw (HaddockException str) withExceptionContext :: MonadCatch m => String -> m a -> m a withExceptionContext ctxt = - handle (\ex -> - case ex of - HaddockException _ -> throwM $ WithContext [ctxt] (toException ex) - WithContext ctxts se -> throwM $ WithContext (ctxt:ctxts) se - ) . - handle (throwM . WithContext [ctxt]) + handle + ( \ex -> + case ex of + HaddockException _ -> throwM $ WithContext [ctxt] (toException ex) + WithContext ctxts se -> throwM $ WithContext (ctxt : ctxts) se + ) + . handle (throwM . WithContext [ctxt]) ----------------------------------------------------------------------------- + -- * Pass sensitive types + ----------------------------------------------------------------------------- type instance XRec DocNameI a = GenLocated (Anno a) a @@ -814,157 +796,157 @@ instance MapXRec DocNameI where instance WrapXRec DocNameI (HsType DocNameI) where wrapXRec = noLocA -type instance Anno DocName = SrcSpanAnnN -type instance Anno (HsTyVarBndr flag DocNameI) = SrcSpanAnnA -type instance Anno [LocatedA (HsType DocNameI)] = SrcSpanAnnC -type instance Anno (HsType DocNameI) = SrcSpanAnnA -type instance Anno (DataFamInstDecl DocNameI) = SrcSpanAnnA -type instance Anno (DerivStrategy DocNameI) = EpAnn NoEpAnns -type instance Anno (FieldOcc DocNameI) = SrcSpanAnnA -type instance Anno (ConDeclField DocNameI) = SrcSpan +type instance Anno DocName = SrcSpanAnnN +type instance Anno (HsTyVarBndr flag DocNameI) = SrcSpanAnnA +type instance Anno [LocatedA (HsType DocNameI)] = SrcSpanAnnC +type instance Anno (HsType DocNameI) = SrcSpanAnnA +type instance Anno (DataFamInstDecl DocNameI) = SrcSpanAnnA +type instance Anno (DerivStrategy DocNameI) = EpAnn NoEpAnns +type instance Anno (FieldOcc DocNameI) = SrcSpanAnnA +type instance Anno (ConDeclField DocNameI) = SrcSpan type instance Anno (Located (ConDeclField DocNameI)) = SrcSpan type instance Anno [Located (ConDeclField DocNameI)] = SrcSpan -type instance Anno (ConDecl DocNameI) = SrcSpan -type instance Anno (FunDep DocNameI) = SrcSpan -type instance Anno (TyFamInstDecl DocNameI) = SrcSpanAnnA +type instance Anno (ConDecl DocNameI) = SrcSpan +type instance Anno (FunDep DocNameI) = SrcSpan +type instance Anno (TyFamInstDecl DocNameI) = SrcSpanAnnA type instance Anno [LocatedA (TyFamInstDecl DocNameI)] = SrcSpanAnnL -type instance Anno (FamilyDecl DocNameI) = SrcSpan -type instance Anno (Sig DocNameI) = SrcSpan -type instance Anno (InjectivityAnn DocNameI) = EpAnn NoEpAnns -type instance Anno (HsDecl DocNameI) = SrcSpanAnnA -type instance Anno (FamilyResultSig DocNameI) = EpAnn NoEpAnns +type instance Anno (FamilyDecl DocNameI) = SrcSpan +type instance Anno (Sig DocNameI) = SrcSpan +type instance Anno (InjectivityAnn DocNameI) = EpAnn NoEpAnns +type instance Anno (HsDecl DocNameI) = SrcSpanAnnA +type instance Anno (FamilyResultSig DocNameI) = EpAnn NoEpAnns type instance Anno (HsOuterTyVarBndrs Specificity DocNameI) = SrcSpanAnnA -type instance Anno (HsSigType DocNameI) = SrcSpanAnnA - -type XRecCond a - = ( XParTy a ~ AnnParen - , NoGhcTc a ~ a - , MapXRec a - , UnXRec a - , WrapXRec a (HsType a) - ) +type instance Anno (HsSigType DocNameI) = SrcSpanAnnA + +type XRecCond a = + ( XParTy a ~ AnnParen + , NoGhcTc a ~ a + , MapXRec a + , UnXRec a + , WrapXRec a (HsType a) + ) -type instance XValArg DocNameI = NoExtField +type instance XValArg DocNameI = NoExtField type instance XTypeArg DocNameI = NoExtField -type instance XArgPar DocNameI = NoExtField -type instance XXArg DocNameI = DataConCantHappen +type instance XArgPar DocNameI = NoExtField +type instance XXArg DocNameI = DataConCantHappen -type instance XBndrRequired DocNameI = NoExtField -type instance XBndrInvisible DocNameI = NoExtField -type instance XXBndrVis DocNameI = DataConCantHappen +type instance XBndrRequired DocNameI = NoExtField +type instance XBndrInvisible DocNameI = NoExtField +type instance XXBndrVis DocNameI = DataConCantHappen type instance XUnrestrictedArrow DocNameI = NoExtField -type instance XLinearArrow DocNameI = NoExtField -type instance XExplicitMult DocNameI = NoExtField -type instance XXArrow DocNameI = DataConCantHappen - -type instance XForAllTy DocNameI = EpAnn [AddEpAnn] -type instance XQualTy DocNameI = EpAnn [AddEpAnn] -type instance XTyVar DocNameI = EpAnn [AddEpAnn] -type instance XStarTy DocNameI = EpAnn [AddEpAnn] -type instance XAppTy DocNameI = EpAnn [AddEpAnn] -type instance XAppKindTy DocNameI = EpAnn [AddEpAnn] -type instance XFunTy DocNameI = EpAnn [AddEpAnn] -type instance XListTy DocNameI = EpAnn AnnParen -type instance XTupleTy DocNameI = EpAnn AnnParen -type instance XSumTy DocNameI = EpAnn AnnParen -type instance XOpTy DocNameI = EpAnn [AddEpAnn] -type instance XParTy DocNameI = AnnParen -type instance XIParamTy DocNameI = EpAnn [AddEpAnn] -type instance XKindSig DocNameI = EpAnn [AddEpAnn] -type instance XSpliceTy DocNameI = DataConCantHappen -type instance XDocTy DocNameI = EpAnn [AddEpAnn] -type instance XBangTy DocNameI = EpAnn [AddEpAnn] -type instance XRecTy DocNameI = EpAnn [AddEpAnn] -type instance XExplicitListTy DocNameI = EpAnn [AddEpAnn] +type instance XLinearArrow DocNameI = NoExtField +type instance XExplicitMult DocNameI = NoExtField +type instance XXArrow DocNameI = DataConCantHappen + +type instance XForAllTy DocNameI = EpAnn [AddEpAnn] +type instance XQualTy DocNameI = EpAnn [AddEpAnn] +type instance XTyVar DocNameI = EpAnn [AddEpAnn] +type instance XStarTy DocNameI = EpAnn [AddEpAnn] +type instance XAppTy DocNameI = EpAnn [AddEpAnn] +type instance XAppKindTy DocNameI = EpAnn [AddEpAnn] +type instance XFunTy DocNameI = EpAnn [AddEpAnn] +type instance XListTy DocNameI = EpAnn AnnParen +type instance XTupleTy DocNameI = EpAnn AnnParen +type instance XSumTy DocNameI = EpAnn AnnParen +type instance XOpTy DocNameI = EpAnn [AddEpAnn] +type instance XParTy DocNameI = AnnParen +type instance XIParamTy DocNameI = EpAnn [AddEpAnn] +type instance XKindSig DocNameI = EpAnn [AddEpAnn] +type instance XSpliceTy DocNameI = DataConCantHappen +type instance XDocTy DocNameI = EpAnn [AddEpAnn] +type instance XBangTy DocNameI = EpAnn [AddEpAnn] +type instance XRecTy DocNameI = EpAnn [AddEpAnn] +type instance XExplicitListTy DocNameI = EpAnn [AddEpAnn] type instance XExplicitTupleTy DocNameI = EpAnn [AddEpAnn] -type instance XTyLit DocNameI = EpAnn [AddEpAnn] -type instance XWildCardTy DocNameI = EpAnn [AddEpAnn] -type instance XXType DocNameI = HsCoreTy +type instance XTyLit DocNameI = EpAnn [AddEpAnn] +type instance XWildCardTy DocNameI = EpAnn [AddEpAnn] +type instance XXType DocNameI = HsCoreTy -type instance XNumTy DocNameI = NoExtField -type instance XStrTy DocNameI = NoExtField -type instance XCharTy DocNameI = NoExtField -type instance XXTyLit DocNameI = DataConCantHappen +type instance XNumTy DocNameI = NoExtField +type instance XStrTy DocNameI = NoExtField +type instance XCharTy DocNameI = NoExtField +type instance XXTyLit DocNameI = DataConCantHappen -type instance XHsForAllVis DocNameI = NoExtField -type instance XHsForAllInvis DocNameI = NoExtField +type instance XHsForAllVis DocNameI = NoExtField +type instance XHsForAllInvis DocNameI = NoExtField type instance XXHsForAllTelescope DocNameI = DataConCantHappen -type instance XUserTyVar DocNameI = NoExtField -type instance XKindedTyVar DocNameI = NoExtField -type instance XXTyVarBndr DocNameI = DataConCantHappen +type instance XUserTyVar DocNameI = NoExtField +type instance XKindedTyVar DocNameI = NoExtField +type instance XXTyVarBndr DocNameI = DataConCantHappen -type instance XCFieldOcc DocNameI = DocName -type instance XXFieldOcc DocNameI = NoExtField +type instance XCFieldOcc DocNameI = DocName +type instance XXFieldOcc DocNameI = NoExtField -type instance XFixitySig DocNameI = NoExtField -type instance XFixSig DocNameI = NoExtField -type instance XPatSynSig DocNameI = NoExtField -type instance XClassOpSig DocNameI = NoExtField -type instance XTypeSig DocNameI = NoExtField -type instance XMinimalSig DocNameI = NoExtField +type instance XFixitySig DocNameI = NoExtField +type instance XFixSig DocNameI = NoExtField +type instance XPatSynSig DocNameI = NoExtField +type instance XClassOpSig DocNameI = NoExtField +type instance XTypeSig DocNameI = NoExtField +type instance XMinimalSig DocNameI = NoExtField -type instance XForeignExport DocNameI = NoExtField -type instance XForeignImport DocNameI = NoExtField +type instance XForeignExport DocNameI = NoExtField +type instance XForeignImport DocNameI = NoExtField -type instance XCImport DocNameI = NoExtField -type instance XCExport DocNameI = NoExtField +type instance XCImport DocNameI = NoExtField +type instance XCExport DocNameI = NoExtField type instance XXForeignImport DocNameI = DataConCantHappen type instance XXForeignExport DocNameI = DataConCantHappen -type instance XConDeclGADT DocNameI = NoExtField -type instance XConDeclH98 DocNameI = NoExtField -type instance XXConDecl DocNameI = DataConCantHappen +type instance XConDeclGADT DocNameI = NoExtField +type instance XConDeclH98 DocNameI = NoExtField +type instance XXConDecl DocNameI = DataConCantHappen -type instance XPrefixConGADT DocNameI = NoExtField -type instance XRecConGADT DocNameI = NoExtField +type instance XPrefixConGADT DocNameI = NoExtField +type instance XRecConGADT DocNameI = NoExtField type instance XXConDeclGADTDetails DocNameI = DataConCantHappen -type instance XDerivD DocNameI = NoExtField -type instance XInstD DocNameI = NoExtField -type instance XForD DocNameI = NoExtField -type instance XSigD DocNameI = NoExtField -type instance XTyClD DocNameI = NoExtField +type instance XDerivD DocNameI = NoExtField +type instance XInstD DocNameI = NoExtField +type instance XForD DocNameI = NoExtField +type instance XSigD DocNameI = NoExtField +type instance XTyClD DocNameI = NoExtField -type instance XNoSig DocNameI = NoExtField -type instance XCKindSig DocNameI = NoExtField -type instance XTyVarSig DocNameI = NoExtField +type instance XNoSig DocNameI = NoExtField +type instance XCKindSig DocNameI = NoExtField +type instance XTyVarSig DocNameI = NoExtField type instance XXFamilyResultSig DocNameI = DataConCantHappen -type instance XCFamEqn DocNameI _ = NoExtField -type instance XXFamEqn DocNameI _ = DataConCantHappen +type instance XCFamEqn DocNameI _ = NoExtField +type instance XXFamEqn DocNameI _ = DataConCantHappen type instance XCClsInstDecl DocNameI = NoExtField -type instance XCDerivDecl DocNameI = NoExtField -type instance XStockStrategy DocNameI = NoExtField +type instance XCDerivDecl DocNameI = NoExtField +type instance XStockStrategy DocNameI = NoExtField type instance XAnyClassStrategy DocNameI = NoExtField -type instance XNewtypeStrategy DocNameI = NoExtField -type instance XViaStrategy DocNameI = LHsSigType DocNameI +type instance XNewtypeStrategy DocNameI = NoExtField +type instance XViaStrategy DocNameI = LHsSigType DocNameI type instance XDataFamInstD DocNameI = NoExtField -type instance XTyFamInstD DocNameI = NoExtField -type instance XClsInstD DocNameI = NoExtField -type instance XCHsDataDefn DocNameI = NoExtField -type instance XCFamilyDecl DocNameI = NoExtField -type instance XClassDecl DocNameI = NoExtField -type instance XDataDecl DocNameI = NoExtField -type instance XSynDecl DocNameI = NoExtField -type instance XFamDecl DocNameI = NoExtField -type instance XXFamilyDecl DocNameI = DataConCantHappen -type instance XXTyClDecl DocNameI = DataConCantHappen +type instance XTyFamInstD DocNameI = NoExtField +type instance XClsInstD DocNameI = NoExtField +type instance XCHsDataDefn DocNameI = NoExtField +type instance XCFamilyDecl DocNameI = NoExtField +type instance XClassDecl DocNameI = NoExtField +type instance XDataDecl DocNameI = NoExtField +type instance XSynDecl DocNameI = NoExtField +type instance XFamDecl DocNameI = NoExtField +type instance XXFamilyDecl DocNameI = DataConCantHappen +type instance XXTyClDecl DocNameI = DataConCantHappen type instance XHsWC DocNameI _ = NoExtField -type instance XHsOuterExplicit DocNameI _ = NoExtField -type instance XHsOuterImplicit DocNameI = NoExtField -type instance XXHsOuterTyVarBndrs DocNameI = DataConCantHappen +type instance XHsOuterExplicit DocNameI _ = NoExtField +type instance XHsOuterImplicit DocNameI = NoExtField +type instance XXHsOuterTyVarBndrs DocNameI = DataConCantHappen -type instance XHsSig DocNameI = NoExtField +type instance XHsSig DocNameI = NoExtField type instance XXHsSigType DocNameI = DataConCantHappen -type instance XHsQTvs DocNameI = NoExtField -type instance XConDeclField DocNameI = NoExtField +type instance XHsQTvs DocNameI = NoExtField +type instance XConDeclField DocNameI = NoExtField type instance XXConDeclField DocNameI = DataConCantHappen type instance XXPat DocNameI = DataConCantHappen @@ -979,7 +961,9 @@ type instance XCFunDep DocNameI = NoExtField type instance XCTyFamInstDecl DocNameI = NoExtField ----------------------------------------------------------------------------- + -- * NFData instances for GHC types + ----------------------------------------------------------------------------- instance NFData RdrName where @@ -1002,64 +986,64 @@ instance NFData (EpAnn NameAnn) where instance NFData NameAnn where rnf (NameAnn a b c d e) = - a - `deepseq` b - `deepseq` c - `deepseq` d - `deepseq` e - `deepseq` () + a `deepseq` + b `deepseq` + c `deepseq` + d `deepseq` + e `deepseq` + () rnf (NameAnnCommas a b c d e) = - a - `deepseq` b - `deepseq` c - `deepseq` d - `deepseq` e - `deepseq` () + a `deepseq` + b `deepseq` + c `deepseq` + d `deepseq` + e `deepseq` + () rnf (NameAnnBars a b c d e) = - a - `deepseq` b - `deepseq` c - `deepseq` d - `deepseq` e - `deepseq` () + a `deepseq` + b `deepseq` + c `deepseq` + d `deepseq` + e `deepseq` + () rnf (NameAnnOnly a b c d) = - a - `deepseq` b - `deepseq` c - `deepseq` d - `deepseq` () + a `deepseq` + b `deepseq` + c `deepseq` + d `deepseq` + () rnf (NameAnnRArrow a b c d e) = - a - `deepseq` b - `deepseq` c - `deepseq` d - `deepseq` e - `deepseq` () + a `deepseq` + b `deepseq` + c `deepseq` + d `deepseq` + e `deepseq` + () rnf (NameAnnQuote a b c) = - a - `deepseq` b - `deepseq` c - `deepseq` () + a `deepseq` + b `deepseq` + c `deepseq` + () rnf (NameAnnTrailing a) = rnf a instance NFData TrailingAnn where - rnf (AddSemiAnn epaL) = rnf epaL - rnf (AddCommaAnn epaL) = rnf epaL - rnf (AddVbarAnn epaL) = rnf epaL - rnf (AddDarrowAnn epaL) = rnf epaL + rnf (AddSemiAnn epaL) = rnf epaL + rnf (AddCommaAnn epaL) = rnf epaL + rnf (AddVbarAnn epaL) = rnf epaL + rnf (AddDarrowAnn epaL) = rnf epaL rnf (AddDarrowUAnn epaL) = rnf epaL instance NFData NameAdornment where - rnf NameParens = () + rnf NameParens = () rnf NameParensHash = () rnf NameBackquotes = () - rnf NameSquare = () + rnf NameSquare = () instance NFData NoComments where rnf NoComments = () -instance (NFData a) => NFData (EpaLocation' a) where - rnf (EpaSpan ss) = rnf ss +instance NFData a => NFData (EpaLocation' a) where + rnf (EpaSpan ss) = rnf ss rnf (EpaDelta dp lc) = dp `seq` lc `deepseq` () instance NFData EpAnnComments where @@ -1070,14 +1054,13 @@ instance NFData EpaComment where rnf (EpaComment t rss) = t `deepseq` rss `seq` () instance NFData EpaCommentTok where - rnf (EpaDocComment ds) = rnf ds - rnf (EpaDocOptions s) = rnf s - rnf (EpaLineComment s) = rnf s + rnf (EpaDocComment ds) = rnf ds + rnf (EpaDocOptions s) = rnf s + rnf (EpaLineComment s) = rnf s rnf (EpaBlockComment s) = rnf s - instance NFData a => NFData (Strict.Maybe a) where - rnf Strict.Nothing = () + rnf Strict.Nothing = () rnf (Strict.Just x) = rnf x instance NFData BufSpan where @@ -1087,5 +1070,5 @@ instance NFData BufPos where rnf (BufPos n) = rnf n instance NFData DeltaPos where - rnf (SameLine n) = rnf n + rnf (SameLine n) = rnf n rnf (DifferentLine n m) = n `deepseq` m `deepseq` () diff --git a/haddock-api/src/Haddock/Utils.hs b/haddock-api/src/Haddock/Utils.hs index 314b8db9e6..94b5138e65 100644 --- a/haddock-api/src/Haddock/Utils.hs +++ b/haddock-api/src/Haddock/Utils.hs @@ -1,8 +1,11 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE GADTs #-} - {-# OPTIONS_GHC -Wno-incomplete-record-updates #-} + ----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- + -- | -- Module : Haddock.Utils -- Copyright : (c) The University of Glasgow 2001-2002, @@ -13,43 +16,56 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------ -module Haddock.Utils ( - - -- * Filename utilities - moduleHtmlFile, moduleHtmlFile', - contentsHtmlFile, indexHtmlFile, indexJsonFile, - subIndexHtmlFile, - haddockJsFile, jsQuickJumpFile, - quickJumpCssFile, - - -- * Anchor and URL utilities - moduleNameUrl, moduleNameUrl', moduleUrl, - nameAnchorId, - makeAnchorId, - - -- * Miscellaneous utilities - getProgramName, bye, die, escapeStr, - writeUtf8File, withTempDir, - - -- * HTML cross reference mapping - html_xrefs_ref, html_xrefs_ref', - - -- * Doc markup - mkMeta, - - -- * List utilities - replace, - spanWith, - - -- * Logging - parseVerbosity, Verbosity(..), silent, normal, verbose, deafening, - out, - - -- * System tools - getProcessID - ) where - +module Haddock.Utils + ( -- * Filename utilities + moduleHtmlFile + , moduleHtmlFile' + , contentsHtmlFile + , indexHtmlFile + , indexJsonFile + , subIndexHtmlFile + , haddockJsFile + , jsQuickJumpFile + , quickJumpCssFile + + -- * Anchor and URL utilities + , moduleNameUrl + , moduleNameUrl' + , moduleUrl + , nameAnchorId + , makeAnchorId + + -- * Miscellaneous utilities + , getProgramName + , bye + , die + , escapeStr + , writeUtf8File + , withTempDir + + -- * HTML cross reference mapping + , html_xrefs_ref + , html_xrefs_ref' + + -- * Doc markup + , mkMeta + + -- * List utilities + , replace + , spanWith + + -- * Logging + , parseVerbosity + , Verbosity (..) + , silent + , normal + , verbose + , deafening + , out + + -- * System tools + , getProcessID + ) where import Documentation.Haddock.Doc (emptyMetaDoc) import Haddock.Types @@ -57,36 +73,38 @@ import Haddock.Types import GHC import GHC.Types.Name -import Control.Monad.IO.Class ( MonadIO(..) ) -import Control.Monad.Catch ( MonadMask, bracket_ ) -import Data.Char ( isAlpha, isAlphaNum, isAscii, ord, chr ) -import Numeric ( showIntAtBase ) -import Data.Map ( Map ) -import qualified Data.Map as Map hiding ( Map ) -import Data.IORef ( IORef, newIORef, readIORef ) -import Data.List ( isSuffixOf ) -import System.Environment ( getProgName ) +import Control.Monad.Catch (MonadMask, bracket_) +import Control.Monad.IO.Class (MonadIO (..)) +import Data.Char (chr, isAlpha, isAlphaNum, isAscii, ord) +import Data.IORef (IORef, newIORef, readIORef) +import Data.List (isSuffixOf) +import Data.Map (Map) +import qualified Data.Map as Map hiding (Map) +import Numeric (showIntAtBase) +import System.Directory (createDirectory, removeDirectoryRecursive) +import System.Environment (getProgName) import System.Exit -import System.Directory ( createDirectory, removeDirectoryRecursive ) -import System.IO ( hPutStr, hSetEncoding, IOMode(..), utf8, withFile ) -import System.IO.Unsafe ( unsafePerformIO ) import qualified System.FilePath.Posix as HtmlPath +import System.IO (IOMode (..), hPutStr, hSetEncoding, utf8, withFile) +import System.IO.Unsafe (unsafePerformIO) #ifndef mingw32_HOST_OS import qualified System.Posix.Internals #endif -------------------------------------------------------------------------------- + -- * Logging + -------------------------------------------------------------------------------- data Verbosity = Silent | Normal | Verbose | Deafening deriving (Eq, Ord, Enum, Bounded, Show) silent, normal, verbose, deafening :: Verbosity -silent = Silent -normal = Normal -verbose = Verbose +silent = Silent +normal = Normal +verbose = Verbose deafening = Deafening -- | Parse out a verbosity level. Inspired from Cabal's verbosity parsing. @@ -95,70 +113,74 @@ parseVerbosity "0" = Right Silent parseVerbosity "1" = Right Normal parseVerbosity "2" = Right Silent parseVerbosity "3" = Right Deafening -parseVerbosity "silent" = return Silent -parseVerbosity "normal" = return Normal -parseVerbosity "verbose" = return Verbose -parseVerbosity "debug" = return Deafening +parseVerbosity "silent" = return Silent +parseVerbosity "normal" = return Normal +parseVerbosity "verbose" = return Verbose +parseVerbosity "debug" = return Deafening parseVerbosity "deafening" = return Deafening parseVerbosity other = Left ("Can't parse verbosity " ++ other) -- | Print a message to stdout, if it is not too verbose -out :: MonadIO m - => Verbosity -- ^ program verbosity - -> Verbosity -- ^ message verbosity - -> String -> m () +out + :: MonadIO m + => Verbosity + -- ^ program verbosity + -> Verbosity + -- ^ message verbosity + -> String + -> m () out progVerbosity msgVerbosity msg | msgVerbosity <= progVerbosity = liftIO $ putStrLn msg | otherwise = return () - --------------------------------------------------------------------------------- --- * Some Utilities -------------------------------------------------------------------------------- +-- * Some Utilities +-------------------------------------------------------------------------------- mkMeta :: Doc a -> MDoc a -mkMeta x = emptyMetaDoc { _doc = x } +mkMeta x = emptyMetaDoc{_doc = x} -------------------------------------------------------------------------------- + -- * Filename mangling functions stolen from s main/DriverUtil.lhs. + -------------------------------------------------------------------------------- baseName :: ModuleName -> FilePath baseName = map (\c -> if c == '.' then '-' else c) . moduleNameString - moduleHtmlFile :: Module -> FilePath moduleHtmlFile mdl = case Map.lookup mdl html_xrefs of - Nothing -> baseName mdl' ++ ".html" + Nothing -> baseName mdl' ++ ".html" Just fp0 -> HtmlPath.joinPath [fp0, baseName mdl' ++ ".html"] where - mdl' = moduleName mdl - + mdl' = moduleName mdl moduleHtmlFile' :: ModuleName -> FilePath moduleHtmlFile' mdl = case Map.lookup mdl html_xrefs' of - Nothing -> baseName mdl ++ ".html" + Nothing -> baseName mdl ++ ".html" Just fp0 -> HtmlPath.joinPath [fp0, baseName mdl ++ ".html"] - contentsHtmlFile, indexHtmlFile, indexJsonFile :: String contentsHtmlFile = "index.html" indexHtmlFile = "doc-index.html" indexJsonFile = "doc-index.json" - subIndexHtmlFile :: String -> String subIndexHtmlFile ls = "doc-index-" ++ b ++ ".html" - where b | all isAlpha ls = ls - | otherwise = concatMap (show . ord) ls - + where + b + | all isAlpha ls = ls + | otherwise = concatMap (show . ord) ls ------------------------------------------------------------------------------- + -- * Anchor and URL utilities + -- -- NB: Anchor IDs, used as the destination of a link within a document must -- conform to XML's NAME production. That, taken with XHTML and HTML 4.01's @@ -170,44 +192,43 @@ subIndexHtmlFile ls = "doc-index-" ++ b ++ ".html" -- before being matched with IDs in the target document. ------------------------------------------------------------------------------- - moduleUrl :: Module -> String moduleUrl = moduleHtmlFile - moduleNameUrl :: Module -> OccName -> String moduleNameUrl mdl n = moduleUrl mdl ++ '#' : nameAnchorId n - moduleNameUrl' :: ModuleName -> OccName -> String moduleNameUrl' mdl n = moduleHtmlFile' mdl ++ '#' : nameAnchorId n - nameAnchorId :: OccName -> String nameAnchorId name = makeAnchorId (prefix : ':' : occNameString name) - where prefix | isValOcc name = 'v' - | otherwise = 't' - + where + prefix + | isValOcc name = 'v' + | otherwise = 't' -- | Takes an arbitrary string and makes it a valid anchor ID. The mapping is -- identity preserving. makeAnchorId :: String -> String makeAnchorId [] = [] -makeAnchorId (f:r) = escape isAlpha f ++ concatMap (escape isLegal) r +makeAnchorId (f : r) = escape isAlpha f ++ concatMap (escape isLegal) r where - escape p c | p c = [c] - | otherwise = '-' : show (ord c) ++ "-" + escape p c + | p c = [c] + | otherwise = '-' : show (ord c) ++ "-" isLegal ':' = True isLegal '_' = True isLegal '.' = True isLegal c = isAscii c && isAlphaNum c - -- NB: '-' is legal in IDs, but we use it as the escape char +-- NB: '-' is legal in IDs, but we use it as the escape char ------------------------------------------------------------------------------- + -- * Files we need to copy from our $libdir -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- haddockJsFile :: String haddockJsFile = "haddock-bundle.min.js" @@ -219,16 +240,17 @@ quickJumpCssFile :: String quickJumpCssFile = "quick-jump.css" ------------------------------------------------------------------------------- + -- * Misc. -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- getProgramName :: IO String getProgramName = fmap (`withoutSuffix` ".bin") getProgName - where str `withoutSuffix` suff - | suff `isSuffixOf` str = take (length str - length suff) str - | otherwise = str - + where + str `withoutSuffix` suff + | suff `isSuffixOf` str = take (length str - length suff) str + | otherwise = str bye :: String -> IO a bye s = putStr s >> exitSuccess @@ -236,37 +258,33 @@ bye s = putStr s >> exitSuccess escapeStr :: String -> String escapeStr = escapeURIString isUnreserved - -- Following few functions are copy'n'pasted from Network.URI module -- to avoid depending on the network lib, since doing so gives a -- circular build dependency between haddock and network -- (at least if you want to build network with haddock docs) escapeURIChar :: (Char -> Bool) -> Char -> String escapeURIChar p c - | p c = [c] - | otherwise = '%' : myShowHex (ord c) "" - where - myShowHex :: Int -> ShowS - myShowHex n r = case showIntAtBase 16 toChrHex n r of - [] -> "00" - [a] -> ['0',a] - cs -> cs - toChrHex d - | d < 10 = chr (ord '0' + fromIntegral d) - | otherwise = chr (ord 'A' + fromIntegral (d - 10)) - + | p c = [c] + | otherwise = '%' : myShowHex (ord c) "" + where + myShowHex :: Int -> ShowS + myShowHex n r = case showIntAtBase 16 toChrHex n r of + [] -> "00" + [a] -> ['0', a] + cs -> cs + toChrHex d + | d < 10 = chr (ord '0' + fromIntegral d) + | otherwise = chr (ord 'A' + fromIntegral (d - 10)) escapeURIString :: (Char -> Bool) -> String -> String escapeURIString = concatMap . escapeURIChar - isUnreserved :: Char -> Bool isUnreserved c = isAlphaNumChar c || (c `elem` "-_.~") - isAlphaChar, isDigitChar, isAlphaNumChar :: Char -> Bool -isAlphaChar c = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') -isDigitChar c = c >= '0' && c <= '9' +isAlphaChar c = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') +isDigitChar c = c >= '0' && c <= '9' isAlphaNumChar c = isAlphaChar c || isDigitChar c -- | Utility to write output to UTF-8 encoded files. @@ -276,15 +294,19 @@ isAlphaNumChar c = isAlphaChar c || isDigitChar c -- encoding isn't enough for the characters we want to write. writeUtf8File :: FilePath -> String -> IO () writeUtf8File filepath contents = withFile filepath WriteMode $ \h -> do - hSetEncoding h utf8 - hPutStr h contents + hSetEncoding h utf8 + hPutStr h contents withTempDir :: (MonadIO m, MonadMask m) => FilePath -> m a -> m a -withTempDir dir = bracket_ (liftIO $ createDirectory dir) - (liftIO $ removeDirectoryRecursive dir) +withTempDir dir = + bracket_ + (liftIO $ createDirectory dir) + (liftIO $ removeDirectoryRecursive dir) ----------------------------------------------------------------------------- + -- * HTML cross references + -- -- For each module, we need to know where its HTML documentation lives -- so that we can point hyperlinks to it. It is extremely @@ -294,46 +316,42 @@ withTempDir dir = bracket_ (liftIO $ createDirectory dir) -- being I'm going to use a write-once global variable. ----------------------------------------------------------------------------- - {-# NOINLINE html_xrefs_ref #-} html_xrefs_ref :: IORef (Map Module FilePath) html_xrefs_ref = unsafePerformIO (newIORef (error "module_map")) - {-# NOINLINE html_xrefs_ref' #-} html_xrefs_ref' :: IORef (Map ModuleName FilePath) html_xrefs_ref' = unsafePerformIO (newIORef (error "module_map")) - {-# NOINLINE html_xrefs #-} html_xrefs :: Map Module FilePath html_xrefs = unsafePerformIO (readIORef html_xrefs_ref) - {-# NOINLINE html_xrefs' #-} html_xrefs' :: Map ModuleName FilePath html_xrefs' = unsafePerformIO (readIORef html_xrefs_ref') - ----------------------------------------------------------------------------- + -- * List utils ------------------------------------------------------------------------------ +----------------------------------------------------------------------------- replace :: Eq a => a -> a -> [a] -> [a] replace a b = map (\x -> if x == a then b else x) - -spanWith :: (a -> Maybe b) -> [a] -> ([b],[a]) -spanWith _ [] = ([],[]) -spanWith p xs@(a:as) - | Just b <- p a = let (bs,cs) = spanWith p as in (b:bs,cs) - | otherwise = ([],xs) +spanWith :: (a -> Maybe b) -> [a] -> ([b], [a]) +spanWith _ [] = ([], []) +spanWith p xs@(a : as) + | Just b <- p a = let (bs, cs) = spanWith p as in (b : bs, cs) + | otherwise = ([], xs) ----------------------------------------------------------------------------- + -- * System tools ------------------------------------------------------------------------------ +----------------------------------------------------------------------------- #ifdef mingw32_HOST_OS foreign import ccall unsafe "_getpid" getProcessID :: IO Int -- relies on Int == Int32 on Windows diff --git a/haddock-api/src/Haddock/Utils/Json.hs b/haddock-api/src/Haddock/Utils/Json.hs index 0a796b4a8f..1486519bd7 100644 --- a/haddock-api/src/Haddock/Utils/Json.hs +++ b/haddock-api/src/Haddock/Utils/Json.hs @@ -1,54 +1,55 @@ {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE RankNTypes #-} -- | Minimal JSON / RFC 7159 support -- -- The API is heavily inspired by @aeson@'s API but puts emphasis on -- simplicity rather than performance. The 'ToJSON' instances are -- intended to have an encoding compatible with @aeson@'s encoding. --- module Haddock.Utils.Json - ( Value(..) - , Object, object, Pair, (.=) - , encodeToString - , encodeToBuilder - , ToJSON(toJSON) - - , Parser(..) - , Result(..) - , FromJSON(parseJSON) - , withObject - , withArray - , withString - , withDouble - , withBool - , fromJSON - , parse - , parseEither - , (.:) - , (.:?) - , decode - , decodeWith - , eitherDecode - , eitherDecodeWith - , decodeFile - , eitherDecodeFile - ) - where + ( Value (..) + , Object + , object + , Pair + , (.=) + , encodeToString + , encodeToBuilder + , ToJSON (toJSON) + , Parser (..) + , Result (..) + , FromJSON (parseJSON) + , withObject + , withArray + , withString + , withDouble + , withBool + , fromJSON + , parse + , parseEither + , (.:) + , (.:?) + , decode + , decodeWith + , eitherDecode + , eitherDecodeWith + , decodeFile + , eitherDecodeFile + ) +where import Control.Applicative (Alternative (..)) import Control.Monad (MonadPlus (..), zipWithM, (>=>)) import qualified Control.Monad as Monad import qualified Control.Monad.Fail as Fail -import qualified Data.ByteString.Lazy as BSL import Data.ByteString.Builder (Builder) import qualified Data.ByteString.Builder as BB +import qualified Data.ByteString.Lazy as BSL import Data.Char import Data.Int -import Data.Word import Data.List (intersperse) import Data.Monoid +import Data.Word import GHC.Natural @@ -57,16 +58,14 @@ import GHC.Natural import qualified Text.Parsec.ByteString.Lazy as Parsec.Lazy import qualified Text.ParserCombinators.Parsec as Parsec -import Haddock.Utils.Json.Types import Haddock.Utils.Json.Parser - +import Haddock.Utils.Json.Types infixr 8 .= -- | A key-value pair for encoding a JSON object. (.=) :: ToJSON v => String -> v -> Pair -k .= v = (k, toJSON v) - +k .= v = (k, toJSON v) -- | A type that can be converted to JSON. class ToJSON a where @@ -86,17 +85,17 @@ instance ToJSON a => ToJSON [a] where toJSON = Array . map toJSON instance ToJSON a => ToJSON (Maybe a) where - toJSON Nothing = Null + toJSON Nothing = Null toJSON (Just a) = toJSON a -instance (ToJSON a,ToJSON b) => ToJSON (a,b) where - toJSON (a,b) = Array [toJSON a, toJSON b] +instance (ToJSON a, ToJSON b) => ToJSON (a, b) where + toJSON (a, b) = Array [toJSON a, toJSON b] -instance (ToJSON a,ToJSON b,ToJSON c) => ToJSON (a,b,c) where - toJSON (a,b,c) = Array [toJSON a, toJSON b, toJSON c] +instance (ToJSON a, ToJSON b, ToJSON c) => ToJSON (a, b, c) where + toJSON (a, b, c) = Array [toJSON a, toJSON b, toJSON c] -instance (ToJSON a,ToJSON b,ToJSON c, ToJSON d) => ToJSON (a,b,c,d) where - toJSON (a,b,c,d) = Array [toJSON a, toJSON b, toJSON c, toJSON d] +instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d) => ToJSON (a, b, c, d) where + toJSON (a, b, c, d) = Array [toJSON a, toJSON b, toJSON c, toJSON d] instance ToJSON Float where toJSON = Number . realToFrac @@ -104,21 +103,21 @@ instance ToJSON Float where instance ToJSON Double where toJSON = Number -instance ToJSON Int where toJSON = Number . realToFrac -instance ToJSON Int8 where toJSON = Number . realToFrac -instance ToJSON Int16 where toJSON = Number . realToFrac -instance ToJSON Int32 where toJSON = Number . realToFrac +instance ToJSON Int where toJSON = Number . realToFrac +instance ToJSON Int8 where toJSON = Number . realToFrac +instance ToJSON Int16 where toJSON = Number . realToFrac +instance ToJSON Int32 where toJSON = Number . realToFrac -instance ToJSON Word where toJSON = Number . realToFrac -instance ToJSON Word8 where toJSON = Number . realToFrac -instance ToJSON Word16 where toJSON = Number . realToFrac -instance ToJSON Word32 where toJSON = Number . realToFrac +instance ToJSON Word where toJSON = Number . realToFrac +instance ToJSON Word8 where toJSON = Number . realToFrac +instance ToJSON Word16 where toJSON = Number . realToFrac +instance ToJSON Word32 where toJSON = Number . realToFrac -- | Possibly lossy due to conversion to 'Double' -instance ToJSON Int64 where toJSON = Number . realToFrac +instance ToJSON Int64 where toJSON = Number . realToFrac -- | Possibly lossy due to conversion to 'Double' -instance ToJSON Word64 where toJSON = Number . realToFrac +instance ToJSON Word64 where toJSON = Number . realToFrac -- | Possibly lossy due to conversion to 'Double' instance ToJSON Integer where toJSON = Number . fromInteger @@ -132,14 +131,14 @@ encodeToBuilder = encodeValueBB . toJSON encodeValueBB :: Value -> Builder encodeValueBB jv = case jv of - Bool True -> "true" + Bool True -> "true" Bool False -> "false" - Null -> "null" + Null -> "null" Number n - | isNaN n || isInfinite n -> encodeValueBB Null + | isNaN n || isInfinite n -> encodeValueBB Null | Just i <- doubleToInt64 n -> BB.int64Dec i - | otherwise -> BB.doubleDec n - Array a -> encodeArrayBB a + | otherwise -> BB.doubleDec n + Array a -> encodeArrayBB a String s -> encodeStringBB s Object o -> encodeObjectBB o @@ -154,7 +153,7 @@ encodeObjectBB [] = "{}" encodeObjectBB jvs = BB.char8 '{' <> go jvs <> BB.char8 '}' where go = Data.Monoid.mconcat . intersperse (BB.char8 ',') . map encPair - encPair (l,x) = encodeStringBB l <> BB.char8 ':' <> encodeValueBB x + encPair (l, x) = encodeStringBB l <> BB.char8 ':' <> encodeValueBB x encodeStringBB :: String -> Builder encodeStringBB str = BB.char8 '"' <> go str <> BB.char8 '"' @@ -170,34 +169,34 @@ encodeToString jv = encodeValue (toJSON jv) [] encodeValue :: Value -> ShowS encodeValue jv = case jv of - Bool b -> showString (if b then "true" else "false") - Null -> showString "null" + Bool b -> showString (if b then "true" else "false") + Null -> showString "null" Number n - | isNaN n || isInfinite n -> encodeValue Null + | isNaN n || isInfinite n -> encodeValue Null | Just i <- doubleToInt64 n -> shows i - | otherwise -> shows n + | otherwise -> shows n Array a -> encodeArray a String s -> encodeString s Object o -> encodeObject o encodeArray :: [Value] -> ShowS encodeArray [] = showString "[]" -encodeArray jvs = ('[':) . go jvs . (']':) +encodeArray jvs = ('[' :) . go jvs . (']' :) where - go [] = id - go [x] = encodeValue x - go (x:xs) = encodeValue x . (',':) . go xs + go [] = id + go [x] = encodeValue x + go (x : xs) = encodeValue x . (',' :) . go xs encodeObject :: Object -> ShowS encodeObject [] = showString "{}" -encodeObject jvs = ('{':) . go jvs . ('}':) +encodeObject jvs = ('{' :) . go jvs . ('}' :) where - go [] = id - go [(l,x)] = encodeString l . (':':) . encodeValue x - go ((l,x):lxs) = encodeString l . (':':) . encodeValue x . (',':) . go lxs + go [] = id + go [(l, x)] = encodeString l . (':' :) . encodeValue x + go ((l, x) : lxs) = encodeString l . (':' :) . encodeValue x . (',' :) . go lxs encodeString :: String -> ShowS -encodeString str = ('"':) . showString (escapeString str) . ('"':) +encodeString str = ('"' :) . showString (escapeString str) . ('"' :) ------------------------------------------------------------------------------ -- helpers @@ -208,8 +207,8 @@ doubleToInt64 :: Double -> Maybe Int64 doubleToInt64 x | fromInteger x' == x , x' <= toInteger (maxBound :: Int64) - , x' >= toInteger (minBound :: Int64) - = Just (fromIntegral x') + , x' >= toInteger (minBound :: Int64) = + Just (fromIntegral x') | otherwise = Nothing where x' = round x @@ -218,23 +217,24 @@ doubleToInt64 x escapeString :: String -> String escapeString s | not (any needsEscape s) = s - | otherwise = escape s + | otherwise = escape s where escape [] = [] - escape (x:xs) = case x of - '\\' -> '\\':'\\':escape xs - '"' -> '\\':'"':escape xs - '\b' -> '\\':'b':escape xs - '\f' -> '\\':'f':escape xs - '\n' -> '\\':'n':escape xs - '\r' -> '\\':'r':escape xs - '\t' -> '\\':'t':escape xs - c | ord c < 0x10 -> '\\':'u':'0':'0':'0':intToDigit (ord c):escape xs - | ord c < 0x20 -> '\\':'u':'0':'0':'1':intToDigit (ord c - 0x10):escape xs - | otherwise -> c : escape xs + escape (x : xs) = case x of + '\\' -> '\\' : '\\' : escape xs + '"' -> '\\' : '"' : escape xs + '\b' -> '\\' : 'b' : escape xs + '\f' -> '\\' : 'f' : escape xs + '\n' -> '\\' : 'n' : escape xs + '\r' -> '\\' : 'r' : escape xs + '\t' -> '\\' : 't' : escape xs + c + | ord c < 0x10 -> '\\' : 'u' : '0' : '0' : '0' : intToDigit (ord c) : escape xs + | ord c < 0x20 -> '\\' : 'u' : '0' : '0' : '1' : intToDigit (ord c - 0x10) : escape xs + | otherwise -> c : escape xs -- unescaped = %x20-21 / %x23-5B / %x5D-10FFFF - needsEscape c = ord c < 0x20 || c `elem` ['\\','"'] + needsEscape c = ord c < 0x20 || c `elem` ['\\', '"'] ------------------------------------------------------------------------------ -- FromJSON @@ -242,33 +242,34 @@ escapeString s -- | Elements of a JSON path used to describe the location of an -- error. data JSONPathElement - = Key String - -- ^ JSON path element of a key into an object, - -- \"object.key\". - | Index !Int - -- ^ JSON path element of an index into an - -- array, \"array[index]\". + = -- | JSON path element of a key into an object, + -- \"object.key\". + Key String + | -- | JSON path element of an index into an + -- array, \"array[index]\". + Index !Int deriving (Eq, Show, Ord) type JSONPath = [JSONPathElement] -- | Failure continuation. -type Failure f r = JSONPath -> String -> f r +type Failure f r = JSONPath -> String -> f r -- | Success continuation. type Success a f r = a -> f r -newtype Parser a = Parser { - runParser :: forall f r. - JSONPath - -> Failure f r - -> Success a f r - -> f r - } +newtype Parser a = Parser + { runParser + :: forall f r + . JSONPath + -> Failure f r + -> Success a f r + -> f r + } modifyFailure :: (String -> String) -> Parser a -> Parser a modifyFailure f (Parser p) = Parser $ \path kf ks -> - p path (\p' m -> kf p' (f m)) ks + p path (\p' m -> kf p' (f m)) ks prependFailure :: String -> Parser a -> Parser a prependFailure = modifyFailure . (++) @@ -278,41 +279,44 @@ prependContext name = prependFailure ("parsing " ++ name ++ " failed, ") typeMismatch :: String -> Value -> Parser a typeMismatch expected actual = - fail $ "expected " ++ expected ++ ", but encountered " ++ typeOf actual + fail $ "expected " ++ expected ++ ", but encountered " ++ typeOf actual instance Monad.Monad Parser where - m >>= g = Parser $ \path kf ks -> - runParser m path kf - (\a -> runParser (g a) path kf ks) - return = pure + m >>= g = Parser $ \path kf ks -> + runParser + m + path + kf + (\a -> runParser (g a) path kf ks) + return = pure instance Fail.MonadFail Parser where - fail msg = Parser $ \path kf _ks -> kf (reverse path) msg + fail msg = Parser $ \path kf _ks -> kf (reverse path) msg instance Functor Parser where - fmap f m = Parser $ \path kf ks -> - let ks' a = ks (f a) - in runParser m path kf ks' + fmap f m = Parser $ \path kf ks -> + let ks' a = ks (f a) + in runParser m path kf ks' instance Applicative Parser where - pure a = Parser $ \_path _kf ks -> ks a - (<*>) = apP + pure a = Parser $ \_path _kf ks -> ks a + (<*>) = apP instance Alternative Parser where - empty = fail "empty" - (<|>) = mplus + empty = fail "empty" + (<|>) = mplus instance MonadPlus Parser where - mzero = fail "mzero" - mplus a b = Parser $ \path kf ks -> - runParser a path (\_ _ -> runParser b path kf ks) ks + mzero = fail "mzero" + mplus a b = Parser $ \path kf ks -> + runParser a path (\_ _ -> runParser b path kf ks) ks instance Semigroup (Parser a) where - (<>) = mplus + (<>) = mplus instance Monoid (Parser a) where - mempty = fail "mempty" - mappend = (<>) + mempty = fail "mempty" + mappend = (<>) apP :: Parser (a -> b) -> Parser a -> Parser b apP d e = do @@ -320,7 +324,7 @@ apP d e = do b <$> e () :: Parser a -> JSONPathElement -> Parser a -p pathElem = Parser $ \path kf ks -> runParser p (pathElem:path) kf ks +p pathElem = Parser $ \path kf ks -> runParser p (pathElem : path) kf ks parseIndexedJSON :: (Value -> Parser a) -> Int -> Value -> Parser a parseIndexedJSON p idx value = p value Index idx @@ -329,126 +333,128 @@ unexpected :: Value -> Parser a unexpected actual = fail $ "unexpected " ++ typeOf actual withObject :: String -> (Object -> Parser a) -> Value -> Parser a -withObject _ f (Object obj) = f obj -withObject name _ v = prependContext name (typeMismatch "Object" v) +withObject _ f (Object obj) = f obj +withObject name _ v = prependContext name (typeMismatch "Object" v) withArray :: String -> ([Value] -> Parser a) -> Value -> Parser a -withArray _ f (Array arr) = f arr -withArray name _ v = prependContext name (typeMismatch "Array" v) +withArray _ f (Array arr) = f arr +withArray name _ v = prependContext name (typeMismatch "Array" v) withString :: String -> (String -> Parser a) -> Value -> Parser a -withString _ f (String txt) = f txt -withString name _ v = prependContext name (typeMismatch "String" v) +withString _ f (String txt) = f txt +withString name _ v = prependContext name (typeMismatch "String" v) withDouble :: String -> (Double -> Parser a) -> Value -> Parser a -withDouble _ f (Number duble) = f duble -withDouble name _ v = prependContext name (typeMismatch "Number" v) +withDouble _ f (Number duble) = f duble +withDouble name _ v = prependContext name (typeMismatch "Number" v) withBool :: String -> (Bool -> Parser a) -> Value -> Parser a -withBool _ f (Bool arr) = f arr -withBool name _ v = prependContext name (typeMismatch "Boolean" v) +withBool _ f (Bool arr) = f arr +withBool name _ v = prependContext name (typeMismatch "Boolean" v) class FromJSON a where - parseJSON :: Value -> Parser a + parseJSON :: Value -> Parser a - parseJSONList :: Value -> Parser [a] - parseJSONList = withArray "[]" (zipWithM (parseIndexedJSON parseJSON) [0..]) + parseJSONList :: Value -> Parser [a] + parseJSONList = withArray "[]" (zipWithM (parseIndexedJSON parseJSON) [0 ..]) instance FromJSON Bool where - parseJSON (Bool b) = pure b - parseJSON v = typeMismatch "Bool" v + parseJSON (Bool b) = pure b + parseJSON v = typeMismatch "Bool" v instance FromJSON () where - parseJSON = - withArray "()" $ \v -> - if null v - then pure () - else prependContext "()" $ fail "expected an empty array" + parseJSON = + withArray "()" $ \v -> + if null v + then pure () + else prependContext "()" $ fail "expected an empty array" instance FromJSON Char where - parseJSON = withString "Char" parseChar + parseJSON = withString "Char" parseChar - parseJSONList (String s) = pure s - parseJSONList v = typeMismatch "String" v + parseJSONList (String s) = pure s + parseJSONList v = typeMismatch "String" v parseChar :: String -> Parser Char parseChar t = - if length t == 1 - then pure $ head t - else prependContext "Char" $ fail "expected a string of length 1" + if length t == 1 + then pure $ head t + else prependContext "Char" $ fail "expected a string of length 1" parseRealFloat :: RealFloat a => String -> Value -> Parser a -parseRealFloat _ (Number s) = pure $ realToFrac s -parseRealFloat _ Null = pure (0/0) -parseRealFloat name v = prependContext name (unexpected v) +parseRealFloat _ (Number s) = pure $ realToFrac s +parseRealFloat _ Null = pure (0 / 0) +parseRealFloat name v = prependContext name (unexpected v) instance FromJSON Double where - parseJSON = parseRealFloat "Double" + parseJSON = parseRealFloat "Double" instance FromJSON Float where - parseJSON = parseRealFloat "Float" + parseJSON = parseRealFloat "Float" parseNatural :: Integer -> Parser Natural parseNatural integer = - if integer < 0 then - fail $ "parsing Natural failed, unexpected negative number " <> show integer - else - pure $ fromIntegral integer + if integer < 0 + then fail $ "parsing Natural failed, unexpected negative number " <> show integer + else pure $ fromIntegral integer parseIntegralFromDouble :: Integral a => Double -> Parser a parseIntegralFromDouble d = - let r = toRational d - x = truncate r - in if toRational x == r - then pure x - else fail $ "unexpected floating number " <> show d + let r = toRational d + x = truncate r + in if toRational x == r + then pure x + else fail $ "unexpected floating number " <> show d parseIntegral :: Integral a => String -> Value -> Parser a parseIntegral name = withDouble name parseIntegralFromDouble instance FromJSON Integer where - parseJSON = parseIntegral "Integer" + parseJSON = parseIntegral "Integer" instance FromJSON Natural where - parseJSON = withDouble "Natural" - (parseIntegralFromDouble >=> parseNatural) + parseJSON = + withDouble + "Natural" + (parseIntegralFromDouble >=> parseNatural) instance FromJSON Int where - parseJSON = parseIntegral "Int" + parseJSON = parseIntegral "Int" instance FromJSON Int8 where - parseJSON = parseIntegral "Int8" + parseJSON = parseIntegral "Int8" instance FromJSON Int16 where - parseJSON = parseIntegral "Int16" + parseJSON = parseIntegral "Int16" instance FromJSON Int32 where - parseJSON = parseIntegral "Int32" + parseJSON = parseIntegral "Int32" instance FromJSON Int64 where - parseJSON = parseIntegral "Int64" + parseJSON = parseIntegral "Int64" instance FromJSON Word where - parseJSON = parseIntegral "Word" + parseJSON = parseIntegral "Word" instance FromJSON Word8 where - parseJSON = parseIntegral "Word8" + parseJSON = parseIntegral "Word8" instance FromJSON Word16 where - parseJSON = parseIntegral "Word16" + parseJSON = parseIntegral "Word16" instance FromJSON Word32 where - parseJSON = parseIntegral "Word32" + parseJSON = parseIntegral "Word32" instance FromJSON Word64 where - parseJSON = parseIntegral "Word64" + parseJSON = parseIntegral "Word64" instance FromJSON a => FromJSON [a] where - parseJSON = parseJSONList + parseJSON = parseJSONList -data Result a = Error String - | Success a - deriving (Eq, Show) +data Result a + = Error String + | Success a + deriving (Eq, Show) fromJSON :: FromJSON a => Value -> Result a fromJSON = parse parseJSON @@ -458,7 +464,8 @@ parse m v = runParser (m v) [] (const Error) Success parseEither :: (a -> Parser b) -> a -> Either String b parseEither m v = runParser (m v) [] onError Right - where onError path msg = Left (formatError path msg) + where + onError path msg = Left (formatError path msg) formatError :: JSONPath -> String -> String formatError path msg = "Error in " ++ formatPath path ++ ": " ++ msg @@ -470,18 +477,18 @@ formatRelativePath :: JSONPath -> String formatRelativePath path = format "" path where format :: String -> JSONPath -> String - format pfx [] = pfx - format pfx (Index idx:parts) = format (pfx ++ "[" ++ show idx ++ "]") parts - format pfx (Key key:parts) = format (pfx ++ formatKey key) parts + format pfx [] = pfx + format pfx (Index idx : parts) = format (pfx ++ "[" ++ show idx ++ "]") parts + format pfx (Key key : parts) = format (pfx ++ formatKey key) parts formatKey :: String -> String formatKey key - | isIdentifierKey key = "." ++ key - | otherwise = "['" ++ escapeKey key ++ "']" + | isIdentifierKey key = "." ++ key + | otherwise = "['" ++ escapeKey key ++ "']" isIdentifierKey :: String -> Bool - isIdentifierKey [] = False - isIdentifierKey (x:xs) = isAlpha x && all isAlphaNum xs + isIdentifierKey [] = False + isIdentifierKey (x : xs) = isAlpha x && all isAlphaNum xs escapeKey :: String -> String escapeKey = concatMap escapeChar @@ -489,70 +496,66 @@ formatRelativePath path = format "" path escapeChar :: Char -> String escapeChar '\'' = "\\'" escapeChar '\\' = "\\\\" - escapeChar c = [c] + escapeChar c = [c] explicitParseField :: (Value -> Parser a) -> Object -> String -> Parser a explicitParseField p obj key = - case key `lookup` obj of - Nothing -> fail $ "key " ++ key ++ " not found" - Just v -> p v Key key + case key `lookup` obj of + Nothing -> fail $ "key " ++ key ++ " not found" + Just v -> p v Key key (.:) :: FromJSON a => Object -> String -> Parser a (.:) = explicitParseField parseJSON explicitParseFieldMaybe :: (Value -> Parser a) -> Object -> String -> Parser (Maybe a) explicitParseFieldMaybe p obj key = - case key `lookup` obj of - Nothing -> pure Nothing - Just v -> Just <$> p v Key key + case key `lookup` obj of + Nothing -> pure Nothing + Just v -> Just <$> p v Key key (.:?) :: FromJSON a => Object -> String -> Parser (Maybe a) (.:?) = explicitParseFieldMaybe parseJSON - decodeWith :: (Value -> Result a) -> BSL.ByteString -> Maybe a decodeWith decoder bsl = - case Parsec.parse parseJSONValue "" bsl of - Left _ -> Nothing - Right json -> - case decoder json of - Success a -> Just a - Error _ -> Nothing + case Parsec.parse parseJSONValue "" bsl of + Left _ -> Nothing + Right json -> + case decoder json of + Success a -> Just a + Error _ -> Nothing decode :: FromJSON a => BSL.ByteString -> Maybe a decode = decodeWith fromJSON eitherDecodeWith :: (Value -> Result a) -> BSL.ByteString -> Either String a eitherDecodeWith decoder bsl = - case Parsec.parse parseJSONValue "" bsl of - Left parsecError -> Left (show parsecError) - Right json -> - case decoder json of - Success a -> Right a - Error err -> Left err + case Parsec.parse parseJSONValue "" bsl of + Left parsecError -> Left (show parsecError) + Right json -> + case decoder json of + Success a -> Right a + Error err -> Left err eitherDecode :: FromJSON a => BSL.ByteString -> Either String a eitherDecode = eitherDecodeWith fromJSON - decodeFile :: FromJSON a => FilePath -> IO (Maybe a) decodeFile filePath = do - parsecResult <- Parsec.Lazy.parseFromFile parseJSONValue filePath - case parsecResult of - Right r -> - case fromJSON r of - Success a -> return (Just a) - Error _ -> return Nothing - Left _ -> return Nothing - + parsecResult <- Parsec.Lazy.parseFromFile parseJSONValue filePath + case parsecResult of + Right r -> + case fromJSON r of + Success a -> return (Just a) + Error _ -> return Nothing + Left _ -> return Nothing eitherDecodeFile :: FromJSON a => FilePath -> IO (Either String a) eitherDecodeFile filePath = do - parsecResult <- Parsec.Lazy.parseFromFile parseJSONValue filePath - case parsecResult of - Right r -> - case fromJSON r of - Success a -> return (Right a) - Error err -> return (Left err) - Left err -> return $ Left (show err) - + parsecResult <- Parsec.Lazy.parseFromFile parseJSONValue filePath + case parsecResult of + Right r -> + case fromJSON r of + Success a -> return (Right a) + Error err -> return (Left err) + Left err -> return $ Left (show err) diff --git a/haddock-api/src/Haddock/Utils/Json/Parser.hs b/haddock-api/src/Haddock/Utils/Json/Parser.hs index 018e27d307..79fc877a23 100644 --- a/haddock-api/src/Haddock/Utils/Json/Parser.hs +++ b/haddock-api/src/Haddock/Utils/Json/Parser.hs @@ -1,6 +1,5 @@ -- | Json "Parsec" parser, based on -- [json](https://hackage.haskell.org/package/json) package. --- module Haddock.Utils.Json.Parser ( parseJSONValue ) where @@ -9,9 +8,9 @@ import Prelude hiding (null) import Control.Applicative (Alternative (..)) import Control.Monad (MonadPlus (..)) +import qualified Data.ByteString.Lazy.Char8 as BSCL import Data.Char (isHexDigit) import Data.Functor (($>)) -import qualified Data.ByteString.Lazy.Char8 as BSCL import Numeric import Text.Parsec.ByteString.Lazy (Parser) import Text.ParserCombinators.Parsec (()) @@ -27,76 +26,98 @@ tok p = p <* Parsec.spaces parseValue :: Parser Value parseValue = - parseNull - <|> Bool <$> parseBoolean - <|> Array <$> parseArray - <|> String <$> parseString - <|> Object <$> parseObject - <|> Number <$> parseNumber - "JSON value" + parseNull + <|> Bool + <$> parseBoolean + <|> Array + <$> parseArray + <|> String + <$> parseString + <|> Object + <$> parseObject + <|> Number + <$> parseNumber + "JSON value" parseNull :: Parser Value -parseNull = tok - $ Parsec.string "null" - $> Null +parseNull = + tok $ + Parsec.string "null" + $> Null parseBoolean :: Parser Bool -parseBoolean = tok - $ Parsec.string "true" $> True - <|> Parsec.string "false" $> False +parseBoolean = + tok $ + Parsec.string "true" + $> True + <|> Parsec.string "false" + $> False parseArray :: Parser [Value] parseArray = - Parsec.between - (tok (Parsec.char '[')) - (tok (Parsec.char ']')) - (parseValue `Parsec.sepBy` tok (Parsec.char ',')) + Parsec.between + (tok (Parsec.char '[')) + (tok (Parsec.char ']')) + (parseValue `Parsec.sepBy` tok (Parsec.char ',')) parseString :: Parser String parseString = - Parsec.between - (tok (Parsec.char '"')) - (tok (Parsec.char '"')) - (many char) + Parsec.between + (tok (Parsec.char '"')) + (tok (Parsec.char '"')) + (many char) where - char = (Parsec.char '\\' >> escapedChar) - <|> Parsec.satisfy (\x -> x /= '"' && x /= '\\') + char = + (Parsec.char '\\' >> escapedChar) + <|> Parsec.satisfy (\x -> x /= '"' && x /= '\\') escapedChar = - Parsec.char '"' $> '"' - <|> Parsec.char '\\' $> '\\' - <|> Parsec.char '/' $> '/' - <|> Parsec.char 'b' $> '\b' - <|> Parsec.char 'f' $> '\f' - <|> Parsec.char 'n' $> '\n' - <|> Parsec.char 'r' $> '\r' - <|> Parsec.char 't' $> '\t' - <|> Parsec.char 'u' *> uni - "escape character" + Parsec.char '"' + $> '"' + <|> Parsec.char '\\' + $> '\\' + <|> Parsec.char '/' + $> '/' + <|> Parsec.char 'b' + $> '\b' + <|> Parsec.char 'f' + $> '\f' + <|> Parsec.char 'n' + $> '\n' + <|> Parsec.char 'r' + $> '\r' + <|> Parsec.char 't' + $> '\t' + <|> Parsec.char 'u' + *> uni + "escape character" uni = check =<< Parsec.count 4 (Parsec.satisfy isHexDigit) where - check x | code <= max_char = return (toEnum code) - | otherwise = mzero - where code = fst $ head $ readHex x - max_char = fromEnum (maxBound :: Char) + check x + | code <= max_char = return (toEnum code) + | otherwise = mzero + where + code = fst $ head $ readHex x + max_char = fromEnum (maxBound :: Char) parseObject :: Parser Object parseObject = - Parsec.between - (tok (Parsec.char '{')) - (tok (Parsec.char '}')) - (field `Parsec.sepBy` tok (Parsec.char ',')) + Parsec.between + (tok (Parsec.char '{')) + (tok (Parsec.char '}')) + (field `Parsec.sepBy` tok (Parsec.char ',')) where field :: Parser (String, Value) - field = (,) + field = + (,) <$> parseString - <* tok (Parsec.char ':') + <* tok (Parsec.char ':') <*> parseValue parseNumber :: Parser Double parseNumber = tok $ do s <- BSCL.unpack <$> Parsec.getInput case readSigned readFloat s of - [(n,s')] -> Parsec.setInput (BSCL.pack s') $> n - _ -> mzero + [(n, s')] -> Parsec.setInput (BSCL.pack s') $> n + _ -> mzero diff --git a/haddock-api/src/Haddock/Utils/Json/Types.hs b/haddock-api/src/Haddock/Utils/Json/Types.hs index 1174329ce3..7887ecf16c 100644 --- a/haddock-api/src/Haddock/Utils/Json/Types.hs +++ b/haddock-api/src/Haddock/Utils/Json/Types.hs @@ -1,5 +1,5 @@ module Haddock.Utils.Json.Types - ( Value(..) + ( Value (..) , typeOf , Pair , Object @@ -11,22 +11,23 @@ import Data.String -- TODO: We may want to replace 'String' with 'Text' or 'ByteString' -- | A JSON value represented as a Haskell value. -data Value = Object !Object - | Array [Value] - | String String - | Number !Double - | Bool !Bool - | Null - deriving (Eq, Read, Show) +data Value + = Object !Object + | Array [Value] + | String String + | Number !Double + | Bool !Bool + | Null + deriving (Eq, Read, Show) typeOf :: Value -> String typeOf v = case v of - Object _ -> "Object" - Array _ -> "Array" - String _ -> "String" - Number _ -> "Number" - Bool _ -> "Boolean" - Null -> "Null" + Object _ -> "Object" + Array _ -> "Array" + String _ -> "String" + Number _ -> "Number" + Bool _ -> "Boolean" + Null -> "Null" -- | A key\/value pair for an 'Object' type Pair = (String, Value) diff --git a/haddock-api/src/Haddock/Version.hs b/haddock-api/src/Haddock/Version.hs index 4e9a581a7f..4ff3f4c000 100644 --- a/haddock-api/src/Haddock/Version.hs +++ b/haddock-api/src/Haddock/Version.hs @@ -1,5 +1,9 @@ {-# LANGUAGE CPP #-} + +----------------------------------------------------------------------------- + ----------------------------------------------------------------------------- + -- | -- Module : Haddock.Version -- Copyright : (c) Simon Marlow 2003 @@ -8,23 +12,24 @@ -- Maintainer : haddock@projects.haskell.org -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------ -module Haddock.Version ( - projectName, projectVersion, projectUrl -) where +module Haddock.Version + ( projectName + , projectVersion + , projectUrl + ) where #ifdef IN_GHC_TREE import Paths_haddock ( version ) #else import Paths_haddock_api ( version ) #endif -import Data.Version ( showVersion ) +import Data.Version (showVersion) projectName :: String projectName = "Haddock" projectUrl :: String -projectUrl = "http://www.haskell.org/haddock/" +projectUrl = "http://www.haskell.org/haddock/" projectVersion :: String projectVersion = showVersion version diff --git a/haddock-api/test/Haddock/Backends/Hyperlinker/ParserSpec.hs b/haddock-api/test/Haddock/Backends/Hyperlinker/ParserSpec.hs index 3b4cbb9619..7ec182bffa 100644 --- a/haddock-api/test/Haddock/Backends/Hyperlinker/ParserSpec.hs +++ b/haddock-api/test/Haddock/Backends/Hyperlinker/ParserSpec.hs @@ -1,16 +1,17 @@ {-# LANGUAGE OverloadedStrings #-} + module Haddock.Backends.Hyperlinker.ParserSpec (main, spec) where import Test.Hspec import Test.QuickCheck -import GHC ( runGhc, getSessionDynFlags ) -import GHC.Driver.Session ( DynFlags ) import Control.Monad.IO.Class +import GHC (getSessionDynFlags, runGhc) +import GHC.Driver.Session (DynFlags) -import Data.String ( fromString ) -import Data.ByteString ( ByteString ) -import qualified Data.ByteString as BS +import Data.ByteString (ByteString) +import qualified Data.ByteString as BS +import Data.String (fromString) import Haddock (getGhcDirs) import Haddock.Backends.Hyperlinker.Parser @@ -23,15 +24,12 @@ withDynFlags cont = do dflags <- getSessionDynFlags liftIO $ cont dflags - main :: IO () main = hspec spec - spec :: Spec spec = describe "parse" parseSpec - -- | Defined for its instance of 'Arbitrary'. Represents strings that, when -- considered as GHC source, won't be rewritten. newtype NoGhcRewrite = NoGhcRewrite String deriving (Show, Eq) @@ -39,124 +37,180 @@ newtype NoGhcRewrite = NoGhcRewrite String deriving (Show, Eq) -- | Filter out strings where GHC would replace/remove some characters during -- lexing. noGhcRewrite :: String -> Bool -noGhcRewrite ('\t':_) = False -- GHC replaces tabs with 8 spaces -noGhcRewrite ('\r':_) = False -noGhcRewrite ('\f':_) = False -noGhcRewrite ('\v':_) = False -noGhcRewrite (' ':'\n':_) = False -- GHC strips whitespace on empty lines -noGhcRewrite (_:s) = noGhcRewrite s +noGhcRewrite ('\t' : _) = False -- GHC replaces tabs with 8 spaces +noGhcRewrite ('\r' : _) = False +noGhcRewrite ('\f' : _) = False +noGhcRewrite ('\v' : _) = False +noGhcRewrite (' ' : '\n' : _) = False -- GHC strips whitespace on empty lines +noGhcRewrite (_ : s) = noGhcRewrite s noGhcRewrite "" = True instance Arbitrary NoGhcRewrite where arbitrary = fmap NoGhcRewrite (arbitrary `suchThat` noGhcRewrite) - shrink (NoGhcRewrite src) = [ NoGhcRewrite shrunk - | shrunk <- shrink src - , noGhcRewrite shrunk - ] - + shrink (NoGhcRewrite src) = + [ NoGhcRewrite shrunk + | shrunk <- shrink src + , noGhcRewrite shrunk + ] parseSpec :: Spec parseSpec = around withDynFlags $ do - - it "is total" $ \dflags -> - property $ \src -> length (parse dflags "" (fromString src)) `shouldSatisfy` (>= 0) - - it "retains file layout" $ \dflags -> - property $ \(NoGhcRewrite src) -> - let orig = fromString src - lexed = BS.concat (map tkValue (parse dflags "" orig)) - in lexed == orig - - context "when parsing single-line comments" $ do - - it "should ignore content until the end of line" $ \dflags -> - shouldParseTo - "-- some very simple comment\nidentifier" - [TkComment, TkSpace, TkIdentifier] - dflags - - it "should allow endline escaping" $ \dflags -> - shouldParseTo - "#define first line\\\nsecond line\\\nand another one" - [TkCpp] - dflags - - context "when parsing multi-line comments" $ do - - it "should support nested comments" $ \dflags -> - shouldParseTo - "{- comment {- nested -} still comment -} {- next comment -}" - [TkComment, TkSpace, TkComment] - dflags - - it "should distinguish compiler pragma" $ \dflags -> - shouldParseTo - "{- comment -}{-# LANGUAGE GADTs #-}{- comment -}" - [TkComment, TkPragma, TkComment] - dflags - - it "should recognize preprocessor directives" $ \dflags -> do - shouldParseTo - "\n#define foo bar" - [TkCpp] - dflags - shouldParseTo - "x # y" - [TkIdentifier, TkSpace, TkOperator, TkSpace,TkIdentifier] - dflags - - it "should distinguish basic language constructs" $ \dflags -> do - - shouldParseTo - "(* 2) <$> (\"abc\", foo)" - [ TkSpecial, TkOperator, TkSpace, TkNumber, TkSpecial - , TkSpace, TkOperator, TkSpace - , TkSpecial, TkString, TkSpecial, TkSpace, TkIdentifier, TkSpecial - ] - dflags - - shouldParseTo - "let foo' = foo in foo' + foo'" - [ TkKeyword, TkSpace, TkIdentifier - , TkSpace, TkGlyph, TkSpace - , TkIdentifier, TkSpace, TkKeyword, TkSpace - , TkIdentifier, TkSpace, TkOperator, TkSpace, TkIdentifier - ] - dflags - - shouldParseTo - "square x = y^2 where y = x" - [ TkIdentifier, TkSpace, TkIdentifier - , TkSpace, TkGlyph, TkSpace - , TkIdentifier, TkOperator, TkNumber - , TkSpace, TkKeyword, TkSpace - , TkIdentifier, TkSpace, TkGlyph, TkSpace, TkIdentifier - ] - dflags - - it "should parse do-notation syntax" $ \dflags -> do - shouldParseTo - "do { foo <- getLine; putStrLn foo }" - [ TkKeyword, TkSpace, TkSpecial, TkSpace - , TkIdentifier, TkSpace, TkGlyph, TkSpace - , TkIdentifier, TkSpecial, TkSpace - , TkIdentifier, TkSpace, TkIdentifier, TkSpace, TkSpecial - ] - dflags - - shouldParseTo - (fromString $ unlines - [ "do" - , " foo <- getLine" - , " putStrLn foo" - ]) - [ TkKeyword, TkSpace, TkIdentifier - , TkSpace, TkGlyph, TkSpace, TkIdentifier, TkSpace - , TkIdentifier, TkSpace, TkIdentifier, TkSpace + it "is total" $ \dflags -> + property $ \src -> length (parse dflags "" (fromString src)) `shouldSatisfy` (>= 0) + + it "retains file layout" $ \dflags -> + property $ \(NoGhcRewrite src) -> + let orig = fromString src + lexed = BS.concat (map tkValue (parse dflags "" orig)) + in lexed == orig + + context "when parsing single-line comments" $ do + it "should ignore content until the end of line" $ \dflags -> + shouldParseTo + "-- some very simple comment\nidentifier" + [TkComment, TkSpace, TkIdentifier] + dflags + + it "should allow endline escaping" $ \dflags -> + shouldParseTo + "#define first line\\\nsecond line\\\nand another one" + [TkCpp] + dflags + + context "when parsing multi-line comments" $ do + it "should support nested comments" $ \dflags -> + shouldParseTo + "{- comment {- nested -} still comment -} {- next comment -}" + [TkComment, TkSpace, TkComment] + dflags + + it "should distinguish compiler pragma" $ \dflags -> + shouldParseTo + "{- comment -}{-# LANGUAGE GADTs #-}{- comment -}" + [TkComment, TkPragma, TkComment] + dflags + + it "should recognize preprocessor directives" $ \dflags -> do + shouldParseTo + "\n#define foo bar" + [TkCpp] + dflags + shouldParseTo + "x # y" + [TkIdentifier, TkSpace, TkOperator, TkSpace, TkIdentifier] + dflags + + it "should distinguish basic language constructs" $ \dflags -> do + shouldParseTo + "(* 2) <$> (\"abc\", foo)" + [ TkSpecial + , TkOperator + , TkSpace + , TkNumber + , TkSpecial + , TkSpace + , TkOperator + , TkSpace + , TkSpecial + , TkString + , TkSpecial + , TkSpace + , TkIdentifier + , TkSpecial + ] + dflags + + shouldParseTo + "let foo' = foo in foo' + foo'" + [ TkKeyword + , TkSpace + , TkIdentifier + , TkSpace + , TkGlyph + , TkSpace + , TkIdentifier + , TkSpace + , TkKeyword + , TkSpace + , TkIdentifier + , TkSpace + , TkOperator + , TkSpace + , TkIdentifier + ] + dflags + + shouldParseTo + "square x = y^2 where y = x" + [ TkIdentifier + , TkSpace + , TkIdentifier + , TkSpace + , TkGlyph + , TkSpace + , TkIdentifier + , TkOperator + , TkNumber + , TkSpace + , TkKeyword + , TkSpace + , TkIdentifier + , TkSpace + , TkGlyph + , TkSpace + , TkIdentifier + ] + dflags + + it "should parse do-notation syntax" $ \dflags -> do + shouldParseTo + "do { foo <- getLine; putStrLn foo }" + [ TkKeyword + , TkSpace + , TkSpecial + , TkSpace + , TkIdentifier + , TkSpace + , TkGlyph + , TkSpace + , TkIdentifier + , TkSpecial + , TkSpace + , TkIdentifier + , TkSpace + , TkIdentifier + , TkSpace + , TkSpecial + ] + dflags + + shouldParseTo + ( fromString $ + unlines + [ "do" + , " foo <- getLine" + , " putStrLn foo" ] - dflags + ) + [ TkKeyword + , TkSpace + , TkIdentifier + , TkSpace + , TkGlyph + , TkSpace + , TkIdentifier + , TkSpace + , TkIdentifier + , TkSpace + , TkIdentifier + , TkSpace + ] + dflags where shouldParseTo :: ByteString -> [TokenType] -> DynFlags -> Expectation - shouldParseTo str tokens dflags = [ tkType tok - | tok <- parse dflags "" str - , not (BS.null (tkValue tok)) ] `shouldBe` tokens + shouldParseTo str tokens dflags = + [ tkType tok + | tok <- parse dflags "" str + , not (BS.null (tkValue tok)) + ] + `shouldBe` tokens diff --git a/haddock-library/Setup.hs b/haddock-library/Setup.hs index 9a994af677..e8ef27dbba 100644 --- a/haddock-library/Setup.hs +++ b/haddock-library/Setup.hs @@ -1,2 +1,3 @@ import Distribution.Simple + main = defaultMain diff --git a/haddock-library/fixtures/Fixtures.hs b/haddock-library/fixtures/Fixtures.hs index 374a664c60..21655360e4 100644 --- a/haddock-library/fixtures/Fixtures.hs +++ b/haddock-library/fixtures/Fixtures.hs @@ -1,5 +1,7 @@ -{-# LANGUAGE DeriveGeneric, StandaloneDeriving #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE StandaloneDeriving #-} {-# OPTIONS_GHC -fno-warn-orphans #-} + module Main (main) where import Control.Applicative ((<|>)) @@ -9,96 +11,97 @@ import Data.Foldable (traverse_) import Data.List (foldl') import Data.Traversable (for) import GHC.Generics (Generic) -import Prelude import System.Directory (getDirectoryContents) import System.Exit (exitFailure) import System.FilePath import System.IO +import Prelude import Data.TreeDiff import Data.TreeDiff.Golden import qualified Options.Applicative as O -import Documentation.Haddock.Types import qualified Documentation.Haddock.Parser as Parse +import Documentation.Haddock.Types type Doc id = DocH () id data Fixture = Fixture - { fixtureName :: FilePath - , fixtureOutput :: FilePath - } - deriving Show + { fixtureName :: FilePath + , fixtureOutput :: FilePath + } + deriving (Show) -data Result = Result - { _resultSuccess :: !Int - , _resultTotal :: !Int - } - deriving Show +data Result = Result + { _resultSuccess :: !Int + , _resultTotal :: !Int + } + deriving (Show) combineResults :: Result -> Result -> Result combineResults (Result s t) (Result s' t') = Result (s + s') (t + t') readFixtures :: IO [Fixture] readFixtures = do - let dir = "fixtures/examples" - files <- getDirectoryContents dir - let inputs = filter (\fp -> takeExtension fp == ".input") files - return $ flip map inputs $ \fp -> Fixture - { fixtureName = dir fp - , fixtureOutput = dir fp -<.> "parsed" - } + let dir = "fixtures/examples" + files <- getDirectoryContents dir + let inputs = filter (\fp -> takeExtension fp == ".input") files + return $ flip map inputs $ \fp -> + Fixture + { fixtureName = dir fp + , fixtureOutput = dir fp -<.> "parsed" + } goldenFixture - :: String - -> IO Expr - -> IO Expr - -> (Expr -> Expr -> IO (Maybe String)) - -> (Expr -> IO ()) - -> IO Result + :: String + -> IO Expr + -> IO Expr + -> (Expr -> Expr -> IO (Maybe String)) + -> (Expr -> IO ()) + -> IO Result goldenFixture name expect actual cmp wrt = do - putStrLn $ "running " ++ name - a <- actual - e <- expect `catch` handler a - mres <- cmp e a - case mres of - Nothing -> return (Result 1 1) - Just str -> do - putStrLn str - return (Result 0 1) + putStrLn $ "running " ++ name + a <- actual + e <- expect `catch` handler a + mres <- cmp e a + case mres of + Nothing -> return (Result 1 1) + Just str -> do + putStrLn str + return (Result 0 1) where handler :: Expr -> IOException -> IO Expr handler a exc = do - putStrLn $ "Caught " ++ show exc - putStrLn "Accepting the test" - wrt a - return a + putStrLn $ "Caught " ++ show exc + putStrLn "Accepting the test" + wrt a + return a runFixtures :: [Fixture] -> IO () runFixtures fixtures = do - results <- for fixtures $ \(Fixture i o) -> do - let name = takeBaseName i - let readDoc = do - input <- readFile i - return (parseString input) - ediffGolden goldenFixture name o readDoc - case foldl' combineResults (Result 0 0) results of - Result s t -> do - putStrLn $ "Fixtures: success " ++ show s ++ "; total " ++ show t - when (s /= t) exitFailure + results <- for fixtures $ \(Fixture i o) -> do + let name = takeBaseName i + let readDoc = do + input <- readFile i + return (parseString input) + ediffGolden goldenFixture name o readDoc + case foldl' combineResults (Result 0 0) results of + Result s t -> do + putStrLn $ "Fixtures: success " ++ show s ++ "; total " ++ show t + when (s /= t) exitFailure listFixtures :: [Fixture] -> IO () listFixtures = traverse_ $ \(Fixture i _) -> do - let name = takeBaseName i - putStrLn name + let name = takeBaseName i + putStrLn name acceptFixtures :: [Fixture] -> IO () acceptFixtures = traverse_ $ \(Fixture i o) -> do - input <- readFile i - let doc = parseString input - let actual = show (prettyExpr $ toExpr doc) ++ "\n" - writeFile o actual + input <- readFile i + let doc = parseString input + let actual = show (prettyExpr $ toExpr doc) ++ "\n" + writeFile o actual parseString :: String -> Doc String parseString = Parse.toRegular . _doc . Parse.parseParas Nothing @@ -107,32 +110,38 @@ data Cmd = CmdRun | CmdAccept | CmdList main :: IO () main = do - hSetBuffering stdout NoBuffering -- For interleaved output when debugging - runCmd =<< O.execParser opts + hSetBuffering stdout NoBuffering -- For interleaved output when debugging + runCmd =<< O.execParser opts where opts = O.info (O.helper <*> cmdParser) O.fullDesc cmdParser :: O.Parser Cmd cmdParser = cmdRun <|> cmdAccept <|> cmdList <|> pure CmdRun - cmdRun = O.flag' CmdRun $ mconcat - [ O.long "run" - , O.help "Run parser fixtures" - ] - - cmdAccept = O.flag' CmdAccept $ mconcat - [ O.long "accept" - , O.help "Run & accept parser fixtures" - ] - - cmdList = O.flag' CmdList $ mconcat - [ O.long "list" - , O.help "List fixtures" - ] + cmdRun = + O.flag' CmdRun $ + mconcat + [ O.long "run" + , O.help "Run parser fixtures" + ] + + cmdAccept = + O.flag' CmdAccept $ + mconcat + [ O.long "accept" + , O.help "Run & accept parser fixtures" + ] + + cmdList = + O.flag' CmdList $ + mconcat + [ O.long "list" + , O.help "List fixtures" + ] runCmd :: Cmd -> IO () -runCmd CmdRun = readFixtures >>= runFixtures -runCmd CmdList = readFixtures >>= listFixtures +runCmd CmdRun = readFixtures >>= runFixtures +runCmd CmdList = readFixtures >>= listFixtures runCmd CmdAccept = readFixtures >>= acceptFixtures ------------------------------------------------------------------------------- @@ -140,7 +149,7 @@ runCmd CmdAccept = readFixtures >>= acceptFixtures ------------------------------------------------------------------------------- deriving instance Generic (DocH mod id) -instance (ToExpr mod, ToExpr id) => ToExpr (DocH mod id) +instance (ToExpr mod, ToExpr id) => ToExpr (DocH mod id) deriving instance Generic (Header id) instance ToExpr id => ToExpr (Header id) diff --git a/haddock-library/src/CompatPrelude.hs b/haddock-library/src/CompatPrelude.hs index 71a9955904..0a98d485ad 100644 --- a/haddock-library/src/CompatPrelude.hs +++ b/haddock-library/src/CompatPrelude.hs @@ -7,9 +7,9 @@ -- | Bridge impedance mismatch of different @base@ versions back till @base-4.5@ (GHC 7.4.2) module CompatPrelude - ( ($>) - , isSymbolChar - ) where + ( ($>) + , isSymbolChar + ) where #if MIN_VERSION_base(4,7,0) import Data.Functor ( ($>) ) @@ -23,7 +23,6 @@ import Text.Read.Lex (isSymbolChar) import Data.Char (GeneralCategory(..), generalCategory) #endif - #if !MIN_VERSION_base(4,7,0) infixl 4 $> diff --git a/haddock-library/src/Documentation/Haddock/Doc.hs b/haddock-library/src/Documentation/Haddock/Doc.hs index 47147e7b30..4e43a10b59 100644 --- a/haddock-library/src/Documentation/Haddock/Doc.hs +++ b/haddock-library/src/Documentation/Haddock/Doc.hs @@ -10,8 +10,8 @@ module Documentation.Haddock.Doc ) where import Control.Applicative ((<|>)) -import Documentation.Haddock.Types import Data.Char (isSpace) +import Documentation.Haddock.Types docConcat :: [DocH mod id] -> DocH mod id docConcat = foldr docAppend DocEmpty @@ -28,9 +28,10 @@ metaDocConcat = foldr metaDocAppend emptyMetaDoc -- in ‘reverse’: this results in the metadata from the ‘latest’ -- paragraphs taking precedence. metaDocAppend :: MetaDoc mod id -> MetaDoc mod id -> MetaDoc mod id -metaDocAppend (MetaDoc { _meta = m, _doc = d }) - (MetaDoc { _meta = m', _doc = d' }) = - MetaDoc { _meta = m' `metaAppend` m, _doc = d `docAppend` d' } +metaDocAppend + (MetaDoc{_meta = m, _doc = d}) + (MetaDoc{_meta = m', _doc = d'}) = + MetaDoc{_meta = m' `metaAppend` m, _doc = d `docAppend` d'} -- | This is not a monoidal append, it uses '<|>' for the '_version' and -- '_package'. @@ -38,18 +39,18 @@ metaAppend :: Meta -> Meta -> Meta metaAppend (Meta v1) (Meta v2) = Meta (v1 <|> v2) emptyMetaDoc :: MetaDoc mod id -emptyMetaDoc = MetaDoc { _meta = emptyMeta, _doc = DocEmpty } +emptyMetaDoc = MetaDoc{_meta = emptyMeta, _doc = DocEmpty} emptyMeta :: Meta emptyMeta = Meta Nothing docAppend :: DocH mod id -> DocH mod id -> DocH mod id -docAppend (DocDefList ds1) (DocDefList ds2) = DocDefList (ds1++ds2) -docAppend (DocDefList ds1) (DocAppend (DocDefList ds2) d) = DocAppend (DocDefList (ds1++ds2)) d +docAppend (DocDefList ds1) (DocDefList ds2) = DocDefList (ds1 ++ ds2) +docAppend (DocDefList ds1) (DocAppend (DocDefList ds2) d) = DocAppend (DocDefList (ds1 ++ ds2)) d docAppend (DocOrderedList ds1) (DocOrderedList ds2) = DocOrderedList (ds1 ++ ds2) -docAppend (DocOrderedList ds1) (DocAppend (DocOrderedList ds2) d) = DocAppend (DocOrderedList (ds1++ds2)) d +docAppend (DocOrderedList ds1) (DocAppend (DocOrderedList ds2) d) = DocAppend (DocOrderedList (ds1 ++ ds2)) d docAppend (DocUnorderedList ds1) (DocUnorderedList ds2) = DocUnorderedList (ds1 ++ ds2) -docAppend (DocUnorderedList ds1) (DocAppend (DocUnorderedList ds2) d) = DocAppend (DocUnorderedList (ds1++ds2)) d +docAppend (DocUnorderedList ds1) (DocAppend (DocUnorderedList ds2) d) = DocAppend (DocUnorderedList (ds1 ++ ds2)) d docAppend DocEmpty d = d docAppend d DocEmpty = d docAppend (DocString s1) (DocString s2) = DocString (s1 ++ s2) @@ -60,21 +61,23 @@ docAppend d1 d2 = DocAppend d1 d2 -- again to make parsing easier - we spot a paragraph whose only item -- is a DocMonospaced and make it into a DocCodeBlock docParagraph :: DocH mod id -> DocH mod id -docParagraph (DocMonospaced p) - = DocCodeBlock (docCodeBlock p) +docParagraph (DocMonospaced p) = + DocCodeBlock (docCodeBlock p) docParagraph (DocAppend (DocString s1) (DocMonospaced p)) - | all isSpace s1 - = DocCodeBlock (docCodeBlock p) -docParagraph (DocAppend (DocString s1) - (DocAppend (DocMonospaced p) (DocString s2))) - | all isSpace s1 && all isSpace s2 - = DocCodeBlock (docCodeBlock p) + | all isSpace s1 = + DocCodeBlock (docCodeBlock p) +docParagraph + ( DocAppend + (DocString s1) + (DocAppend (DocMonospaced p) (DocString s2)) + ) + | all isSpace s1 && all isSpace s2 = + DocCodeBlock (docCodeBlock p) docParagraph (DocAppend (DocMonospaced p) (DocString s2)) - | all isSpace s2 - = DocCodeBlock (docCodeBlock p) -docParagraph p - = DocParagraph p - + | all isSpace s2 = + DocCodeBlock (docCodeBlock p) +docParagraph p = + DocParagraph p -- Drop trailing whitespace from @..@ code blocks. Otherwise this: -- @@ -87,8 +90,8 @@ docParagraph p -- on the final line seems to trigger the extra vertical space. -- docCodeBlock :: DocH mod id -> DocH mod id -docCodeBlock (DocString s) - = DocString (reverse $ dropWhile (`elem` " \t") $ reverse s) -docCodeBlock (DocAppend l r) - = DocAppend l (docCodeBlock r) +docCodeBlock (DocString s) = + DocString (reverse $ dropWhile (`elem` " \t") $ reverse s) +docCodeBlock (DocAppend l r) = + DocAppend l (docCodeBlock r) docCodeBlock d = d diff --git a/haddock-library/src/Documentation/Haddock/Markup.hs b/haddock-library/src/Documentation/Haddock/Markup.hs index 28c5c2ca35..a2fce2330e 100644 --- a/haddock-library/src/Documentation/Haddock/Markup.hs +++ b/haddock-library/src/Documentation/Haddock/Markup.hs @@ -1,99 +1,101 @@ -- | @since 1.4.5 -module Documentation.Haddock.Markup ( - markup +module Documentation.Haddock.Markup + ( markup , idMarkup , plainMarkup ) where import Documentation.Haddock.Types -import Data.Maybe ( fromMaybe ) +import Data.Maybe (fromMaybe) markup :: DocMarkupH mod id a -> DocH mod id -> a -markup m DocEmpty = markupEmpty m -markup m (DocAppend d1 d2) = markupAppend m (markup m d1) (markup m d2) -markup m (DocString s) = markupString m s -markup m (DocParagraph d) = markupParagraph m (markup m d) -markup m (DocIdentifier x) = markupIdentifier m x -markup m (DocIdentifierUnchecked x) = markupIdentifierUnchecked m x -markup m (DocModule (ModLink mo l)) = markupModule m (ModLink mo (fmap (markup m) l)) -markup m (DocWarning d) = markupWarning m (markup m d) -markup m (DocEmphasis d) = markupEmphasis m (markup m d) -markup m (DocBold d) = markupBold m (markup m d) -markup m (DocMonospaced d) = markupMonospaced m (markup m d) -markup m (DocUnorderedList ds) = markupUnorderedList m (map (markup m) ds) -markup m (DocOrderedList ds) = markupOrderedList m (map (\(index, a) -> (index, markup m a)) ds) -markup m (DocDefList ds) = markupDefList m (map (markupPair m) ds) -markup m (DocCodeBlock d) = markupCodeBlock m (markup m d) +markup m DocEmpty = markupEmpty m +markup m (DocAppend d1 d2) = markupAppend m (markup m d1) (markup m d2) +markup m (DocString s) = markupString m s +markup m (DocParagraph d) = markupParagraph m (markup m d) +markup m (DocIdentifier x) = markupIdentifier m x +markup m (DocIdentifierUnchecked x) = markupIdentifierUnchecked m x +markup m (DocModule (ModLink mo l)) = markupModule m (ModLink mo (fmap (markup m) l)) +markup m (DocWarning d) = markupWarning m (markup m d) +markup m (DocEmphasis d) = markupEmphasis m (markup m d) +markup m (DocBold d) = markupBold m (markup m d) +markup m (DocMonospaced d) = markupMonospaced m (markup m d) +markup m (DocUnorderedList ds) = markupUnorderedList m (map (markup m) ds) +markup m (DocOrderedList ds) = markupOrderedList m (map (\(index, a) -> (index, markup m a)) ds) +markup m (DocDefList ds) = markupDefList m (map (markupPair m) ds) +markup m (DocCodeBlock d) = markupCodeBlock m (markup m d) markup m (DocHyperlink (Hyperlink u l)) = markupHyperlink m (Hyperlink u (fmap (markup m) l)) -markup m (DocAName ref) = markupAName m ref -markup m (DocPic img) = markupPic m img -markup m (DocMathInline mathjax) = markupMathInline m mathjax -markup m (DocMathDisplay mathjax) = markupMathDisplay m mathjax -markup m (DocProperty p) = markupProperty m p -markup m (DocExamples e) = markupExample m e -markup m (DocHeader (Header l t)) = markupHeader m (Header l (markup m t)) -markup m (DocTable (Table h b)) = markupTable m (Table (map (fmap (markup m)) h) (map (fmap (markup m)) b)) +markup m (DocAName ref) = markupAName m ref +markup m (DocPic img) = markupPic m img +markup m (DocMathInline mathjax) = markupMathInline m mathjax +markup m (DocMathDisplay mathjax) = markupMathDisplay m mathjax +markup m (DocProperty p) = markupProperty m p +markup m (DocExamples e) = markupExample m e +markup m (DocHeader (Header l t)) = markupHeader m (Header l (markup m t)) +markup m (DocTable (Table h b)) = markupTable m (Table (map (fmap (markup m)) h) (map (fmap (markup m)) b)) markupPair :: DocMarkupH mod id a -> (DocH mod id, DocH mod id) -> (a, a) -markupPair m (a,b) = (markup m a, markup m b) +markupPair m (a, b) = (markup m a, markup m b) -- | The identity markup idMarkup :: DocMarkupH mod id (DocH mod id) -idMarkup = Markup { - markupEmpty = DocEmpty, - markupString = DocString, - markupParagraph = DocParagraph, - markupAppend = DocAppend, - markupIdentifier = DocIdentifier, - markupIdentifierUnchecked = DocIdentifierUnchecked, - markupModule = DocModule, - markupWarning = DocWarning, - markupEmphasis = DocEmphasis, - markupBold = DocBold, - markupMonospaced = DocMonospaced, - markupUnorderedList = DocUnorderedList, - markupOrderedList = DocOrderedList, - markupDefList = DocDefList, - markupCodeBlock = DocCodeBlock, - markupHyperlink = DocHyperlink, - markupAName = DocAName, - markupPic = DocPic, - markupMathInline = DocMathInline, - markupMathDisplay = DocMathDisplay, - markupProperty = DocProperty, - markupExample = DocExamples, - markupHeader = DocHeader, - markupTable = DocTable - } +idMarkup = + Markup + { markupEmpty = DocEmpty + , markupString = DocString + , markupParagraph = DocParagraph + , markupAppend = DocAppend + , markupIdentifier = DocIdentifier + , markupIdentifierUnchecked = DocIdentifierUnchecked + , markupModule = DocModule + , markupWarning = DocWarning + , markupEmphasis = DocEmphasis + , markupBold = DocBold + , markupMonospaced = DocMonospaced + , markupUnorderedList = DocUnorderedList + , markupOrderedList = DocOrderedList + , markupDefList = DocDefList + , markupCodeBlock = DocCodeBlock + , markupHyperlink = DocHyperlink + , markupAName = DocAName + , markupPic = DocPic + , markupMathInline = DocMathInline + , markupMathDisplay = DocMathDisplay + , markupProperty = DocProperty + , markupExample = DocExamples + , markupHeader = DocHeader + , markupTable = DocTable + } -- | Map a 'DocH' into a best estimate of an alternate string. The idea is to -- strip away any formatting while preserving as much of the actual text as -- possible. plainMarkup :: (mod -> String) -> (id -> String) -> DocMarkupH mod id String -plainMarkup plainMod plainIdent = Markup { - markupEmpty = "", - markupString = id, - markupParagraph = id, - markupAppend = (++), - markupIdentifier = plainIdent, - markupIdentifierUnchecked = plainMod, - markupModule = \(ModLink m lbl) -> fromMaybe m lbl, - markupWarning = id, - markupEmphasis = id, - markupBold = id, - markupMonospaced = id, - markupUnorderedList = const "", - markupOrderedList = const "", - markupDefList = const "", - markupCodeBlock = id, - markupHyperlink = \(Hyperlink url lbl) -> fromMaybe url lbl, - markupAName = id, - markupPic = \(Picture uri title) -> fromMaybe uri title, - markupMathInline = id, - markupMathDisplay = id, - markupProperty = id, - markupExample = const "", - markupHeader = \(Header _ title) -> title, - markupTable = const "" - } +plainMarkup plainMod plainIdent = + Markup + { markupEmpty = "" + , markupString = id + , markupParagraph = id + , markupAppend = (++) + , markupIdentifier = plainIdent + , markupIdentifierUnchecked = plainMod + , markupModule = \(ModLink m lbl) -> fromMaybe m lbl + , markupWarning = id + , markupEmphasis = id + , markupBold = id + , markupMonospaced = id + , markupUnorderedList = const "" + , markupOrderedList = const "" + , markupDefList = const "" + , markupCodeBlock = id + , markupHyperlink = \(Hyperlink url lbl) -> fromMaybe url lbl + , markupAName = id + , markupPic = \(Picture uri title) -> fromMaybe uri title + , markupMathInline = id + , markupMathDisplay = id + , markupProperty = id + , markupExample = const "" + , markupHeader = \(Header _ title) -> title + , markupTable = const "" + } diff --git a/haddock-library/src/Documentation/Haddock/Parser.hs b/haddock-library/src/Documentation/Haddock/Parser.hs index 2185d5bcc5..0463e26ef0 100644 --- a/haddock-library/src/Documentation/Haddock/Parser.hs +++ b/haddock-library/src/Documentation/Haddock/Parser.hs @@ -1,5 +1,6 @@ {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ViewPatterns #-} +{-# LANGUAGE ViewPatterns #-} + -- | -- Module : Documentation.Haddock.Parser -- Copyright : (c) Mateusz Kowalczyk 2013-2014, @@ -15,37 +16,36 @@ -- to be -- -- @'toRegular' . '_doc' . 'parseParas'@ -module Documentation.Haddock.Parser ( - parseString, - parseParas, - overIdentifier, - toRegular, - Identifier -) where - -import Control.Applicative -import Control.Arrow (first) -import Control.Monad -import Data.Char (chr, isUpper, isAlpha, isSpace) -import Data.List (intercalate, unfoldr, elemIndex) -import Data.Maybe (fromMaybe, mapMaybe) -import Data.Monoid +module Documentation.Haddock.Parser + ( parseString + , parseParas + , overIdentifier + , toRegular + , Identifier + ) where + +import Control.Applicative +import Control.Arrow (first) +import Control.Monad +import Data.Char (chr, isAlpha, isSpace, isUpper) +import Data.List (elemIndex, intercalate, unfoldr) +import Data.Maybe (fromMaybe, mapMaybe) +import Data.Monoid import qualified Data.Set as Set -import Documentation.Haddock.Doc -import Documentation.Haddock.Markup ( markup, plainMarkup ) -import Documentation.Haddock.Parser.Monad -import Documentation.Haddock.Parser.Util -import Documentation.Haddock.Parser.Identifier -import Documentation.Haddock.Types -import Prelude hiding (takeWhile) +import Documentation.Haddock.Doc +import Documentation.Haddock.Markup (markup, plainMarkup) +import Documentation.Haddock.Parser.Identifier +import Documentation.Haddock.Parser.Monad +import Documentation.Haddock.Parser.Util +import Documentation.Haddock.Types +import Prelude hiding (takeWhile) import qualified Prelude as P +import Text.Parsec (try) import qualified Text.Parsec as Parsec -import Text.Parsec (try) +import Data.Text (Text) import qualified Data.Text as T -import Data.Text (Text) - -- $setup -- >>> :set -XOverloadedStrings @@ -59,9 +59,10 @@ toRegular = fmap (\(Identifier _ _ x _) -> x) -- conversion using user-supplied function. If the conversion fails, -- the identifier is deemed to not be valid and is treated as a -- regular string. -overIdentifier :: (Namespace -> String -> Maybe a) - -> DocH mod Identifier - -> DocH mod a +overIdentifier + :: (Namespace -> String -> Maybe a) + -> DocH mod Identifier + -> DocH mod a overIdentifier f d = g d where g (DocIdentifier (Identifier ns o x e)) = case f ns x of @@ -91,7 +92,6 @@ overIdentifier f d = g d g (DocHeader (Header l x)) = DocHeader . Header l $ g x g (DocTable (Table h b)) = DocTable (Table (map (fmap g) h) (map (fmap g) b)) - choice' :: [Parser a] -> Parser a choice' [] = empty choice' [p] = p @@ -104,15 +104,18 @@ parse p = either err id . parseOnly (p <* Parsec.eof) -- | Main entry point to the parser. Appends the newline character -- to the input string. -parseParas :: Maybe Package - -> String -- ^ String to parse - -> MetaDoc mod Identifier +parseParas + :: Maybe Package + -> String + -- ^ String to parse + -> MetaDoc mod Identifier parseParas pkg input = case parseParasState input of (state, a) -> - let defaultPackage s = s { sincePackage = sincePackage s <|> pkg } - in MetaDoc { _meta = Meta { _metaSince = defaultPackage <$> parserStateSince state } - , _doc = a - } + let defaultPackage s = s{sincePackage = sincePackage s <|> pkg} + in MetaDoc + { _meta = Meta{_metaSince = defaultPackage <$> parserStateSince state} + , _doc = a + } parseParasState :: String -> (ParserState, DocH mod Identifier) parseParasState = parse (emptyLines *> p) . T.pack . (++ "\n") . filter (/= '\r') @@ -140,22 +143,27 @@ parseParagraph :: Text -> DocH mod Identifier parseParagraph = snd . parse p where p :: Parser (DocH mod Identifier) - p = docConcat <$> many (choice' [ monospace - , anchor - , identifier - , moduleName - , picture - , mathDisplay - , mathInline - , markdownImage - , markdownLink - , hyperlink - , bold - , emphasis - , encodedChar - , string' - , skipSpecialChar - ]) + p = + docConcat + <$> many + ( choice' + [ monospace + , anchor + , identifier + , moduleName + , picture + , mathDisplay + , mathInline + , markdownImage + , markdownLink + , hyperlink + , bold + , emphasis + , encodedChar + , string' + , skipSpecialChar + ] + ) -- | Parses and processes -- @@ -182,8 +190,8 @@ string' :: Parser (DocH mod a) string' = DocString . unescape . T.unpack <$> takeWhile1_ (`notElem` specialChar) where unescape "" = "" - unescape ('\\':x:xs) = x : unescape xs - unescape (x:xs) = x : unescape xs + unescape ('\\' : x : xs) = x : unescape xs + unescape (x : xs) = x : unescape xs -- | Skips a single special character and treats it as a plain string. -- This is done to skip over any special characters belonging to other @@ -196,8 +204,9 @@ skipSpecialChar = DocString . return <$> Parsec.oneOf specialChar -- >>> parseString "/Hello world/" -- DocEmphasis (DocString "Hello world") emphasis :: Parser (DocH mod Identifier) -emphasis = DocEmphasis . parseParagraph <$> - disallowNewline ("/" *> takeWhile1_ (/= '/') <* "/") +emphasis = + DocEmphasis . parseParagraph + <$> disallowNewline ("/" *> takeWhile1_ (/= '/') <* "/") -- | Bold parser. -- @@ -227,16 +236,18 @@ takeWhile1_ = mfilter (not . T.null) . takeWhile_ -- >>> parseString "#Hello world#" -- DocAName "Hello world" anchor :: Parser (DocH mod a) -anchor = DocAName . T.unpack <$> - ("#" *> takeWhile1_ (\x -> x /= '#' && not (isSpace x)) <* "#") +anchor = + DocAName . T.unpack + <$> ("#" *> takeWhile1_ (\x -> x /= '#' && not (isSpace x)) <* "#") -- | Monospaced strings. -- -- >>> parseString "@cruel@" -- DocMonospaced (DocString "cruel") monospace :: Parser (DocH mod Identifier) -monospace = DocMonospaced . parseParagraph - <$> ("@" *> takeWhile1_ (/= '@') <* "@") +monospace = + DocMonospaced . parseParagraph + <$> ("@" *> takeWhile1_ (/= '@') <* "@") -- | Module names. -- @@ -246,20 +257,21 @@ moduleName :: Parser (DocH mod a) moduleName = DocModule . flip ModLink Nothing <$> ("\"" *> moduleNameString <* "\"") -- | A module name, optionally with an anchor --- moduleNameString :: Parser String moduleNameString = modid `maybeFollowedBy` anchor_ where modid = intercalate "." <$> conid `Parsec.sepBy1` "." - anchor_ = (++) - <$> (Parsec.string "#" <|> Parsec.string "\\#") - <*> many (Parsec.satisfy (\c -> c /= '"' && not (isSpace c))) + anchor_ = + (++) + <$> (Parsec.string "#" <|> Parsec.string "\\#") + <*> many (Parsec.satisfy (\c -> c /= '"' && not (isSpace c))) maybeFollowedBy pre suf = (\x -> maybe x (x ++)) <$> pre <*> optional suf conid :: Parser String - conid = (:) - <$> Parsec.satisfy (\c -> isAlpha c && isUpper c) - <*> many conChar + conid = + (:) + <$> Parsec.satisfy (\c -> isAlpha c && isUpper c) + <*> many conChar conChar = Parsec.alphaNum <|> Parsec.char '_' @@ -268,12 +280,17 @@ moduleNameString = modid `maybeFollowedBy` anchor_ markdownLink :: Parser (DocH mod Identifier) markdownLink = do lbl <- markdownLinkText - choice' [ markdownModuleName lbl, markdownURL lbl ] + choice' [markdownModuleName lbl, markdownURL lbl] where markdownModuleName lbl = do - mn <- "(" *> skipHorizontalSpace *> - "\"" *> moduleNameString <* "\"" - <* skipHorizontalSpace <* ")" + mn <- + "(" + *> skipHorizontalSpace + *> "\"" + *> moduleNameString + <* "\"" + <* skipHorizontalSpace + <* ")" pure $ DocModule (ModLink mn (Just lbl)) markdownURL lbl = do @@ -288,24 +305,27 @@ markdownLink = do -- >>> parseString "<>" -- DocPic (Picture {pictureUri = "hello.png", pictureTitle = Just "world"}) picture :: Parser (DocH mod a) -picture = DocPic . makeLabeled Picture - <$> disallowNewline ("<<" *> takeUntil ">>") +picture = + DocPic . makeLabeled Picture + <$> disallowNewline ("<<" *> takeUntil ">>") -- | Inline math parser, surrounded by \\( and \\). -- -- >>> parseString "\\(\\int_{-\\infty}^{\\infty} e^{-x^2/2} = \\sqrt{2\\pi}\\)" -- DocMathInline "\\int_{-\\infty}^{\\infty} e^{-x^2/2} = \\sqrt{2\\pi}" mathInline :: Parser (DocH mod a) -mathInline = DocMathInline . T.unpack - <$> disallowNewline ("\\(" *> takeUntil "\\)") +mathInline = + DocMathInline . T.unpack + <$> disallowNewline ("\\(" *> takeUntil "\\)") -- | Display math parser, surrounded by \\[ and \\]. -- -- >>> parseString "\\[\\int_{-\\infty}^{\\infty} e^{-x^2/2} = \\sqrt{2\\pi}\\]" -- DocMathDisplay "\\int_{-\\infty}^{\\infty} e^{-x^2/2} = \\sqrt{2\\pi}" mathDisplay :: Parser (DocH mod a) -mathDisplay = DocMathDisplay . T.unpack - <$> ("\\[" *> takeUntil "\\]") +mathDisplay = + DocMathDisplay . T.unpack + <$> ("\\[" *> takeUntil "\\]") -- | Markdown image parser. As per the commonmark reference recommendation, the -- description text for an image converted to its a plain string representation. @@ -323,21 +343,25 @@ markdownImage = do -- | Paragraph parser, called by 'parseParas'. paragraph :: Parser (DocH mod Identifier) -paragraph = choice' [ examples - , table - , do indent <- takeIndent - choice' [ since - , unorderedList indent - , orderedList indent - , birdtracks - , codeblock - , property - , header - , textParagraphThatStartsWithMarkdownLink - , definitionList indent - , docParagraph <$> textParagraph - ] - ] +paragraph = + choice' + [ examples + , table + , do + indent <- takeIndent + choice' + [ since + , unorderedList indent + , orderedList indent + , birdtracks + , codeblock + , property + , header + , textParagraphThatStartsWithMarkdownLink + , definitionList indent + , docParagraph <$> textParagraph + ] + ] -- | Provides support for grid tables. -- @@ -354,134 +378,150 @@ paragraph = choice' [ examples -- -- Algorithms loosely follows ideas in -- http://docutils.sourceforge.net/docutils/parsers/rst/tableparser.py --- table :: Parser (DocH mod Identifier) table = do - -- first we parse the first row, which determines the width of the table - firstRow <- parseFirstRow - let len = T.length firstRow + -- first we parse the first row, which determines the width of the table + firstRow <- parseFirstRow + let len = T.length firstRow - -- then we parse all consecutive rows starting and ending with + or |, - -- of the width `len`. - restRows <- many (try (parseRestRows len)) + -- then we parse all consecutive rows starting and ending with + or |, + -- of the width `len`. + restRows <- many (try (parseRestRows len)) - -- Now we gathered the table block, the next step is to split the block - -- into cells. - DocTable <$> tableStepTwo len (firstRow : restRows) + -- Now we gathered the table block, the next step is to split the block + -- into cells. + DocTable <$> tableStepTwo len (firstRow : restRows) where parseFirstRow :: Parser Text parseFirstRow = do - skipHorizontalSpace - cs <- takeWhile (\c -> c == '-' || c == '+') + skipHorizontalSpace + cs <- takeWhile (\c -> c == '-' || c == '+') - -- upper-left and upper-right corners are `+` - guard (T.length cs >= 2 && - T.head cs == '+' && - T.last cs == '+') + -- upper-left and upper-right corners are `+` + guard + ( T.length cs >= 2 + && T.head cs == '+' + && T.last cs == '+' + ) - -- trailing space - skipHorizontalSpace - _ <- Parsec.newline + -- trailing space + skipHorizontalSpace + _ <- Parsec.newline - return cs + return cs parseRestRows :: Int -> Parser Text parseRestRows l = do - skipHorizontalSpace - bs <- scan predicate l + skipHorizontalSpace + bs <- scan predicate l - -- Left and right edges are `|` or `+` - guard (T.length bs >= 2 && - (T.head bs == '|' || T.head bs == '+') && - (T.last bs == '|' || T.last bs == '+')) + -- Left and right edges are `|` or `+` + guard + ( T.length bs >= 2 + && (T.head bs == '|' || T.head bs == '+') + && (T.last bs == '|' || T.last bs == '+') + ) - -- trailing space - skipHorizontalSpace - _ <- Parsec.newline + -- trailing space + skipHorizontalSpace + _ <- Parsec.newline - return bs + return bs where predicate n c - | n <= 0 = Nothing - | c == '\n' = Nothing - | otherwise = Just (n - 1) + | n <= 0 = Nothing + | c == '\n' = Nothing + | otherwise = Just (n - 1) -- Second step searchs for row of '+' and '=' characters, records it's index -- and changes to '=' to '-'. tableStepTwo - :: Int -- ^ width - -> [Text] -- ^ rows - -> Parser (Table (DocH mod Identifier)) -tableStepTwo width = go 0 [] where + :: Int + -- ^ width + -> [Text] + -- ^ rows + -> Parser (Table (DocH mod Identifier)) +tableStepTwo width = go 0 [] + where go _ left [] = tableStepThree width (reverse left) Nothing go n left (r : rs) - | T.all (`elem` ['+', '=']) r = - tableStepThree width (reverse left ++ r' : rs) (Just n) - | otherwise = - go (n + 1) (r : left) rs + | T.all (`elem` ['+', '=']) r = + tableStepThree width (reverse left ++ r' : rs) (Just n) + | otherwise = + go (n + 1) (r : left) rs where r' = T.map (\c -> if c == '=' then '-' else c) r -- Third step recognises cells in the table area, returning a list of TC, cells. tableStepThree - :: Int -- ^ width - -> [Text] -- ^ rows - -> Maybe Int -- ^ index of header separator - -> Parser (Table (DocH mod Identifier)) + :: Int + -- ^ width + -> [Text] + -- ^ rows + -> Maybe Int + -- ^ index of header separator + -> Parser (Table (DocH mod Identifier)) tableStepThree width rs hdrIndex = do - cells <- loop (Set.singleton (0, 0)) - tableStepFour rs hdrIndex cells + cells <- loop (Set.singleton (0, 0)) + tableStepFour rs hdrIndex cells where height = length rs loop :: Set.Set (Int, Int) -> Parser [TC] loop queue = case Set.minView queue of - Nothing -> return [] - Just ((y, x), queue') - | y + 1 >= height || x + 1 >= width -> loop queue' - | otherwise -> case scanRight x y of - Nothing -> loop queue' - Just (x2, y2) -> do - let tc = TC y x y2 x2 - fmap (tc :) $ loop $ queue' `Set.union` Set.fromList - [(y, x2), (y2, x), (y2, x2)] + Nothing -> return [] + Just ((y, x), queue') + | y + 1 >= height || x + 1 >= width -> loop queue' + | otherwise -> case scanRight x y of + Nothing -> loop queue' + Just (x2, y2) -> do + let tc = TC y x y2 x2 + fmap (tc :) $ + loop $ + queue' + `Set.union` Set.fromList + [(y, x2), (y2, x), (y2, x2)] -- scan right looking for +, then try scan down -- -- do we need to record + saw on the way left and down? scanRight :: Int -> Int -> Maybe (Int, Int) - scanRight x y = go (x + 1) where + scanRight x y = go (x + 1) + where bs = rs !! y - go x' | x' >= width = fail "overflow right " - | T.index bs x' == '+' = scanDown x y x' <|> go (x' + 1) - | T.index bs x' == '-' = go (x' + 1) - | otherwise = fail $ "not a border (right) " ++ show (x,y,x') + go x' + | x' >= width = fail "overflow right " + | T.index bs x' == '+' = scanDown x y x' <|> go (x' + 1) + | T.index bs x' == '-' = go (x' + 1) + | otherwise = fail $ "not a border (right) " ++ show (x, y, x') -- scan down looking for + scanDown :: Int -> Int -> Int -> Maybe (Int, Int) - scanDown x y x2 = go (y + 1) where - go y' | y' >= height = fail "overflow down" - | T.index (rs !! y') x2 == '+' = scanLeft x y x2 y' <|> go (y' + 1) - | T.index (rs !! y') x2 == '|' = go (y' + 1) - | otherwise = fail $ "not a border (down) " ++ show (x,y,x2,y') + scanDown x y x2 = go (y + 1) + where + go y' + | y' >= height = fail "overflow down" + | T.index (rs !! y') x2 == '+' = scanLeft x y x2 y' <|> go (y' + 1) + | T.index (rs !! y') x2 == '|' = go (y' + 1) + | otherwise = fail $ "not a border (down) " ++ show (x, y, x2, y') -- check that at y2 x..x2 characters are '+' or '-' scanLeft :: Int -> Int -> Int -> Int -> Maybe (Int, Int) scanLeft x y x2 y2 - | all (\x' -> T.index bs x' `elem` ['+', '-']) [x..x2] = scanUp x y x2 y2 - | otherwise = fail $ "not a border (left) " ++ show (x,y,x2,y2) + | all (\x' -> T.index bs x' `elem` ['+', '-']) [x .. x2] = scanUp x y x2 y2 + | otherwise = fail $ "not a border (left) " ++ show (x, y, x2, y2) where bs = rs !! y2 -- check that at y2 x..x2 characters are '+' or '-' scanUp :: Int -> Int -> Int -> Int -> Maybe (Int, Int) scanUp x y x2 y2 - | all (\y' -> T.index (rs !! y') x `elem` ['+', '|']) [y..y2] = return (x2, y2) - | otherwise = fail $ "not a border (up) " ++ show (x,y,x2,y2) + | all (\y' -> T.index (rs !! y') x `elem` ['+', '|']) [y .. y2] = return (x2, y2) + | otherwise = fail $ "not a border (up) " ++ show (x, y, x2, y2) -- | table cell: top left bottom right data TC = TC !Int !Int !Int !Int - deriving Show + deriving (Show) tcXS :: TC -> [Int] tcXS (TC _ x _ x2) = [x, x2] @@ -491,11 +531,11 @@ tcYS (TC y _ y2 _) = [y, y2] -- | Fourth step. Given the locations of cells, forms 'Table' structure. tableStepFour :: [Text] -> Maybe Int -> [TC] -> Parser (Table (DocH mod Identifier)) -tableStepFour rs hdrIndex cells = case hdrIndex of +tableStepFour rs hdrIndex cells = case hdrIndex of + Nothing -> return $ Table [] rowsDoc + Just i -> case elemIndex i yTabStops of Nothing -> return $ Table [] rowsDoc - Just i -> case elemIndex i yTabStops of - Nothing -> return $ Table [] rowsDoc - Just i' -> return $ uncurry Table $ splitAt i' rowsDoc + Just i' -> return $ uncurry Table $ splitAt i' rowsDoc where xTabStops = sortNub $ concatMap tcXS cells yTabStops = sortNub $ concatMap tcYS cells @@ -504,8 +544,8 @@ tableStepFour rs hdrIndex cells = case hdrIndex of sortNub = Set.toList . Set.fromList init' :: [a] -> [a] - init' [] = [] - init' [_] = [] + init' [] = [] + init' [_] = [] init' (x : xs) = x : init' xs rowsDoc = (fmap . fmap) parseParagraph rows @@ -514,15 +554,17 @@ tableStepFour rs hdrIndex cells = case hdrIndex of where makeRow y = TableRow $ mapMaybe (makeCell y) cells makeCell y (TC y' x y2 x2) - | y /= y' = Nothing - | otherwise = Just $ TableCell xts yts (extract (x + 1) (y + 1) (x2 - 1) (y2 - 1)) + | y /= y' = Nothing + | otherwise = Just $ TableCell xts yts (extract (x + 1) (y + 1) (x2 - 1) (y2 - 1)) where xts = length $ P.takeWhile (< x2) $ dropWhile (< x) xTabStops yts = length $ P.takeWhile (< y2) $ dropWhile (< y) yTabStops -- extract cell contents given boundaries extract :: Int -> Int -> Int -> Int -> Text - extract x y x2 y2 = T.intercalate "\n" + extract x y x2 y2 = + T.intercalate + "\n" [ T.stripEnd $ T.stripStart $ T.take (x2 - x + 1) $ T.drop x $ rs !! y' | y' <- [y .. y2] ] @@ -563,8 +605,11 @@ textParagraphThatStartsWithMarkdownLink :: Parser (DocH mod Identifier) textParagraphThatStartsWithMarkdownLink = docParagraph <$> (docAppend <$> markdownLink <*> optionalTextParagraph) where optionalTextParagraph :: Parser (DocH mod Identifier) - optionalTextParagraph = choice' [ docAppend <$> whitespace <*> textParagraph - , pure DocEmpty ] + optionalTextParagraph = + choice' + [ docAppend <$> whitespace <*> textParagraph + , pure DocEmpty + ] whitespace :: Parser (DocH mod a) whitespace = DocString <$> (f <$> takeHorizontalSpace <*> optional "\n") @@ -591,9 +636,11 @@ orderedList indent = DocOrderedList <$> p paren = "(" *> decimal <* ")" -- | Like 'innerList' but takes the parsed index of the list item -innerList' :: Text -> Parser [(Int, DocH mod Identifier)] - -> Int - -> Parser [(Int, DocH mod Identifier)] +innerList' + :: Text + -> Parser [(Int, DocH mod Identifier)] + -> Int + -> Parser [(Int, DocH mod Identifier)] innerList' indent item index = do c <- takeLine (cs, items) <- more indent item @@ -607,8 +654,10 @@ innerList' indent item index = do -- same paragraph. Usually used as -- -- > someListFunction = listBeginning *> innerList someListFunction -innerList :: Text -> Parser [DocH mod Identifier] - -> Parser [DocH mod Identifier] +innerList + :: Text + -> Parser [DocH mod Identifier] + -> Parser [DocH mod Identifier] innerList indent item = do c <- takeLine (cs, items) <- more indent item @@ -637,39 +686,50 @@ dropNLs = T.dropWhileEnd (== '\n') -- | Main worker for 'innerList' and 'definitionList'. -- We need the 'Either' here to be able to tell in the respective functions -- whether we're dealing with the next list or a nested paragraph. -more :: Monoid a => Text -> Parser a - -> Parser ([Text], Either (DocH mod Identifier) a) -more indent item = choice' [ innerParagraphs indent - , moreListItems indent item - , moreContent indent item - , pure ([], Right mempty) - ] +more + :: Monoid a + => Text + -> Parser a + -> Parser ([Text], Either (DocH mod Identifier) a) +more indent item = + choice' + [ innerParagraphs indent + , moreListItems indent item + , moreContent indent item + , pure ([], Right mempty) + ] -- | Used by 'innerList' and 'definitionList' to parse any nested paragraphs. -innerParagraphs :: Text - -> Parser ([Text], Either (DocH mod Identifier) a) +innerParagraphs + :: Text + -> Parser ([Text], Either (DocH mod Identifier) a) innerParagraphs indent = (,) [] . Left <$> ("\n" *> indentedParagraphs indent) -- | Attempts to fetch the next list if possibly. Used by 'innerList' and -- 'definitionList' to recursively grab lists that aren't separated by a whole -- paragraph. -moreListItems :: Text -> Parser a - -> Parser ([Text], Either (DocH mod Identifier) a) +moreListItems + :: Text + -> Parser a + -> Parser ([Text], Either (DocH mod Identifier) a) moreListItems indent item = (,) [] . Right <$> indentedItem where indentedItem = string indent *> Parsec.spaces *> item -- | Helper for 'innerList' and 'definitionList' which simply takes -- a line of text and attempts to parse more list content with 'more'. -moreContent :: Monoid a => Text -> Parser a - -> Parser ([Text], Either (DocH mod Identifier) a) +moreContent + :: Monoid a + => Text + -> Parser a + -> Parser ([Text], Either (DocH mod Identifier) a) moreContent indent item = first . (:) <$> nonEmptyLine <*> more indent item -- | Parses an indented paragraph. -- The indentation is 4 spaces. indentedParagraphs :: Text -> Parser (DocH mod Identifier) indentedParagraphs indent = - (T.unpack . T.concat <$> dropFrontOfPara indent') >>= parseParagraphs + (T.unpack . T.concat <$> dropFrontOfPara indent') >>= parseParagraphs where indent' = string $ indent <> " " @@ -678,10 +738,11 @@ dropFrontOfPara :: Parser Text -> Parser [Text] dropFrontOfPara sp = do currentParagraph <- some (try (sp *> takeNonEmptyLine)) followingParagraphs <- - choice' [ skipHorizontalSpace *> nextPar -- we have more paragraphs to take - , skipHorizontalSpace *> nlList -- end of the ride, remember the newline - , Parsec.eof *> return [] -- nothing more to take at all - ] + choice' + [ skipHorizontalSpace *> nextPar -- we have more paragraphs to take + , skipHorizontalSpace *> nlList -- end of the ride, remember the newline + , Parsec.eof *> return [] -- nothing more to take at all + ] return (currentParagraph ++ followingParagraphs) where nextPar = (++) <$> nlList <*> dropFrontOfPara sp @@ -697,9 +758,9 @@ nonSpace xs -- Doesn't discard the trailing newline. takeNonEmptyLine :: Parser Text takeNonEmptyLine = do - l <- takeWhile1 (/= '\n') >>= nonSpace - _ <- "\n" - pure (l <> "\n") + l <- takeWhile1 (/= '\n') >>= nonSpace + _ <- "\n" + pure (l <> "\n") -- | Takes indentation of first non-empty line. -- @@ -708,16 +769,16 @@ takeNonEmptyLine = do takeIndent :: Parser Text takeIndent = do indent <- takeHorizontalSpace - choice' [ "\n" *> takeIndent - , return indent - ] + choice' + [ "\n" *> takeIndent + , return indent + ] -- | Blocks of text of the form: -- -- >> foo -- >> bar -- >> baz --- birdtracks :: Parser (DocH mod a) birdtracks = DocCodeBlock . DocString . T.unpack . T.intercalate "\n" . stripSpace <$> some line where @@ -727,9 +788,9 @@ stripSpace :: [Text] -> [Text] stripSpace = fromMaybe <*> mapM strip' where strip' t = case T.uncons t of - Nothing -> Just "" - Just (' ',t') -> Just t' - _ -> Nothing + Nothing -> Just "" + Just (' ', t') -> Just t' + _ -> Nothing -- | Parses examples. Examples are a paragraph level entity (separated by an empty line). -- Consecutive examples are accepted. @@ -744,7 +805,7 @@ examples = DocExamples <$> (many (try (skipHorizontalSpace *> "\n")) *> go) return (makeExample prefix expr rs : es) where resultAndMoreExamples :: Parser ([Text], [Example]) - resultAndMoreExamples = choice' [ moreExamples, result, pure ([], []) ] + resultAndMoreExamples = choice' [moreExamples, result, pure ([], [])] where moreExamples :: Parser ([Text], [Example]) moreExamples = (,) [] <$> go @@ -785,30 +846,33 @@ property = DocProperty . T.unpack . T.strip <$> ("prop>" *> takeWhile1 (/= '\n') codeblock :: Parser (DocH mod Identifier) codeblock = DocCodeBlock . parseParagraph . dropSpaces - <$> ("@" *> skipHorizontalSpace *> "\n" *> block' <* "@") + <$> ("@" *> skipHorizontalSpace *> "\n" *> block' <* "@") where dropSpaces xs = case splitByNl xs of [] -> xs ys -> case T.uncons (last ys) of - Just (' ',_) -> case mapM dropSpace ys of - Nothing -> xs - Just zs -> T.intercalate "\n" zs + Just (' ', _) -> case mapM dropSpace ys of + Nothing -> xs + Just zs -> T.intercalate "\n" zs _ -> xs -- This is necessary because ‘lines’ swallows up a trailing newline -- and we lose information about whether the last line belongs to @ or to -- text which we need to decide whether we actually want to be dropping -- anything at all. - splitByNl = unfoldr (\x -> case T.uncons x of - Just ('\n',x') -> Just (T.span (/= '\n') x') - _ -> Nothing) - . ("\n" <>) + splitByNl = + unfoldr + ( \x -> case T.uncons x of + Just ('\n', x') -> Just (T.span (/= '\n') x') + _ -> Nothing + ) + . ("\n" <>) dropSpace t = case T.uncons t of - Nothing -> Just "" - Just (' ',t') -> Just t' - _ -> Nothing + Nothing -> Just "" + Just (' ', t') -> Just t' + _ -> Nothing block' = scan p False where @@ -818,11 +882,11 @@ codeblock = | otherwise = Just $ c == '\n' hyperlink :: Parser (DocH mod Identifier) -hyperlink = choice' [ angleBracketLink, autoUrl ] +hyperlink = choice' [angleBracketLink, autoUrl] angleBracketLink :: Parser (DocH mod a) angleBracketLink = - DocHyperlink . makeLabeled (\s -> Hyperlink s . fmap DocString) + DocHyperlink . makeLabeled (\s -> Hyperlink s . fmap DocString) <$> disallowNewline ("<" *> takeUntil ">") -- | The text for a markdown link, enclosed in square brackets. @@ -850,17 +914,16 @@ markdownLinkTarget = whitespace *> url autoUrl :: Parser (DocH mod a) autoUrl = mkLink <$> url where - url = mappend <$> choice' [ "http://", "https://", "ftp://"] <*> takeWhile1 (not . isSpace) + url = mappend <$> choice' ["http://", "https://", "ftp://"] <*> takeWhile1 (not . isSpace) mkLink :: Text -> DocH mod a mkLink s = case T.unsnoc s of - Just (xs,x) | x `elem` (",.!?" :: String) -> DocHyperlink (mkHyperlink xs) `docAppend` DocString [x] + Just (xs, x) | x `elem` (",.!?" :: String) -> DocHyperlink (mkHyperlink xs) `docAppend` DocString [x] _ -> DocHyperlink (mkHyperlink s) mkHyperlink :: Text -> Hyperlink (DocH mod a) mkHyperlink lnk = Hyperlink (T.unpack lnk) Nothing - -- | Parses identifiers with help of 'parseValid'. identifier :: Parser (DocH mod Identifier) identifier = DocIdentifier <$> parseValid diff --git a/haddock-library/src/Documentation/Haddock/Parser/Identifier.hs b/haddock-library/src/Documentation/Haddock/Parser/Identifier.hs index 4c56be9b75..6ed3d04019 100644 --- a/haddock-library/src/Documentation/Haddock/Parser/Identifier.hs +++ b/haddock-library/src/Documentation/Haddock/Parser/Identifier.hs @@ -1,4 +1,5 @@ {-# LANGUAGE BangPatterns #-} + -- | -- Module : Documentation.Haddock.Parser.Identifier -- Copyright : (c) Alec Theriault 2019, @@ -9,26 +10,28 @@ -- Portability : portable -- -- Functionality for parsing identifiers and operators +module Documentation.Haddock.Parser.Identifier + ( Identifier (..) + , parseValid + ) where -module Documentation.Haddock.Parser.Identifier ( - Identifier(..), - parseValid, -) where - -import Documentation.Haddock.Types ( Namespace(..) ) import Documentation.Haddock.Parser.Monad +import Documentation.Haddock.Types (Namespace (..)) +import Text.Parsec + ( State (..) + , getParserState + , setParserState + ) import qualified Text.Parsec as Parsec -import Text.Parsec.Pos ( updatePosChar ) -import Text.Parsec ( State(..) - , getParserState, setParserState ) +import Text.Parsec.Pos (updatePosChar) import Data.Text (Text) import qualified Data.Text as T -import Data.Char (isAlpha, isAlphaNum) +import CompatPrelude import Control.Monad (guard) +import Data.Char (isAlpha, isAlphaNum) import Data.Maybe -import CompatPrelude -- | Identifier string surrounded with namespace, opening, and closing quotes/backticks. data Identifier = Identifier !Namespace !Char String !Char @@ -36,7 +39,7 @@ data Identifier = Identifier !Namespace !Char String !Char parseValid :: Parser Identifier parseValid = do - s@State{ stateInput = inp, statePos = pos } <- getParserState + s@State{stateInput = inp, statePos = pos} <- getParserState case takeIdentifier inp of Nothing -> Parsec.parserFail "parseValid: Failed to match a valid identifier" @@ -44,9 +47,8 @@ parseValid = do let posOp = updatePosChar pos op posIdent = T.foldl updatePosChar posOp ident posCl = updatePosChar posIdent cl - s' = s{ stateInput = inp', statePos = posCl } - in setParserState s' $> Identifier ns op (T.unpack ident) cl - + s' = s{stateInput = inp', statePos = posCl} + in setParserState s' $> Identifier ns op (T.unpack ident) cl -- | Try to parse a delimited identifier off the front of the given input. -- @@ -64,96 +66,105 @@ parseValid = do -- This function should make /O(1)/ allocations takeIdentifier :: Text -> Maybe (Namespace, Char, Text, Char, Text) takeIdentifier input = listToMaybe $ do + -- Optional namespace + let (ns, input') = case T.uncons input of + Just ('v', i) -> (Value, i) + Just ('t', i) -> (Type, i) + _ -> (None, input) - -- Optional namespace - let (ns, input') = case T.uncons input of - Just ('v', i) -> (Value, i) - Just ('t', i) -> (Type, i) - _ -> (None, input) - - -- Opening tick - (op, input'') <- maybeToList (T.uncons input') - guard (op == '\'' || op == '`') + -- Opening tick + (op, input'') <- maybeToList (T.uncons input') + guard (op == '\'' || op == '`') - -- Identifier/operator - (ident, input''') <- wrapped input'' + -- Identifier/operator + (ident, input''') <- wrapped input'' - -- Closing tick - (cl, input'''') <- maybeToList (T.uncons input''') - guard (cl == '\'' || cl == '`') - - return (ns, op, ident, cl, input'''') + -- Closing tick + (cl, input'''') <- maybeToList (T.uncons input''') + guard (cl == '\'' || cl == '`') + return (ns, op, ident, cl, input'''') where - - -- | Parse out a wrapped, possibly qualified, operator or identifier + -- \| Parse out a wrapped, possibly qualified, operator or identifier wrapped t = do - (c, t' ) <- maybeToList (T.uncons t) + (c, t') <- maybeToList (T.uncons t) -- Tuples case c of - '(' | Just (c', _) <- T.uncons t' - , c' == ',' || c' == ')' - -> do let (commas, t'') = T.span (== ',') t' - (')', t''') <- maybeToList (T.uncons t'') - return (T.take (T.length commas + 2) t, t''') + '(' + | Just (c', _) <- T.uncons t' + , c' == ',' || c' == ')' -> + do + let (commas, t'') = T.span (== ',') t' + (')', t''') <- maybeToList (T.uncons t'') + return (T.take (T.length commas + 2) t, t''') -- Parenthesized - '(' -> do (n, t'' ) <- general False 0 [] t' - (')', t''') <- maybeToList (T.uncons t'') - return (T.take (n + 2) t, t''') + '(' -> do + (n, t'') <- general False 0 [] t' + (')', t''') <- maybeToList (T.uncons t'') + return (T.take (n + 2) t, t''') -- Backticked - '`' -> do (n, t'' ) <- general False 0 [] t' - ('`', t''') <- maybeToList (T.uncons t'') - return (T.take (n + 2) t, t''') + '`' -> do + (n, t'') <- general False 0 [] t' + ('`', t''') <- maybeToList (T.uncons t'') + return (T.take (n + 2) t, t''') -- Unadorned - _ -> do (n, t'' ) <- general False 0 [] t - return (T.take n t, t'') - - -- | Parse out a possibly qualified operator or identifier - general :: Bool -- ^ refuse inputs starting with operators - -> Int -- ^ total characters \"consumed\" so far - -> [(Int, Text)] -- ^ accumulated results - -> Text -- ^ current input - -> [(Int, Text)] -- ^ total characters parsed & what remains + _ -> do + (n, t'') <- general False 0 [] t + return (T.take n t, t'') + + -- \| Parse out a possibly qualified operator or identifier + general + :: Bool + -- \^ refuse inputs starting with operators + -> Int + -- \^ total characters \"consumed\" so far + -> [(Int, Text)] + -- \^ accumulated results + -> Text + -- \^ current input + -> [(Int, Text)] + -- \^ total characters parsed & what remains general !identOnly !i acc t -- Starts with an identifier (either just an identifier, or a module qual) - | Just (n, rest) <- identLike t - = if T.null rest - then acc - else case T.head rest of - '`' -> (n + i, rest) : acc - ')' -> (n + i, rest) : acc - '.' -> general False (n + i + 1) acc (T.tail rest) - '\'' -> let (m, rest') = quotes rest - in general True (n + m + 1 + i) ((n + m + i, rest') : acc) (T.tail rest') - _ -> acc - + | Just (n, rest) <- identLike t = + if T.null rest + then acc + else case T.head rest of + '`' -> (n + i, rest) : acc + ')' -> (n + i, rest) : acc + '.' -> general False (n + i + 1) acc (T.tail rest) + '\'' -> + let (m, rest') = quotes rest + in general True (n + m + 1 + i) ((n + m + i, rest') : acc) (T.tail rest') + _ -> acc -- An operator | Just (n, rest) <- optr t - , not identOnly - = (n + i, rest) : acc - + , not identOnly = + (n + i, rest) : acc -- Anything else - | otherwise - = acc + | otherwise = + acc - -- | Parse an identifier off the front of the input + -- \| Parse an identifier off the front of the input identLike t | T.null t = Nothing - | isAlpha (T.head t) || '_' == T.head t - = let !(idt, rest) = T.span (\c -> isAlphaNum c || c == '_') t - !(octos, rest') = T.span (== '#') rest - in Just (T.length idt + T.length octos, rest') + | isAlpha (T.head t) || '_' == T.head t = + let !(idt, rest) = T.span (\c -> isAlphaNum c || c == '_') t + !(octos, rest') = T.span (== '#') rest + in Just (T.length idt + T.length octos, rest') | otherwise = Nothing - -- | Parse all but the last quote off the front of the input + -- \| Parse all but the last quote off the front of the input -- PRECONDITION: T.head t `elem` ['\'', '`'] quotes :: Text -> (Int, Text) - quotes t = let !n = T.length (T.takeWhile (`elem` ['\'', '`']) t) - 1 - in (n, T.drop n t) - - -- | Parse an operator off the front of the input - optr t = let !(op, rest) = T.span isSymbolChar t - in if T.null op then Nothing else Just (T.length op, rest) + quotes t = + let !n = T.length (T.takeWhile (`elem` ['\'', '`']) t) - 1 + in (n, T.drop n t) + + -- \| Parse an operator off the front of the input + optr t = + let !(op, rest) = T.span isSymbolChar t + in if T.null op then Nothing else Just (T.length op, rest) diff --git a/haddock-library/src/Documentation/Haddock/Parser/Monad.hs b/haddock-library/src/Documentation/Haddock/Parser/Monad.hs index f753c0d7f1..344360cf36 100644 --- a/haddock-library/src/Documentation/Haddock/Parser/Monad.hs +++ b/haddock-library/src/Documentation/Haddock/Parser/Monad.hs @@ -1,8 +1,9 @@ +{-# LANGUAGE BangPatterns #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} -{-# LANGUAGE BangPatterns #-} + -- | -- Module : Documentation.Haddock.Parser.Monad -- Copyright : (c) Alec Theriault 2018-2019, @@ -15,53 +16,57 @@ -- Defines the Parsec monad over which all parsing is done and also provides -- more efficient versions of the usual parsec combinator functions (but -- specialized to 'Text'). - module Documentation.Haddock.Parser.Monad where -import qualified Text.Parsec.Char as Parsec +import Text.Parsec + ( State (..) + , getParserState + , setParserState + ) import qualified Text.Parsec as Parsec -import Text.Parsec.Pos ( updatePosChar ) -import Text.Parsec ( State(..) - , getParserState, setParserState ) +import qualified Text.Parsec.Char as Parsec +import Text.Parsec.Pos (updatePosChar) +import Data.Text (Text) import qualified Data.Text as T -import Data.Text ( Text ) -import Control.Monad ( mfilter ) -import Data.String ( IsString(..) ) -import Data.Bits ( Bits(..) ) -import Data.Char ( ord ) -import Data.List ( foldl' ) -import Control.Applicative as App +import Control.Applicative as App +import Control.Monad (mfilter) +import Data.Bits (Bits (..)) +import Data.Char (ord) +import Data.List (foldl') +import Data.String (IsString (..)) -import Documentation.Haddock.Types ( MetaSince(..) ) +import Documentation.Haddock.Types (MetaSince (..)) -import Prelude hiding (takeWhile) -import CompatPrelude +import CompatPrelude +import Prelude hiding (takeWhile) -- | The only bit of information we really care about trudging along with us -- through parsing is the version attached to a @\@since@ annotation - if -- the doc even contained one. -newtype ParserState = ParserState { - parserStateSince :: Maybe MetaSince -} deriving (Eq, Show) +newtype ParserState = ParserState + { parserStateSince :: Maybe MetaSince + } + deriving (Eq, Show) initialParserState :: ParserState initialParserState = ParserState Nothing setSince :: MetaSince -> Parser () -setSince since = Parsec.modifyState (\st -> st{ parserStateSince = Just since }) +setSince since = Parsec.modifyState (\st -> st{parserStateSince = Just since}) type Parser = Parsec.Parsec Text ParserState -instance (a ~ Text) => IsString (Parser a) where +instance a ~ Text => IsString (Parser a) where fromString = fmap T.pack . Parsec.string parseOnly :: Parser a -> Text -> Either String (ParserState, a) parseOnly p t = case Parsec.runParser p' initialParserState "" t of - Left e -> Left (show e) - Right (x,s) -> Right (s,x) - where p' = (,) <$> p <*> Parsec.getState + Left e -> Left (show e) + Right (x, s) -> Right (s, x) + where + p' = (,) <$> p <*> Parsec.getState -- | Always succeeds, but returns 'Nothing' if at the end of input. Does not -- consume input. @@ -70,8 +75,10 @@ parseOnly p t = case Parsec.runParser p' initialParserState "" t of -- more efficient. peekChar :: Parser (Maybe Char) peekChar = headOpt . stateInput <$> getParserState - where headOpt t | T.null t = Nothing - | otherwise = Just (T.head t) + where + headOpt t + | T.null t = Nothing + | otherwise = Just (T.head t) {-# INLINE peekChar #-} -- | Fails if at the end of input. Does not consume input. @@ -79,8 +86,10 @@ peekChar = headOpt . stateInput <$> getParserState -- Equivalent to @Parsec.lookAhead Parsec.anyChar@, but more efficient. peekChar' :: Parser Char peekChar' = headFail . stateInput =<< getParserState - where headFail t | T.null t = Parsec.parserFail "peekChar': reached EOF" - | otherwise = App.pure (T.head t) + where + headFail t + | T.null t = Parsec.parserFail "peekChar': reached EOF" + | otherwise = App.pure (T.head t) {-# INLINE peekChar' #-} -- | Parses the given string. Returns the parsed string. @@ -88,13 +97,13 @@ peekChar' = headFail . stateInput =<< getParserState -- Equivalent to @Parsec.string (T.unpack t) $> t@, but more efficient. string :: Text -> Parser Text string t = do - s@State{ stateInput = inp, statePos = pos } <- getParserState + s@State{stateInput = inp, statePos = pos} <- getParserState case T.stripPrefix t inp of Nothing -> Parsec.parserFail "string: Failed to match the input string" Just inp' -> let pos' = T.foldl updatePosChar pos t - s' = s{ stateInput = inp', statePos = pos' } - in setParserState s' $> t + s' = s{stateInput = inp', statePos = pos'} + in setParserState s' $> t -- | Keep matching characters as long as the predicate function holds (and -- return them). @@ -102,10 +111,10 @@ string t = do -- Equivalent to @fmap T.pack . Parsec.many@, but more efficient. takeWhile :: (Char -> Bool) -> Parser Text takeWhile f = do - s@State{ stateInput = inp, statePos = pos } <- getParserState + s@State{stateInput = inp, statePos = pos} <- getParserState let (t, inp') = T.span f inp pos' = T.foldl updatePosChar pos t - s' = s{ stateInput = inp', statePos = pos' } + s' = s{stateInput = inp', statePos = pos'} setParserState s' $> t -- | Like 'takeWhile', but fails if no characters matched. @@ -116,34 +125,39 @@ takeWhile1 = mfilter (not . T.null) . takeWhile -- | Scan the input text, accumulating characters as long as the scanning -- function returns true. -scan :: (s -> Char -> Maybe s) -- ^ scan function - -> s -- ^ initial state - -> Parser Text +scan + :: (s -> Char -> Maybe s) + -- ^ scan function + -> s + -- ^ initial state + -> Parser Text scan f st = do - s@State{ stateInput = inp, statePos = pos } <- getParserState + s@State{stateInput = inp, statePos = pos} <- getParserState go inp st pos 0 $ \inp' pos' n -> - let s' = s{ Parsec.stateInput = inp', Parsec.statePos = pos' } - in setParserState s' $> T.take n inp + let s' = s{Parsec.stateInput = inp', Parsec.statePos = pos'} + in setParserState s' $> T.take n inp where - go inp s !pos !n cont - = case T.uncons inp of - Nothing -> cont inp pos n -- ran out of input - Just (c, inp') -> - case f s c of - Nothing -> cont inp pos n -- scan function failed - Just s' -> go inp' s' (updatePosChar pos c) (n+1) cont - + go inp s !pos !n cont = + case T.uncons inp of + Nothing -> cont inp pos n -- ran out of input + Just (c, inp') -> + case f s c of + Nothing -> cont inp pos n -- scan function failed + Just s' -> go inp' s' (updatePosChar pos c) (n + 1) cont -- | Parse a decimal number. decimal :: Integral a => Parser a decimal = foldl' step 0 `fmap` Parsec.many1 Parsec.digit - where step a c = a * 10 + fromIntegral (ord c - 48) + where + step a c = a * 10 + fromIntegral (ord c - 48) -- | Parse a hexadecimal number. hexadecimal :: (Integral a, Bits a) => Parser a -hexadecimal = foldl' step 0 `fmap` Parsec.many1 Parsec.hexDigit +hexadecimal = foldl' step 0 `fmap` Parsec.many1 Parsec.hexDigit where - step a c | w >= 48 && w <= 57 = (a `shiftL` 4) .|. fromIntegral (w - 48) - | w >= 97 = (a `shiftL` 4) .|. fromIntegral (w - 87) - | otherwise = (a `shiftL` 4) .|. fromIntegral (w - 55) - where w = ord c + step a c + | w >= 48 && w <= 57 = (a `shiftL` 4) .|. fromIntegral (w - 48) + | w >= 97 = (a `shiftL` 4) .|. fromIntegral (w - 87) + | otherwise = (a `shiftL` 4) .|. fromIntegral (w - 55) + where + w = ord c diff --git a/haddock-library/src/Documentation/Haddock/Parser/Util.hs b/haddock-library/src/Documentation/Haddock/Parser/Util.hs index eef744d864..3cc85bcc7a 100644 --- a/haddock-library/src/Documentation/Haddock/Parser/Util.hs +++ b/haddock-library/src/Documentation/Haddock/Parser/Util.hs @@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-} + -- | -- Module : Documentation.Haddock.Parser.Util -- Copyright : (c) Mateusz Kowalczyk 2013-2014, @@ -10,25 +11,25 @@ -- Portability : portable -- -- Various utility functions used by the parser. -module Documentation.Haddock.Parser.Util ( - takeUntil, - removeEscapes, - makeLabeled, - takeHorizontalSpace, - skipHorizontalSpace, -) where +module Documentation.Haddock.Parser.Util + ( takeUntil + , removeEscapes + , makeLabeled + , takeHorizontalSpace + , skipHorizontalSpace + ) where import qualified Text.Parsec as Parsec +import Data.Text (Text) import qualified Data.Text as T -import Data.Text (Text) -import Control.Applicative -import Control.Monad (mfilter) -import Documentation.Haddock.Parser.Monad -import Prelude hiding (takeWhile) +import Control.Applicative +import Control.Monad (mfilter) +import Documentation.Haddock.Parser.Monad +import Prelude hiding (takeWhile) -import Data.Char (isSpace) +import Data.Char (isSpace) -- | Characters that count as horizontal space horizontalSpace :: Char -> Bool @@ -44,7 +45,7 @@ takeHorizontalSpace = takeWhile horizontalSpace makeLabeled :: (String -> Maybe String -> a) -> Text -> a makeLabeled f input = case T.break isSpace $ removeEscapes $ T.strip input of - (uri, "") -> f (T.unpack uri) Nothing + (uri, "") -> f (T.unpack uri) Nothing (uri, label) -> f (T.unpack uri) (Just . T.unpack $ T.stripStart label) -- | Remove escapes from given string. @@ -53,10 +54,10 @@ makeLabeled f input = case T.break isSpace $ removeEscapes $ T.strip input of removeEscapes :: Text -> Text removeEscapes = T.unfoldr go where - go :: Text -> Maybe (Char, Text) - go xs = case T.uncons xs of - Just ('\\',ys) -> T.uncons ys - unconsed -> unconsed + go :: Text -> Maybe (Char, Text) + go xs = case T.uncons xs of + Just ('\\', ys) -> T.uncons ys + unconsed -> unconsed -- | Consume characters from the input up to and including the given pattern. -- Return everything consumed except for the end pattern itself. @@ -69,7 +70,7 @@ takeUntil end_ = T.dropEnd (T.length end_) <$> requireEnd (scan p (False, end)) p acc c = case acc of (True, _) -> Just (False, end) (_, []) -> Nothing - (_, x:xs) | x == c -> Just (False, xs) + (_, x : xs) | x == c -> Just (False, xs) _ -> Just (c == '\\', end) requireEnd = mfilter (T.isSuffixOf end_) diff --git a/haddock-library/src/Documentation/Haddock/Types.hs b/haddock-library/src/Documentation/Haddock/Types.hs index fc34768c58..424e7f86ca 100644 --- a/haddock-library/src/Documentation/Haddock/Types.hs +++ b/haddock-library/src/Documentation/Haddock/Types.hs @@ -1,4 +1,5 @@ -{-# LANGUAGE CPP, DeriveTraversable #-} +{-# LANGUAGE CPP #-} +{-# LANGUAGE DeriveTraversable #-} -- | -- Module : Documentation.Haddock.Types @@ -31,23 +32,27 @@ import Data.Bitraversable #endif -- | A @\@since@ declaration. -data MetaSince = - MetaSince { sincePackage :: Maybe Package - -- ^ optional package qualification - , sinceVersion :: Version - } deriving (Eq, Show) +data MetaSince = MetaSince + { sincePackage :: Maybe Package + -- ^ optional package qualification + , sinceVersion :: Version + } + deriving (Eq, Show) -- | With the advent of 'Version', we may want to start attaching more -- meta-data to comments. We make a structure for this ahead of time -- so we don't have to gut half the core each time we want to add such -- info. -data Meta = Meta { _metaSince :: Maybe MetaSince - } deriving (Eq, Show) +data Meta = Meta + { _metaSince :: Maybe MetaSince + } + deriving (Eq, Show) -data MetaDoc mod id = - MetaDoc { _meta :: Meta - , _doc :: DocH mod id - } deriving (Eq, Show, Functor, Foldable, Traversable) +data MetaDoc mod id = MetaDoc + { _meta :: Meta + , _doc :: DocH mod id + } + deriving (Eq, Show, Functor, Foldable, Traversable) #if MIN_VERSION_base(4,8,0) -- | __NOTE__: Only defined for @base >= 4.8.0@ @@ -66,53 +71,62 @@ instance Bitraversable MetaDoc where #endif overDoc :: (DocH a b -> DocH c d) -> MetaDoc a b -> MetaDoc c d -overDoc f d = d { _doc = f $ _doc d } +overDoc f d = d{_doc = f $ _doc d} overDocF :: Functor f => (DocH a b -> f (DocH c d)) -> MetaDoc a b -> f (MetaDoc c d) -overDocF f d = (\x -> d { _doc = x }) <$> f (_doc d) +overDocF f d = (\x -> d{_doc = x}) <$> f (_doc d) type Version = [Int] type Package = String data Hyperlink id = Hyperlink - { hyperlinkUrl :: String + { hyperlinkUrl :: String , hyperlinkLabel :: Maybe id - } deriving (Eq, Show, Functor, Foldable, Traversable) + } + deriving (Eq, Show, Functor, Foldable, Traversable) data ModLink id = ModLink - { modLinkName :: String + { modLinkName :: String , modLinkLabel :: Maybe id - } deriving (Eq, Show, Functor, Foldable, Traversable) + } + deriving (Eq, Show, Functor, Foldable, Traversable) data Picture = Picture - { pictureUri :: String + { pictureUri :: String , pictureTitle :: Maybe String - } deriving (Eq, Show) + } + deriving (Eq, Show) data Header id = Header - { headerLevel :: Int -- ^ between 1 and 6 inclusive + { headerLevel :: Int + -- ^ between 1 and 6 inclusive , headerTitle :: id - } deriving (Eq, Show, Functor, Foldable, Traversable) + } + deriving (Eq, Show, Functor, Foldable, Traversable) data Example = Example { exampleExpression :: String - , exampleResult :: [String] - } deriving (Eq, Show) + , exampleResult :: [String] + } + deriving (Eq, Show) data TableCell id = TableCell - { tableCellColspan :: Int - , tableCellRowspan :: Int + { tableCellColspan :: Int + , tableCellRowspan :: Int , tableCellContents :: id - } deriving (Eq, Show, Functor, Foldable, Traversable) + } + deriving (Eq, Show, Functor, Foldable, Traversable) newtype TableRow id = TableRow { tableRowCells :: [TableCell id] - } deriving (Eq, Show, Functor, Foldable, Traversable) + } + deriving (Eq, Show, Functor, Foldable, Traversable) data Table id = Table { tableHeaderRows :: [TableRow id] - , tableBodyRows :: [TableRow id] - } deriving (Eq, Show, Functor, Foldable, Traversable) + , tableBodyRows :: [TableRow id] + } + deriving (Eq, Show, Functor, Foldable, Traversable) data DocH mod id = DocEmpty @@ -120,12 +134,12 @@ data DocH mod id | DocString String | DocParagraph (DocH mod id) | DocIdentifier id - | DocIdentifierUnchecked mod - -- ^ A qualified identifier that couldn't be resolved. - | DocModule (ModLink (DocH mod id)) - -- ^ A link to a module, with an optional label. - | DocWarning (DocH mod id) - -- ^ This constructor has no counterpart in Haddock markup. + | -- | A qualified identifier that couldn't be resolved. + DocIdentifierUnchecked mod + | -- | A link to a module, with an optional label. + DocModule (ModLink (DocH mod id)) + | -- | This constructor has no counterpart in Haddock markup. + DocWarning (DocH mod id) | DocEmphasis (DocH mod id) | DocMonospaced (DocH mod id) | DocBold (DocH mod id) @@ -137,8 +151,8 @@ data DocH mod id | DocPic Picture | DocMathInline String | DocMathDisplay String - | DocAName String - -- ^ A (HTML) anchor. It must not contain any spaces. + | -- | A (HTML) anchor. It must not contain any spaces. + DocAName String | DocProperty String | DocExamples [Example] | DocHeader (Header (DocH mod id)) @@ -231,7 +245,6 @@ renderNs Value = "v" renderNs Type = "t" renderNs None = "" - -- | 'DocMarkupH' is a set of instructions for marking up documentation. -- In fact, it's really just a mapping from 'Doc' to some other -- type [a], where [a] is usually the type of the output (HTML, say). @@ -239,30 +252,29 @@ renderNs None = "" -- a 'DocH'. -- -- @since 1.4.5 --- data DocMarkupH mod id a = Markup - { markupEmpty :: a - , markupString :: String -> a - , markupParagraph :: a -> a - , markupAppend :: a -> a -> a - , markupIdentifier :: id -> a - , markupIdentifierUnchecked :: mod -> a - , markupModule :: ModLink a -> a - , markupWarning :: a -> a - , markupEmphasis :: a -> a - , markupBold :: a -> a - , markupMonospaced :: a -> a - , markupUnorderedList :: [a] -> a - , markupOrderedList :: [(Int,a)] -> a - , markupDefList :: [(a,a)] -> a - , markupCodeBlock :: a -> a - , markupHyperlink :: Hyperlink a -> a - , markupAName :: String -> a - , markupPic :: Picture -> a - , markupMathInline :: String -> a - , markupMathDisplay :: String -> a - , markupProperty :: String -> a - , markupExample :: [Example] -> a - , markupHeader :: Header a -> a - , markupTable :: Table a -> a + { markupEmpty :: a + , markupString :: String -> a + , markupParagraph :: a -> a + , markupAppend :: a -> a -> a + , markupIdentifier :: id -> a + , markupIdentifierUnchecked :: mod -> a + , markupModule :: ModLink a -> a + , markupWarning :: a -> a + , markupEmphasis :: a -> a + , markupBold :: a -> a + , markupMonospaced :: a -> a + , markupUnorderedList :: [a] -> a + , markupOrderedList :: [(Int, a)] -> a + , markupDefList :: [(a, a)] -> a + , markupCodeBlock :: a -> a + , markupHyperlink :: Hyperlink a -> a + , markupAName :: String -> a + , markupPic :: Picture -> a + , markupMathInline :: String -> a + , markupMathDisplay :: String -> a + , markupProperty :: String -> a + , markupExample :: [Example] -> a + , markupHeader :: Header a -> a + , markupTable :: Table a -> a } diff --git a/haddock-library/test/Documentation/Haddock/Parser/UtilSpec.hs b/haddock-library/test/Documentation/Haddock/Parser/UtilSpec.hs index 716e1adc51..ee16569798 100644 --- a/haddock-library/test/Documentation/Haddock/Parser/UtilSpec.hs +++ b/haddock-library/test/Documentation/Haddock/Parser/UtilSpec.hs @@ -1,10 +1,11 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} + module Documentation.Haddock.Parser.UtilSpec (main, spec) where +import Data.Either (isLeft) import Documentation.Haddock.Parser.Monad import Documentation.Haddock.Parser.Util -import Data.Either (isLeft) import Test.Hspec #if !(MIN_VERSION_base(4,8,0)) import Control.Applicative diff --git a/haddock-library/test/Documentation/Haddock/ParserSpec.hs b/haddock-library/test/Documentation/Haddock/ParserSpec.hs index fc69d72884..a2b36cc95a 100644 --- a/haddock-library/test/Documentation/Haddock/ParserSpec.hs +++ b/haddock-library/test/Documentation/Haddock/ParserSpec.hs @@ -1,17 +1,18 @@ -{-# LANGUAGE OverloadedStrings, FlexibleInstances #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE OverloadedStrings #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Documentation.Haddock.ParserSpec (main, spec) where -import Data.Char (isSpace) -import Data.String +import Data.Char (isSpace) +import Data.String +import Documentation.Haddock.Doc (docAppend) import qualified Documentation.Haddock.Parser as Parse -import Documentation.Haddock.Types -import Documentation.Haddock.Doc (docAppend) -import Test.Hspec -import Test.QuickCheck +import Documentation.Haddock.Types +import Test.Hspec +import Test.QuickCheck -import Prelude hiding ((<>)) +import Prelude hiding ((<>)) infixr 6 <> (<>) :: Doc id -> Doc id -> Doc id @@ -27,9 +28,9 @@ instance IsString a => IsString (Maybe a) where emptyMeta :: Meta emptyMeta = - Meta { - _metaSince = Nothing - } + Meta + { _metaSince = Nothing + } parseParas :: String -> MetaDoc () String parseParas = overDoc Parse.toRegular . Parse.parseParas Nothing @@ -99,14 +100,14 @@ spec = do "'Foo.bar'" `shouldParseTo` DocIdentifier "Foo.bar" it "parses a word with an one of the delimiters in it as DocString" $ do - "don't" `shouldParseTo` "don't" + "don't" `shouldParseTo` "don't" it "doesn't pass pairs of delimiters with spaces between them" $ do "hel'lo w'orld" `shouldParseTo` "hel'lo w'orld" it "don't use apostrophe's in the wrong place's" $ do - " don't use apostrophe's in the wrong place's" `shouldParseTo` - "don't use apostrophe's in the wrong place's" + " don't use apostrophe's in the wrong place's" + `shouldParseTo` "don't use apostrophe's in the wrong place's" it "doesn't parse empty identifiers" $ do "``" `shouldParseTo` "``" @@ -176,65 +177,66 @@ spec = do -- new behaviour test, this will be now consistent with other markup it "allows us to escape > inside the URL" $ do - "le.com>" `shouldParseTo` - hyperlink "http://examp>le.com" Nothing + "le.com>" + `shouldParseTo` hyperlink "http://examp>le.com" Nothing - "mp\\>le.com>" `shouldParseTo` - hyperlink "http://exa>mp>le.com" Nothing + "mp\\>le.com>" + `shouldParseTo` hyperlink "http://exa>mp>le.com" Nothing -- Likewise in label - "oo>" `shouldParseTo` - hyperlink "http://example.com" "f>oo" + "oo>" + `shouldParseTo` hyperlink "http://example.com" "f>oo" it "parses inline URLs" $ do - "foo bar" `shouldParseTo` - "foo " <> hyperlink "http://example.com/" Nothing <> " bar" + "foo bar" + `shouldParseTo` "foo " + <> hyperlink "http://example.com/" Nothing + <> " bar" it "doesn't allow for multi-line link tags" $ do "" `shouldParseTo` "" context "when parsing markdown links" $ do it "parses a simple link" $ do - "[some label](url)" `shouldParseTo` - hyperlink "url" "some label" + "[some label](url)" + `shouldParseTo` hyperlink "url" "some label" it "allows whitespace between label and URL" $ do - "[some label] \t (url)" `shouldParseTo` - hyperlink "url" "some label" + "[some label] \t (url)" + `shouldParseTo` hyperlink "url" "some label" it "allows newlines in label" $ do - "[some\n\nlabel](url)" `shouldParseTo` - hyperlink "url" "some\n\nlabel" + "[some\n\nlabel](url)" + `shouldParseTo` hyperlink "url" "some\n\nlabel" it "allows escaping in label" $ do - "[some\\] label](url)" `shouldParseTo` - hyperlink "url" "some] label" + "[some\\] label](url)" + `shouldParseTo` hyperlink "url" "some] label" it "strips leading and trailing whitespace from label" $ do - "[ some label ](url)" `shouldParseTo` - hyperlink "url" "some label" + "[ some label ](url)" + `shouldParseTo` hyperlink "url" "some label" it "rejects whitespace in URL" $ do - "[some label]( url)" `shouldParseTo` - "[some label]( url)" + "[some label]( url)" + `shouldParseTo` "[some label]( url)" it "allows inline markup in the label" $ do - "[something /emphasized/](url)" `shouldParseTo` - hyperlink "url" (Just ("something " <> DocEmphasis "emphasized")) + "[something /emphasized/](url)" + `shouldParseTo` hyperlink "url" (Just ("something " <> DocEmphasis "emphasized")) context "when URL is on a separate line" $ do it "allows URL to be on a separate line" $ do - "[some label]\n(url)" `shouldParseTo` - hyperlink "url" "some label" + "[some label]\n(url)" + `shouldParseTo` hyperlink "url" "some label" it "allows leading whitespace" $ do - "[some label]\n \t (url)" `shouldParseTo` - hyperlink "url" "some label" + "[some label]\n \t (url)" + `shouldParseTo` hyperlink "url" "some label" it "rejects additional newlines" $ do - "[some label]\n\n(url)" `shouldParseTo` - "[some label]\n\n(url)" - + "[some label]\n\n(url)" + `shouldParseTo` "[some label]\n\n(url)" context "when autolinking URLs" $ do it "autolinks HTTP URLs" $ do @@ -247,24 +249,30 @@ spec = do "ftp://example.com/" `shouldParseTo` hyperlink "ftp://example.com/" Nothing it "does not include a trailing comma" $ do - "http://example.com/, Some other sentence." `shouldParseTo` - hyperlink "http://example.com/" Nothing <> ", Some other sentence." + "http://example.com/, Some other sentence." + `shouldParseTo` hyperlink "http://example.com/" Nothing + <> ", Some other sentence." it "does not include a trailing dot" $ do - "http://example.com/. Some other sentence." `shouldParseTo` - hyperlink "http://example.com/" Nothing <> ". Some other sentence." + "http://example.com/. Some other sentence." + `shouldParseTo` hyperlink "http://example.com/" Nothing + <> ". Some other sentence." it "does not include a trailing exclamation mark" $ do - "http://example.com/! Some other sentence." `shouldParseTo` - hyperlink "http://example.com/" Nothing <> "! Some other sentence." + "http://example.com/! Some other sentence." + `shouldParseTo` hyperlink "http://example.com/" Nothing + <> "! Some other sentence." it "does not include a trailing question mark" $ do - "http://example.com/? Some other sentence." `shouldParseTo` - hyperlink "http://example.com/" Nothing <> "? Some other sentence." + "http://example.com/? Some other sentence." + `shouldParseTo` hyperlink "http://example.com/" Nothing + <> "? Some other sentence." it "autolinks URLs occuring mid-sentence with multiple ‘/’s" $ do - "foo https://example.com/example bar" `shouldParseTo` - "foo " <> hyperlink "https://example.com/example" Nothing <> " bar" + "foo https://example.com/example bar" + `shouldParseTo` "foo " + <> hyperlink "https://example.com/example" Nothing + <> " bar" context "when parsing images" $ do let image :: String -> Maybe String -> Doc String @@ -283,9 +291,8 @@ spec = do "<>" `shouldParseTo` image "b" "a z" context "when parsing display math" $ do - it "accepts markdown syntax for display math containing newlines" $ do - "\\[\\pi\n\\pi\\]" `shouldParseTo` DocMathDisplay "\\pi\n\\pi" + "\\[\\pi\n\\pi\\]" `shouldParseTo` DocMathDisplay "\\pi\n\\pi" context "when parsing anchors" $ do it "parses a single word anchor" $ do @@ -304,7 +311,9 @@ spec = do it "accepts anchors mid-paragraph" $ do "Hello #someAnchor# world!" - `shouldParseTo` "Hello " <> DocAName "someAnchor" <> " world!" + `shouldParseTo` "Hello " + <> DocAName "someAnchor" + <> " world!" it "does not accept empty anchors" $ do "##" `shouldParseTo` "##" @@ -332,8 +341,8 @@ spec = do "/foo\\/bar/" `shouldParseTo` DocEmphasis "foo/bar" it "recognizes other markup constructs within emphasised text" $ do - "/foo @bar@ baz/" `shouldParseTo` - DocEmphasis ("foo " <> DocMonospaced "bar" <> " baz") + "/foo @bar@ baz/" + `shouldParseTo` DocEmphasis ("foo " <> DocMonospaced "bar" <> " baz") it "allows other markup inside of emphasis" $ do "/__inner bold__/" `shouldParseTo` DocEmphasis (DocBold "inner bold") @@ -368,48 +377,51 @@ spec = do context "when parsing bold strings" $ do it "allows for a bold string on its own" $ do - "__bold string__" `shouldParseTo` - DocBold "bold string" + "__bold string__" + `shouldParseTo` DocBold "bold string" it "bolds inline correctly" $ do - "hello __everyone__ there" `shouldParseTo` - "hello " - <> DocBold "everyone" <> " there" + "hello __everyone__ there" + `shouldParseTo` "hello " + <> DocBold "everyone" + <> " there" it "bolds unicode" $ do - "__灼眼のシャナ__" `shouldParseTo` - DocBold "灼眼のシャナ" + "__灼眼のシャナ__" + `shouldParseTo` DocBold "灼眼のシャナ" it "does not do __multi-line\\n bold__" $ do " __multi-line\n bold__" `shouldParseTo` "__multi-line\n bold__" it "allows other markup inside of bold" $ do - "__/inner emphasis/__" `shouldParseTo` - (DocBold $ DocEmphasis "inner emphasis") + "__/inner emphasis/__" + `shouldParseTo` (DocBold $ DocEmphasis "inner emphasis") it "doesn't mangle inner markup unicode" $ do - "__/灼眼のシャナ A/__" `shouldParseTo` - (DocBold $ DocEmphasis "灼眼のシャナ A") + "__/灼眼のシャナ A/__" + `shouldParseTo` (DocBold $ DocEmphasis "灼眼のシャナ A") it "properly converts HTML escape sequences" $ do - "__AAAA__" `shouldParseTo` - DocBold "AAAA" + "__AAAA__" + `shouldParseTo` DocBold "AAAA" it "allows to escape the bold delimiter inside of bold" $ do - "__bo\\__ld__" `shouldParseTo` - DocBold "bo__ld" + "__bo\\__ld__" + `shouldParseTo` DocBold "bo__ld" it "doesn't allow for empty bold" $ do "____" `shouldParseTo` "____" context "when parsing module strings" $ do it "should parse a module on its own" $ do - "\"Module\"" `shouldParseTo` - DocModule (ModLink "Module" Nothing) + "\"Module\"" + `shouldParseTo` DocModule (ModLink "Module" Nothing) it "should parse a module inline" $ do - "This is a \"Module\"." `shouldParseTo` - "This is a " <> DocModule (ModLink "Module" Nothing) <> "." + "This is a \"Module\"." + `shouldParseTo` "This is a " + <> DocModule (ModLink "Module" Nothing) + <> "." it "can accept a simple module name" $ do "\"Hello\"" `shouldParseTo` DocModule (ModLink "Hello" Nothing) @@ -446,32 +458,34 @@ spec = do context "when parsing labeled module links" $ do it "parses a simple labeled module link" $ do - "[some label](\"Some.Module\")" `shouldParseTo` - DocModule (ModLink "Some.Module" (Just "some label")) + "[some label](\"Some.Module\")" + `shouldParseTo` DocModule (ModLink "Some.Module" (Just "some label")) it "allows escaping in label" $ do - "[some\\] label](\"Some.Module\")" `shouldParseTo` - DocModule (ModLink "Some.Module" (Just "some] label")) + "[some\\] label](\"Some.Module\")" + `shouldParseTo` DocModule (ModLink "Some.Module" (Just "some] label")) it "strips leading and trailing whitespace from label" $ do - "[ some label ](\"Some.Module\")" `shouldParseTo` - DocModule (ModLink "Some.Module" (Just "some label")) + "[ some label ](\"Some.Module\")" + `shouldParseTo` DocModule (ModLink "Some.Module" (Just "some label")) it "allows whitespace in module name link" $ do - "[some label]( \"Some.Module\"\t )" `shouldParseTo` - DocModule (ModLink "Some.Module" (Just "some label")) + "[some label]( \"Some.Module\"\t )" + `shouldParseTo` DocModule (ModLink "Some.Module" (Just "some label")) it "allows inline markup in the label" $ do - "[something /emphasized/](\"Some.Module\")" `shouldParseTo` - DocModule (ModLink "Some.Module" (Just ("something " <> DocEmphasis "emphasized"))) + "[something /emphasized/](\"Some.Module\")" + `shouldParseTo` DocModule (ModLink "Some.Module" (Just ("something " <> DocEmphasis "emphasized"))) it "should parse a labeled module on its own" $ do - "[label](\"Module\")" `shouldParseTo` - DocModule (ModLink "Module" (Just "label")) + "[label](\"Module\")" + `shouldParseTo` DocModule (ModLink "Module" (Just "label")) it "should parse a labeled module inline" $ do - "This is a [label](\"Module\")." `shouldParseTo` - "This is a " <> DocModule (ModLink "Module" (Just "label")) <> "." + "This is a [label](\"Module\")." + `shouldParseTo` "This is a " + <> DocModule (ModLink "Module" (Just "label")) + <> "." it "can accept a labeled module name with dots" $ do "[label](\"Hello.World\")" `shouldParseTo` DocModule (ModLink "Hello.World" (Just "label")) @@ -480,35 +494,37 @@ spec = do "[label](\"Hello.Worldλ\")" `shouldParseTo` DocModule (ModLink "Hello.Worldλ" (Just "label")) it "parses a labeled module name with a trailing dot as a hyperlink" $ do - "[label](\"Hello.\")" `shouldParseTo` - hyperlink "\"Hello.\"" (Just "label") + "[label](\"Hello.\")" + `shouldParseTo` hyperlink "\"Hello.\"" (Just "label") it "parses a labeled module name with a space as a regular string" $ do "[label](\"Hello World\")" `shouldParseTo` "[label](\"Hello World\")" it "parses a module name with invalid characters as a hyperlink" $ do - "[label](\"Hello&[{}(=*+]!\")" `shouldParseTo` - hyperlink "\"Hello&[{}(=*+]!\"" (Just "label") + "[label](\"Hello&[{}(=*+]!\")" + `shouldParseTo` hyperlink "\"Hello&[{}(=*+]!\"" (Just "label") it "accepts a labeled module name with unicode" $ do - "[label](\"Foo.Barλ\")" `shouldParseTo` - DocModule (ModLink "Foo.Barλ" (Just "label")) + "[label](\"Foo.Barλ\")" + `shouldParseTo` DocModule (ModLink "Foo.Barλ" (Just "label")) it "treats empty labeled module name as empty hyperlink" $ do - "[label](\"\")" `shouldParseTo` - hyperlink "\"\"" (Just "label") + "[label](\"\")" + `shouldParseTo` hyperlink "\"\"" (Just "label") it "accepts anchor reference syntax for labeled module name" $ do - "[label](\"Foo#bar\")" `shouldParseTo` - DocModule (ModLink "Foo#bar" (Just "label")) + "[label](\"Foo#bar\")" + `shouldParseTo` DocModule (ModLink "Foo#bar" (Just "label")) it "accepts old anchor reference syntax for labeled module name" $ do - "[label](\"Foo\\#bar\")" `shouldParseTo` - DocModule (ModLink "Foo\\#bar" (Just "label")) + "[label](\"Foo\\#bar\")" + `shouldParseTo` DocModule (ModLink "Foo\\#bar" (Just "label")) it "interprets empty label as a unlabeled module name" $ do - "[](\"Module.Name\")" `shouldParseTo` - "[](" <> DocModule (ModLink "Module.Name" Nothing) <> ")" + "[](\"Module.Name\")" + `shouldParseTo` "[](" + <> DocModule (ModLink "Module.Name" Nothing) + <> ")" describe "parseParas" $ do let infix 1 `shouldParseTo` @@ -525,39 +541,61 @@ spec = do context "when parsing @since" $ do it "adds specified version to the result" $ do - parseParas "@since 0.5.0" `shouldBe` - MetaDoc { _meta = emptyMeta { _version = Just [0,5,0] } - , _doc = DocEmpty } + parseParas "@since 0.5.0" + `shouldBe` MetaDoc + { _meta = emptyMeta{_version = Just [0, 5, 0]} + , _doc = DocEmpty + } it "ignores trailing whitespace" $ do - parseParas "@since 0.5.0 \t " `shouldBe` - MetaDoc { _meta = emptyMeta { _version = Just [0,5,0] } - , _doc = DocEmpty } + parseParas "@since 0.5.0 \t " + `shouldBe` MetaDoc + { _meta = emptyMeta{_version = Just [0, 5, 0]} + , _doc = DocEmpty + } it "does not allow trailing input" $ do - parseParas "@since 0.5.0 foo" `shouldBe` - MetaDoc { _meta = emptyMeta { _version = Nothing } - , _doc = DocParagraph "@since 0.5.0 foo" } + parseParas "@since 0.5.0 foo" + `shouldBe` MetaDoc + { _meta = emptyMeta{_version = Nothing} + , _doc = DocParagraph "@since 0.5.0 foo" + } it "parses package name" $ do - parseParas "@since foo-bar-0.5.0" `shouldBe` - MetaDoc { _meta = emptyMeta { _metaSince = Just $ MetaSince { sincePackage = Just "foo-bar" - , sinceVersion = [0,5,0] } } - , _doc = DocParagraph "@since 0.5.0 foo" } - + parseParas "@since foo-bar-0.5.0" + `shouldBe` MetaDoc + { _meta = + emptyMeta + { _metaSince = + Just $ + MetaSince + { sincePackage = Just "foo-bar" + , sinceVersion = [0, 5, 0] + } + } + , _doc = DocParagraph "@since 0.5.0 foo" + } context "when given multiple times" $ do - it "gives last occurrence precedence" $ do - (parseParas . unlines) [ - "@since 0.5.0" - , "@since 0.6.0" - , "@since 0.7.0" - ] - `shouldBe` - MetaDoc { _meta = emptyMeta { _metaSince = Just $ MetaSince { sincePackage = Nothing - , sinceVersion = [0,7,0] } } - , _doc = DocEmpty } - + it "gives last occurrence precedence" $ + do + (parseParas . unlines) + [ "@since 0.5.0" + , "@since 0.6.0" + , "@since 0.7.0" + ] + `shouldBe` MetaDoc + { _meta = + emptyMeta + { _metaSince = + Just $ + MetaSince + { sincePackage = Nothing + , sinceVersion = [0, 7, 0] + } + } + , _doc = DocEmpty + } context "when parsing text paragraphs" $ do let isSpecial c = isSpace c || c `elem` (".(=#-[*`\\\"'_/@<>" :: String) @@ -573,15 +611,19 @@ spec = do "foo /bar/ baz" `shouldParseTo` DocParagraph ("foo " <> DocEmphasis "bar" <> " baz") it "preserve all regular characters" $ do - property $ \xs -> let input = filterSpecial xs in (not . null) input ==> - input `shouldParseTo` DocParagraph (DocString input) + property $ \xs -> + let input = filterSpecial xs + in (not . null) input ==> + input `shouldParseTo` DocParagraph (DocString input) it "separates paragraphs by empty lines" $ do - unlines [ - "foo" + unlines + [ "foo" , " \t " , "bar" - ] `shouldParseTo` DocParagraph "foo" <> DocParagraph "bar" + ] + `shouldParseTo` DocParagraph "foo" + <> DocParagraph "bar" context "when a pragraph only contains monospaced text" $ do it "turns it into a code block" $ do @@ -589,151 +631,172 @@ spec = do context "when a paragraph contains a markdown link" $ do it "correctly parses the link" $ do - "Blah [label](url)" `shouldParseTo` - DocParagraph ("Blah " <> hyperlink "url" "label") + "Blah [label](url)" + `shouldParseTo` DocParagraph ("Blah " <> hyperlink "url" "label") context "when the paragraph starts with the markdown link" $ do it "correctly parses it as a text paragraph (not a definition list)" $ do - "[label](url)" `shouldParseTo` - DocParagraph (hyperlink "url" "label") + "[label](url)" + `shouldParseTo` DocParagraph (hyperlink "url" "label") it "can be followed by an other paragraph" $ do - "[label](url)\n\nfoobar" `shouldParseTo` - DocParagraph (hyperlink "url" "label") <> DocParagraph "foobar" + "[label](url)\n\nfoobar" + `shouldParseTo` DocParagraph (hyperlink "url" "label") + <> DocParagraph "foobar" context "when paragraph contains additional text" $ do it "accepts more text after the link" $ do - "[label](url) foo bar baz" `shouldParseTo` - DocParagraph (hyperlink "url" "label" <> " foo bar baz") + "[label](url) foo bar baz" + `shouldParseTo` DocParagraph (hyperlink "url" "label" <> " foo bar baz") it "accepts a newline right after the markdown link" $ do - "[label](url)\nfoo bar baz" `shouldParseTo` - DocParagraph (hyperlink "url" "label" <> " foo bar baz") + "[label](url)\nfoo bar baz" + `shouldParseTo` DocParagraph (hyperlink "url" "label" <> " foo bar baz") it "can be followed by an other paragraph" $ do - "[label](url)foo\n\nbar" `shouldParseTo` - DocParagraph (hyperlink "url" "label" <> "foo") <> DocParagraph "bar" + "[label](url)foo\n\nbar" + `shouldParseTo` DocParagraph (hyperlink "url" "label" <> "foo") + <> DocParagraph "bar" context "when the link starts on a new line not at the beginning of the paragraph" $ do it "correctly parses the link" $ do - "Bla\n[label](url)" `shouldParseTo` - DocParagraph ("Bla\n" <> hyperlink "url" "label") + "Bla\n[label](url)" + `shouldParseTo` DocParagraph ("Bla\n" <> hyperlink "url" "label") context "when parsing birdtracks" $ do it "parses them as a code block" $ do - unlines [ - ">foo" + unlines + [ ">foo" , ">bar" , ">baz" - ] `shouldParseTo` DocCodeBlock "foo\nbar\nbaz" - - it "ignores leading whitespace" $ do - unlines [ - " >foo" - , " \t >bar" - , " >baz" ] - `shouldParseTo` DocCodeBlock "foo\nbar\nbaz" + `shouldParseTo` DocCodeBlock "foo\nbar\nbaz" + + it "ignores leading whitespace" $ + do + unlines + [ " >foo" + , " \t >bar" + , " >baz" + ] + `shouldParseTo` DocCodeBlock "foo\nbar\nbaz" it "strips one leading space from each line of the block" $ do - unlines [ - "> foo" + unlines + [ "> foo" , "> bar" , "> baz" - ] `shouldParseTo` DocCodeBlock "foo\n bar\nbaz" + ] + `shouldParseTo` DocCodeBlock "foo\n bar\nbaz" it "ignores empty lines when stripping spaces" $ do - unlines [ - "> foo" + unlines + [ "> foo" , ">" , "> bar" - ] `shouldParseTo` DocCodeBlock "foo\n\nbar" + ] + `shouldParseTo` DocCodeBlock "foo\n\nbar" context "when any non-empty line does not start with a space" $ do it "does not strip any spaces" $ do - unlines [ - ">foo" + unlines + [ ">foo" , "> bar" - ] `shouldParseTo` DocCodeBlock "foo\n bar" + ] + `shouldParseTo` DocCodeBlock "foo\n bar" it "ignores nested markup" $ do - unlines [ - ">/foo/" - ] `shouldParseTo` DocCodeBlock "/foo/" + unlines + [ ">/foo/" + ] + `shouldParseTo` DocCodeBlock "/foo/" it "treats them as regular text inside text paragraphs" $ do - unlines [ - "foo" + unlines + [ "foo" , ">bar" - ] `shouldParseTo` DocParagraph "foo\n>bar" + ] + `shouldParseTo` DocParagraph "foo\n>bar" context "when parsing code blocks" $ do it "accepts a simple code block" $ do - unlines [ - "@" + unlines + [ "@" , "foo" , "bar" , "baz" , "@" - ] `shouldParseTo` DocCodeBlock "foo\nbar\nbaz\n" + ] + `shouldParseTo` DocCodeBlock "foo\nbar\nbaz\n" it "ignores trailing whitespace after the opening @" $ do - unlines [ - "@ " + unlines + [ "@ " , "foo" , "@" - ] `shouldParseTo` DocCodeBlock "foo\n" + ] + `shouldParseTo` DocCodeBlock "foo\n" it "rejects code blocks that are not closed" $ do - unlines [ - "@" + unlines + [ "@" , "foo" - ] `shouldParseTo` DocParagraph "@\nfoo" + ] + `shouldParseTo` DocParagraph "@\nfoo" it "accepts nested markup" $ do - unlines [ - "@" + unlines + [ "@" , "/foo/" , "@" - ] `shouldParseTo` DocCodeBlock (DocEmphasis "foo" <> "\n") + ] + `shouldParseTo` DocCodeBlock (DocEmphasis "foo" <> "\n") it "allows to escape the @" $ do - unlines [ - "@" + unlines + [ "@" , "foo" , "\\@" , "bar" , "@" - ] `shouldParseTo` DocCodeBlock "foo\n@\nbar\n" + ] + `shouldParseTo` DocCodeBlock "foo\n@\nbar\n" it "accepts horizontal space before the @" $ do - unlines [ " @" - , "foo" - , "" - , "bar" - , "@" - ] `shouldParseTo` DocCodeBlock "foo\n\nbar\n" + unlines + [ " @" + , "foo" + , "" + , "bar" + , "@" + ] + `shouldParseTo` DocCodeBlock "foo\n\nbar\n" it "strips a leading space from a @ block if present" $ do - unlines [ " @" - , " hello" - , " world" - , " @" - ] `shouldParseTo` DocCodeBlock "hello\nworld\n" - - unlines [ " @" - , " hello" - , "" - , " world" - , " @" - ] `shouldParseTo` DocCodeBlock "hello\n\nworld\n" + unlines + [ " @" + , " hello" + , " world" + , " @" + ] + `shouldParseTo` DocCodeBlock "hello\nworld\n" + + unlines + [ " @" + , " hello" + , "" + , " world" + , " @" + ] + `shouldParseTo` DocCodeBlock "hello\n\nworld\n" it "only drops whitespace if there's some before closing @" $ do - unlines [ "@" - , " Formatting" - , " matters." - , "@" - ] + unlines + [ "@" + , " Formatting" + , " matters." + , "@" + ] `shouldParseTo` DocCodeBlock " Formatting\n matters.\n" it "accepts unicode" $ do @@ -743,34 +806,38 @@ spec = do "@foo /bar/ baz" `shouldParseTo` DocParagraph ("@foo " <> DocEmphasis "bar" <> " baz") - context "when parsing examples" $ do it "parses a simple example" $ do ">>> foo" `shouldParseTo` DocExamples [Example "foo" []] it "parses an example with result" $ do - unlines [ - ">>> foo" + unlines + [ ">>> foo" , "bar" , "baz" - ] `shouldParseTo` DocExamples [Example "foo" ["bar", "baz"]] + ] + `shouldParseTo` DocExamples [Example "foo" ["bar", "baz"]] it "parses consecutive examples" $ do - unlines [ - ">>> fib 5" + unlines + [ ">>> fib 5" , "5" , ">>> fib 10" , "55" - ] `shouldParseTo` DocExamples [ - Example "fib 5" ["5"] - , Example "fib 10" ["55"] ] + `shouldParseTo` DocExamples + [ Example "fib 5" ["5"] + , Example "fib 10" ["55"] + ] - it ("requires an example to be separated" - ++ " from a previous paragraph by an empty line") $ do - "foobar\n\n>>> fib 10\n55" `shouldParseTo` - DocParagraph "foobar" - <> DocExamples [Example "fib 10" ["55"]] + it + ( "requires an example to be separated" + ++ " from a previous paragraph by an empty line" + ) + $ do + "foobar\n\n>>> fib 10\n55" + `shouldParseTo` DocParagraph "foobar" + <> DocExamples [Example "fib 10" ["55"]] it "parses bird-tracks inside of paragraphs as plain strings" $ do let xs = "foo\n>>> bar" @@ -779,300 +846,344 @@ spec = do it "skips empty lines in front of an example" $ do "\n \n\n>>> foo" `shouldParseTo` DocExamples [Example "foo" []] - it "terminates example on empty line" $ do - unlines [ - ">>> foo" - , "bar" - , " " - , "baz" - ] - `shouldParseTo` - DocExamples [Example "foo" ["bar"]] <> DocParagraph "baz" - - it "parses a result as an empty result" $ do - unlines [ - ">>> foo" - , "bar" - , "" - , "baz" - ] - `shouldParseTo` DocExamples [Example "foo" ["bar", "", "baz"]] + it "terminates example on empty line" $ + do + unlines + [ ">>> foo" + , "bar" + , " " + , "baz" + ] + `shouldParseTo` DocExamples [Example "foo" ["bar"]] + <> DocParagraph "baz" + + it "parses a result as an empty result" $ + do + unlines + [ ">>> foo" + , "bar" + , "" + , "baz" + ] + `shouldParseTo` DocExamples [Example "foo" ["bar", "", "baz"]] it "accepts unicode in examples" $ do ">>> 灼眼\nシャナ" `shouldParseTo` DocExamples [Example "灼眼" ["シャナ"]] context "when prompt is prefixed by whitespace" $ do it "strips the exact same amount of whitespace from result lines" $ do - unlines [ - " >>> foo" + unlines + [ " >>> foo" , " bar" , " baz" - ] `shouldParseTo` DocExamples [Example "foo" ["bar", "baz"]] + ] + `shouldParseTo` DocExamples [Example "foo" ["bar", "baz"]] it "preserves additional whitespace" $ do - unlines [ - " >>> foo" + unlines + [ " >>> foo" , " bar" - ] `shouldParseTo` DocExamples [Example "foo" [" bar"]] + ] + `shouldParseTo` DocExamples [Example "foo" [" bar"]] it "keeps original if stripping is not possible" $ do - unlines [ - " >>> foo" + unlines + [ " >>> foo" , " bar" - ] `shouldParseTo` DocExamples [Example "foo" [" bar"]] - + ] + `shouldParseTo` DocExamples [Example "foo" [" bar"]] context "when parsing paragraphs nested in lists" $ do it "can nest the same type of list" $ do - "* foo\n\n * bar" `shouldParseTo` - DocUnorderedList [ DocParagraph "foo" - <> DocUnorderedList [DocParagraph "bar"]] + "* foo\n\n * bar" + `shouldParseTo` DocUnorderedList + [ DocParagraph "foo" + <> DocUnorderedList [DocParagraph "bar"] + ] it "can nest another type of list inside" $ do - "* foo\n\n 1. bar" `shouldParseTo` - DocUnorderedList [ DocParagraph "foo" - <> DocOrderedList [(1, DocParagraph "bar")]] + "* foo\n\n 1. bar" + `shouldParseTo` DocUnorderedList + [ DocParagraph "foo" + <> DocOrderedList [(1, DocParagraph "bar")] + ] it "can nest a code block inside" $ do - "* foo\n\n @foo bar baz@" `shouldParseTo` - DocUnorderedList [ DocParagraph "foo" - <> DocCodeBlock "foo bar baz"] + "* foo\n\n @foo bar baz@" + `shouldParseTo` DocUnorderedList + [ DocParagraph "foo" + <> DocCodeBlock "foo bar baz" + ] - "* foo\n\n @\n foo bar baz\n @" `shouldParseTo` - DocUnorderedList [ DocParagraph "foo" - <> DocCodeBlock "foo bar baz\n"] + "* foo\n\n @\n foo bar baz\n @" + `shouldParseTo` DocUnorderedList + [ DocParagraph "foo" + <> DocCodeBlock "foo bar baz\n" + ] it "can nest more than one level" $ do - "* foo\n\n * bar\n\n * baz\n qux" `shouldParseTo` - DocUnorderedList [ DocParagraph "foo" - <> DocUnorderedList [ DocParagraph "bar" - <> DocUnorderedList [DocParagraph "baz\nqux"] - ] - ] + "* foo\n\n * bar\n\n * baz\n qux" + `shouldParseTo` DocUnorderedList + [ DocParagraph "foo" + <> DocUnorderedList + [ DocParagraph "bar" + <> DocUnorderedList [DocParagraph "baz\nqux"] + ] + ] it "won't fail on not fully indented paragraph" $ do - "* foo\n\n * bar\n\n * qux\nquux" `shouldParseTo` - DocUnorderedList [ DocParagraph "foo" - <> DocUnorderedList [ DocParagraph "bar" ] - , DocParagraph "qux\nquux"] - + "* foo\n\n * bar\n\n * qux\nquux" + `shouldParseTo` DocUnorderedList + [ DocParagraph "foo" + <> DocUnorderedList [DocParagraph "bar"] + , DocParagraph "qux\nquux" + ] it "can nest definition lists" $ do - "[a]: foo\n\n [b]: bar\n\n [c]: baz\n qux" `shouldParseTo` - DocDefList [ ("a", "foo" - <> DocDefList [ ("b", "bar" - <> DocDefList [("c", "baz\nqux")]) - ]) - ] + "[a]: foo\n\n [b]: bar\n\n [c]: baz\n qux" + `shouldParseTo` DocDefList + [ + ( "a" + , "foo" + <> DocDefList + [ + ( "b" + , "bar" + <> DocDefList [("c", "baz\nqux")] + ) + ] + ) + ] it "can come back to top level with a different list" $ do - "* foo\n\n * bar\n\n1. baz" `shouldParseTo` - DocUnorderedList [ DocParagraph "foo" - <> DocUnorderedList [ DocParagraph "bar" ] - ] - <> DocOrderedList [ (1, DocParagraph "baz") ] - - it "allows arbitrary initial indent of a list" $ do - unlines - [ " * foo" - , " * bar" - , "" - , " * quux" - , "" - , " * baz" - ] - `shouldParseTo` - DocUnorderedList - [ DocParagraph "foo" - , DocParagraph "bar" - <> DocUnorderedList [ DocParagraph "quux" ] - , DocParagraph "baz" - ] + "* foo\n\n * bar\n\n1. baz" + `shouldParseTo` DocUnorderedList + [ DocParagraph "foo" + <> DocUnorderedList [DocParagraph "bar"] + ] + <> DocOrderedList [(1, DocParagraph "baz")] + + it "allows arbitrary initial indent of a list" $ + do + unlines + [ " * foo" + , " * bar" + , "" + , " * quux" + , "" + , " * baz" + ] + `shouldParseTo` DocUnorderedList + [ DocParagraph "foo" + , DocParagraph "bar" + <> DocUnorderedList [DocParagraph "quux"] + , DocParagraph "baz" + ] it "definition lists can come back to top level with a different list" $ do - "[foo]: foov\n\n [bar]: barv\n\n1. baz" `shouldParseTo` - DocDefList [ ("foo", "foov" - <> DocDefList [ ("bar", "barv") ]) - ] - <> DocOrderedList [ (1, DocParagraph "baz") ] + "[foo]: foov\n\n [bar]: barv\n\n1. baz" + `shouldParseTo` DocDefList + [ + ( "foo" + , "foov" + <> DocDefList [("bar", "barv")] + ) + ] + <> DocOrderedList [(1, DocParagraph "baz")] it "list order is preserved in presence of nesting + extra text" $ do "1. Foo\n\n > Some code\n\n2. Bar\n\nSome text" - `shouldParseTo` - DocOrderedList [ (1, DocParagraph "Foo" <> DocCodeBlock "Some code") - , (2, DocParagraph "Bar") - ] + `shouldParseTo` DocOrderedList + [ (1, DocParagraph "Foo" <> DocCodeBlock "Some code") + , (2, DocParagraph "Bar") + ] <> DocParagraph (DocString "Some text") "1. Foo\n\n2. Bar\n\nSome text" - `shouldParseTo` - DocOrderedList [ (1, DocParagraph "Foo") - , (2, DocParagraph "Bar") - ] + `shouldParseTo` DocOrderedList + [ (1, DocParagraph "Foo") + , (2, DocParagraph "Bar") + ] <> DocParagraph (DocString "Some text") context "when parsing properties" $ do it "can parse a single property" $ do "prop> 23 == 23" `shouldParseTo` DocProperty "23 == 23" - it "can parse multiple subsequent properties" $ do - unlines [ - "prop> 23 == 23" + it "can parse multiple subsequent properties" $ + do + unlines + [ "prop> 23 == 23" , "prop> 42 == 42" ] - `shouldParseTo` - DocProperty "23 == 23" <> DocProperty "42 == 42" + `shouldParseTo` DocProperty "23 == 23" + <> DocProperty "42 == 42" it "accepts unicode in properties" $ do - "prop> 灼眼のシャナ ≡ 愛" `shouldParseTo` - DocProperty "灼眼のシャナ ≡ 愛" + "prop> 灼眼のシャナ ≡ 愛" + `shouldParseTo` DocProperty "灼眼のシャナ ≡ 愛" it "can deal with whitespace before and after the prop> prompt" $ do - " prop> xs == (reverse $ reverse xs) " `shouldParseTo` - DocProperty "xs == (reverse $ reverse xs)" + " prop> xs == (reverse $ reverse xs) " + `shouldParseTo` DocProperty "xs == (reverse $ reverse xs)" context "when parsing unordered lists" $ do - it "parses a simple list" $ do - unlines [ - " * one" - , " * two" - , " * three" - ] - `shouldParseTo` DocUnorderedList [ - DocParagraph "one" - , DocParagraph "two" - , DocParagraph "three" - ] + it "parses a simple list" $ + do + unlines + [ " * one" + , " * two" + , " * three" + ] + `shouldParseTo` DocUnorderedList + [ DocParagraph "one" + , DocParagraph "two" + , DocParagraph "three" + ] - it "ignores empty lines between list items" $ do - unlines [ - "* one" - , "" - , "* two" - ] - `shouldParseTo` DocUnorderedList [ - DocParagraph "one" - , DocParagraph "two" - ] + it "ignores empty lines between list items" $ + do + unlines + [ "* one" + , "" + , "* two" + ] + `shouldParseTo` DocUnorderedList + [ DocParagraph "one" + , DocParagraph "two" + ] it "accepts an empty list item" $ do "*" `shouldParseTo` DocUnorderedList [DocParagraph DocEmpty] - it "accepts multi-line list items" $ do - unlines [ - "* point one" - , " more one" - , "* point two" - , "more two" - ] - `shouldParseTo` DocUnorderedList [ - DocParagraph "point one\n more one" - , DocParagraph "point two\nmore two" - ] + it "accepts multi-line list items" $ + do + unlines + [ "* point one" + , " more one" + , "* point two" + , "more two" + ] + `shouldParseTo` DocUnorderedList + [ DocParagraph "point one\n more one" + , DocParagraph "point two\nmore two" + ] it "accepts markup in list items" $ do "* /foo/" `shouldParseTo` DocUnorderedList [DocParagraph (DocEmphasis "foo")] - it "requires empty lines between list and other paragraphs" $ do - unlines [ - "foo" - , "" - , "* bar" - , "" - , "baz" - ] - `shouldParseTo` DocParagraph "foo" <> DocUnorderedList [DocParagraph "bar"] <> DocParagraph "baz" + it "requires empty lines between list and other paragraphs" $ + do + unlines + [ "foo" + , "" + , "* bar" + , "" + , "baz" + ] + `shouldParseTo` DocParagraph "foo" + <> DocUnorderedList [DocParagraph "bar"] + <> DocParagraph "baz" context "when parsing ordered lists" $ do - it "parses a simple list" $ do - unlines [ - " 1. one" - , " (1) two" - , " 3. three" - ] - `shouldParseTo` DocOrderedList [ - (1, DocParagraph "one") - , (1, DocParagraph "two") - , (3, DocParagraph "three") - ] + it "parses a simple list" $ + do + unlines + [ " 1. one" + , " (1) two" + , " 3. three" + ] + `shouldParseTo` DocOrderedList + [ (1, DocParagraph "one") + , (1, DocParagraph "two") + , (3, DocParagraph "three") + ] - it "ignores empty lines between list items" $ do - unlines [ - "1. one" - , "" - , "2. two" - ] - `shouldParseTo` DocOrderedList [ - (1, DocParagraph "one") - , (2, DocParagraph "two") - ] + it "ignores empty lines between list items" $ + do + unlines + [ "1. one" + , "" + , "2. two" + ] + `shouldParseTo` DocOrderedList + [ (1, DocParagraph "one") + , (2, DocParagraph "two") + ] it "accepts an empty list item" $ do "1." `shouldParseTo` DocOrderedList [(1, DocParagraph DocEmpty)] - it "accepts multi-line list items" $ do - unlines [ - "1. point one" - , " more one" - , "1. point two" - , "more two" - ] - `shouldParseTo` DocOrderedList [ - (1, DocParagraph "point one\n more one") - , (1, DocParagraph "point two\nmore two") - ] + it "accepts multi-line list items" $ + do + unlines + [ "1. point one" + , " more one" + , "1. point two" + , "more two" + ] + `shouldParseTo` DocOrderedList + [ (1, DocParagraph "point one\n more one") + , (1, DocParagraph "point two\nmore two") + ] it "accepts markup in list items" $ do "1. /foo/" `shouldParseTo` DocOrderedList [(1, DocParagraph (DocEmphasis "foo"))] - it "requires empty lines between list and other paragraphs" $ do - unlines [ - "foo" - , "" - , "1. bar" - , "" - , "baz" - ] - `shouldParseTo` DocParagraph "foo" <> DocOrderedList [(1, DocParagraph "bar")] <> DocParagraph "baz" + it "requires empty lines between list and other paragraphs" $ + do + unlines + [ "foo" + , "" + , "1. bar" + , "" + , "baz" + ] + `shouldParseTo` DocParagraph "foo" + <> DocOrderedList [(1, DocParagraph "bar")] + <> DocParagraph "baz" context "when parsing definition lists" $ do - it "parses a simple list" $ do - unlines [ - " [foo]: one" - , " [bar]: two" - , " [baz]: three" - ] - `shouldParseTo` DocDefList [ - ("foo", "one") - , ("bar", "two") - , ("baz", "three") - ] + it "parses a simple list" $ + do + unlines + [ " [foo]: one" + , " [bar]: two" + , " [baz]: three" + ] + `shouldParseTo` DocDefList + [ ("foo", "one") + , ("bar", "two") + , ("baz", "three") + ] - it "ignores empty lines between list items" $ do - unlines [ - "[foo]: one" - , "" - , "[bar]: two" - ] - `shouldParseTo` DocDefList [ - ("foo", "one") - , ("bar", "two") - ] + it "ignores empty lines between list items" $ + do + unlines + [ "[foo]: one" + , "" + , "[bar]: two" + ] + `shouldParseTo` DocDefList + [ ("foo", "one") + , ("bar", "two") + ] it "accepts an empty list item" $ do "[foo]:" `shouldParseTo` DocDefList [("foo", DocEmpty)] - it "accepts multi-line list items" $ do - unlines [ - "[foo]: point one" - , " more one" - , "[bar]: point two" - , "more two" - ] - `shouldParseTo` DocDefList [ - ("foo", "point one\n more one") - , ("bar", "point two\nmore two") - ] + it "accepts multi-line list items" $ + do + unlines + [ "[foo]: point one" + , " more one" + , "[bar]: point two" + , "more two" + ] + `shouldParseTo` DocDefList + [ ("foo", "point one\n more one") + , ("bar", "point two\nmore two") + ] it "accepts markup in list items" $ do "[foo]: /foo/" `shouldParseTo` DocDefList [("foo", DocEmphasis "foo")] @@ -1080,65 +1191,74 @@ spec = do it "accepts markup for the label" $ do "[/foo/]: bar" `shouldParseTo` DocDefList [(DocEmphasis "foo", "bar")] - it "requires empty lines between list and other paragraphs" $ do - unlines [ - "foo" - , "" - , "[foo]: bar" - , "" - , "baz" - ] - `shouldParseTo` DocParagraph "foo" <> DocDefList [("foo", "bar")] <> DocParagraph "baz" - - it "dose not require the colon (deprecated - this will be removed in a future release)" $ do - unlines [ - " [foo] one" - , " [bar] two" - , " [baz] three" - ] - `shouldParseTo` DocDefList [ - ("foo", "one") - , ("bar", "two") - , ("baz", "three") - ] + it "requires empty lines between list and other paragraphs" $ + do + unlines + [ "foo" + , "" + , "[foo]: bar" + , "" + , "baz" + ] + `shouldParseTo` DocParagraph "foo" + <> DocDefList [("foo", "bar")] + <> DocParagraph "baz" + + it "dose not require the colon (deprecated - this will be removed in a future release)" $ + do + unlines + [ " [foo] one" + , " [bar] two" + , " [baz] three" + ] + `shouldParseTo` DocDefList + [ ("foo", "one") + , ("bar", "two") + , ("baz", "three") + ] context "when parsing consecutive paragraphs" $ do it "will not capture irrelevant consecutive lists" $ do - unlines [ " * bullet" - , "" - , "" - , " - different bullet" - , "" - , "" - , " (1) ordered" - , " " - , " 2. different bullet" - , " " - , " [cat]: kitten" - , " " - , " [pineapple]: fruit" - ] `shouldParseTo` - DocUnorderedList [ DocParagraph "bullet" - , DocParagraph "different bullet"] - <> DocOrderedList [ (1, DocParagraph "ordered") - , (2, DocParagraph "different bullet") - ] - <> DocDefList [ ("cat", "kitten") - , ("pineapple", "fruit") - ] + unlines + [ " * bullet" + , "" + , "" + , " - different bullet" + , "" + , "" + , " (1) ordered" + , " " + , " 2. different bullet" + , " " + , " [cat]: kitten" + , " " + , " [pineapple]: fruit" + ] + `shouldParseTo` DocUnorderedList + [ DocParagraph "bullet" + , DocParagraph "different bullet" + ] + <> DocOrderedList + [ (1, DocParagraph "ordered") + , (2, DocParagraph "different bullet") + ] + <> DocDefList + [ ("cat", "kitten") + , ("pineapple", "fruit") + ] context "when parsing function documentation headers" $ do it "can parse a simple header" $ do - "= Header 1\nHello." `shouldParseTo` - (DocHeader (Header 1 "Header 1")) + "= Header 1\nHello." + `shouldParseTo` (DocHeader (Header 1 "Header 1")) <> DocParagraph "Hello." it "allow consecutive headers" $ do - "= Header 1\n== Header 2" `shouldParseTo` - DocHeader (Header 1 "Header 1") + "= Header 1\n== Header 2" + `shouldParseTo` DocHeader (Header 1 "Header 1") <> DocHeader (Header 2 "Header 2") it "accepts markup in the header" $ do - "= /Header/ __1__\nFoo" `shouldParseTo` - DocHeader (Header 1 (DocEmphasis "Header" <> " " <> DocBold "1")) + "= /Header/ __1__\nFoo" + `shouldParseTo` DocHeader (Header 1 (DocEmphasis "Header" <> " " <> DocBold "1")) <> DocParagraph "Foo" diff --git a/haddock-test/src/Test/Haddock.hs b/haddock-test/src/Test/Haddock.hs index fe547ad528..82e8ef2039 100644 --- a/haddock-test/src/Test/Haddock.hs +++ b/haddock-test/src/Test/Haddock.hs @@ -1,125 +1,125 @@ {-# LANGUAGE RecordWildCards #-} - module Test.Haddock - ( module Test.Haddock.Config - , runAndCheck, runHaddock, checkFiles - ) where - + ( module Test.Haddock.Config + , runAndCheck + , runHaddock + , checkFiles + ) where import Control.Monad import Data.Maybe +import qualified Data.ByteString.Char8 as BS import System.Directory import System.Exit import System.FilePath import System.IO import System.Process -import qualified Data.ByteString.Char8 as BS import Test.Haddock.Config import Test.Haddock.Process import Test.Haddock.Utils - data CheckResult - = Fail - | Pass - | NoRef - | Error String - | Accepted - deriving Eq - + = Fail + | Pass + | NoRef + | Error String + | Accepted + deriving (Eq) runAndCheck :: Config c -> IO () runAndCheck cfg = do - crashed <- runHaddock cfg - checkFiles cfg crashed - + crashed <- runHaddock cfg + checkFiles cfg crashed checkFiles :: Config c -> Bool -> IO () -checkFiles cfg@(Config { .. }) somethingCrashed = do - putStrLn "Testing output files..." - - createDirectoryIfMissing True (cfgOutDir cfg) - files <- ignore <$> getDirectoryTree (cfgOutDir cfg) - failed <- liftM catMaybes . forM files $ \file -> do - putStr $ "Checking \"" ++ file ++ "\"... " - - status <- maybeAcceptFile cfg file =<< checkFile cfg file - case status of - Fail -> putStrLn "FAIL" >> (return $ Just file) - Pass -> putStrLn "PASS" >> (return Nothing) - NoRef -> putStrLn "PASS [no .ref]" >> (return Nothing) - Error msg -> putStrLn ("ERROR (" ++ msg ++ ")") >> return Nothing - Accepted -> putStrLn "ACCEPTED" >> return Nothing - - if (null failed && not somethingCrashed) - then do - putStrLn "All tests passed!" - exitSuccess - else do - unless (null failed) $ maybeDiff cfg failed - when somethingCrashed $ putStrLn "Some tests crashed." - exitFailure +checkFiles cfg@(Config{..}) somethingCrashed = do + putStrLn "Testing output files..." + + createDirectoryIfMissing True (cfgOutDir cfg) + files <- ignore <$> getDirectoryTree (cfgOutDir cfg) + failed <- liftM catMaybes . forM files $ \file -> do + putStr $ "Checking \"" ++ file ++ "\"... " + + status <- maybeAcceptFile cfg file =<< checkFile cfg file + case status of + Fail -> putStrLn "FAIL" >> (return $ Just file) + Pass -> putStrLn "PASS" >> (return Nothing) + NoRef -> putStrLn "PASS [no .ref]" >> (return Nothing) + Error msg -> putStrLn ("ERROR (" ++ msg ++ ")") >> return Nothing + Accepted -> putStrLn "ACCEPTED" >> return Nothing + + if (null failed && not somethingCrashed) + then do + putStrLn "All tests passed!" + exitSuccess + else do + unless (null failed) $ maybeDiff cfg failed + when somethingCrashed $ putStrLn "Some tests crashed." + exitFailure where ignore = filter (not . dcfgCheckIgnore cfgDirConfig) - maybeDiff :: Config c -> [FilePath] -> IO () -maybeDiff (Config { cfgDiffTool = Nothing }) _ = pure () -maybeDiff cfg@(Config { cfgDiffTool = (Just diff) }) files = do - putStrLn "Diffing failed cases..." - forM_ files $ diffFile cfg diff - +maybeDiff (Config{cfgDiffTool = Nothing}) _ = pure () +maybeDiff cfg@(Config{cfgDiffTool = (Just diff)}) files = do + putStrLn "Diffing failed cases..." + forM_ files $ diffFile cfg diff -- | Runs Haddock on all of the test packages, and returns whether 'True' if -- any of them caused Haddock to crash. runHaddock :: Config c -> IO Bool -runHaddock cfg@(Config { .. }) = do - createEmptyDirectory $ cfgOutDir cfg - - putStrLn "Generating documentation..." - successes <- forM cfgPackages $ \tpkg -> do - haddockStdOut <- openFile cfgHaddockStdOut WriteMode - let pc = processConfig - { pcArgs = concat - [ cfgHaddockArgs - , pure $ "--odir=" ++ outDir cfgDirConfig tpkg - , tpkgFiles tpkg - ] - , pcEnv = Just cfgEnv - , pcStdOut = Just haddockStdOut - , pcStdErr = Just haddockStdOut - } - - let msg = "Failed to run Haddock on test package '" ++ tpkgName tpkg ++ "'" - succeeded <- waitForSuccess msg stdout =<< runProcess' cfgHaddockPath pc - unless succeeded $ removeDirectoryRecursive (outDir cfgDirConfig tpkg) - - pure succeeded - - let somethingFailed = any not successes - when somethingFailed $ - putStrLn ("Haddock output is at '" ++ cfgHaddockStdOut ++ "'. " ++ - "This file can be set with `--haddock-stdout`.") - pure somethingFailed - +runHaddock cfg@(Config{..}) = do + createEmptyDirectory $ cfgOutDir cfg + + putStrLn "Generating documentation..." + successes <- forM cfgPackages $ \tpkg -> do + haddockStdOut <- openFile cfgHaddockStdOut WriteMode + let pc = + processConfig + { pcArgs = + concat + [ cfgHaddockArgs + , pure $ "--odir=" ++ outDir cfgDirConfig tpkg + , tpkgFiles tpkg + ] + , pcEnv = Just cfgEnv + , pcStdOut = Just haddockStdOut + , pcStdErr = Just haddockStdOut + } + + let msg = "Failed to run Haddock on test package '" ++ tpkgName tpkg ++ "'" + succeeded <- waitForSuccess msg stdout =<< runProcess' cfgHaddockPath pc + unless succeeded $ removeDirectoryRecursive (outDir cfgDirConfig tpkg) + + pure succeeded + + let somethingFailed = any not successes + when somethingFailed $ + putStrLn + ( "Haddock output is at '" + ++ cfgHaddockStdOut + ++ "'. " + ++ "This file can be set with `--haddock-stdout`." + ) + pure somethingFailed checkFile :: Config c -> FilePath -> IO CheckResult checkFile cfg file = do - hasRef <- doesFileExist $ refFile dcfg file - if hasRef - then do - mout <- readOut cfg file - mref <- readRef cfg file - return $ case (mout, mref) of - (Just out, Just ref) - | ccfgEqual ccfg out ref -> Pass - | otherwise -> Fail - _ -> Error "Failed to parse input files" - else return NoRef + hasRef <- doesFileExist $ refFile dcfg file + if hasRef + then do + mout <- readOut cfg file + mref <- readRef cfg file + return $ case (mout, mref) of + (Just out, Just ref) + | ccfgEqual ccfg out ref -> Pass + | otherwise -> Fail + _ -> Error "Failed to parse input files" + else return NoRef where ccfg = cfgCheckConfig cfg dcfg = cfgDirConfig cfg @@ -132,7 +132,7 @@ checkFile cfg file = do -- | Read the reference artifact for a test readRef :: Config c -> FilePath -> IO (Maybe c) readRef cfg file = - ccfgRead ccfg . BS.unpack + ccfgRead ccfg . BS.unpack <$> BS.readFile (refFile dcfg file) where ccfg = cfgCheckConfig cfg @@ -141,55 +141,52 @@ readRef cfg file = -- | Read (and clean) the test output artifact for a test readOut :: Config c -> FilePath -> IO (Maybe c) readOut cfg file = - fmap (ccfgClean ccfg file) . ccfgRead ccfg . BS.unpack + fmap (ccfgClean ccfg file) . ccfgRead ccfg . BS.unpack <$> BS.readFile (outFile dcfg file) where ccfg = cfgCheckConfig cfg dcfg = cfgDirConfig cfg - diffFile :: Config c -> FilePath -> FilePath -> IO () diffFile cfg diff file = do - Just out <- readOut cfg file - Just ref <- readRef cfg file - writeFile outFile' $ ccfgDump ccfg out - writeFile refFile' $ ccfgDump ccfg ref - - putStrLn $ "Diff for file \"" ++ file ++ "\":" - hFlush stdout - handle <- runProcess' diff $ processConfig + Just out <- readOut cfg file + Just ref <- readRef cfg file + writeFile outFile' $ ccfgDump ccfg out + writeFile refFile' $ ccfgDump ccfg ref + + putStrLn $ "Diff for file \"" ++ file ++ "\":" + hFlush stdout + handle <- + runProcess' diff $ + processConfig { pcArgs = [outFile', refFile'] , pcStdOut = Just stdout } - waitForProcess handle >> return () + waitForProcess handle >> return () where dcfg = cfgDirConfig cfg ccfg = cfgCheckConfig cfg outFile' = outFile dcfg file <.> "dump" refFile' = outFile dcfg file <.> "ref" <.> "dump" - maybeAcceptFile :: Config c -> FilePath -> CheckResult -> IO CheckResult maybeAcceptFile cfg file result - | cfgAccept cfg && result `elem` [NoRef, Fail] = do - Just out <- readOut cfg file - let ref = refFile dcfg file - createDirectoryIfMissing True (takeDirectory ref) - writeFile ref $ ccfgDump ccfg out - pure Accepted + | cfgAccept cfg && result `elem` [NoRef, Fail] = do + Just out <- readOut cfg file + let ref = refFile dcfg file + createDirectoryIfMissing True (takeDirectory ref) + writeFile ref $ ccfgDump ccfg out + pure Accepted where dcfg = cfgDirConfig cfg ccfg = cfgCheckConfig cfg maybeAcceptFile _ _ result = pure result - outDir :: DirConfig -> TestPackage -> FilePath outDir dcfg tpkg = dcfgOutDir dcfg tpkgName tpkg - outFile :: DirConfig -> FilePath -> FilePath outFile dcfg file = dcfgOutDir dcfg file - refFile :: DirConfig -> FilePath -> FilePath refFile dcfg file = dcfgRefDir dcfg file diff --git a/haddock-test/src/Test/Haddock/Process.hs b/haddock-test/src/Test/Haddock/Process.hs index a6cab9ac45..a9b0c99e14 100644 --- a/haddock-test/src/Test/Haddock/Process.hs +++ b/haddock-test/src/Test/Haddock/Process.hs @@ -1,32 +1,28 @@ {-# LANGUAGE RecordWildCards #-} - module Test.Haddock.Process where - import Control.Monad import System.Exit import System.IO import System.Process - type Environment = [(String, String)] - data ProcessConfig = ProcessConfig - { pcArgs :: [String] - , pcWorkDir :: Maybe FilePath - , pcEnv :: Maybe Environment - , pcStdIn :: Maybe Handle - , pcStdOut :: Maybe Handle - , pcStdErr :: Maybe Handle - } - deriving (Show) - + { pcArgs :: [String] + , pcWorkDir :: Maybe FilePath + , pcEnv :: Maybe Environment + , pcStdIn :: Maybe Handle + , pcStdOut :: Maybe Handle + , pcStdErr :: Maybe Handle + } + deriving (Show) processConfig :: ProcessConfig -processConfig = ProcessConfig +processConfig = + ProcessConfig { pcArgs = [] , pcWorkDir = Nothing , pcEnv = Nothing @@ -35,15 +31,21 @@ processConfig = ProcessConfig , pcStdErr = Nothing } - runProcess' :: FilePath -> ProcessConfig -> IO ProcessHandle -runProcess' path (ProcessConfig { .. }) = runProcess - path pcArgs pcWorkDir pcEnv pcStdIn pcStdOut pcStdErr +runProcess' path (ProcessConfig{..}) = + runProcess + path + pcArgs + pcWorkDir + pcEnv + pcStdIn + pcStdOut + pcStdErr -- | Wait for a process to finish running. If it ends up failing, print out the -- error message. waitForSuccess :: String -> Handle -> ProcessHandle -> IO Bool waitForSuccess msg out handle = do - succeeded <- fmap (== ExitSuccess) $ waitForProcess handle - unless succeeded $ hPutStrLn out msg - pure succeeded + succeeded <- fmap (== ExitSuccess) $ waitForProcess handle + unless succeeded $ hPutStrLn out msg + pure succeeded diff --git a/haddock-test/src/Test/Haddock/Utils.hs b/haddock-test/src/Test/Haddock/Utils.hs index 58408aaf16..44a5589287 100644 --- a/haddock-test/src/Test/Haddock/Utils.hs +++ b/haddock-test/src/Test/Haddock/Utils.hs @@ -1,6 +1,5 @@ module Test.Haddock.Utils where - import Control.Monad import Data.Maybe @@ -8,50 +7,43 @@ import Data.Maybe import System.Directory import System.FilePath - mlast :: [a] -> Maybe a mlast = listToMaybe . reverse - partitionM :: Monad m => (a -> m Bool) -> [a] -> m ([a], [a]) partitionM _ [] = pure ([], []) -partitionM p (x:xs) = do - (ss, fs) <- partitionM p xs - b <- p x - pure $ if b then (x:ss, fs) else (ss, x:fs) - +partitionM p (x : xs) = do + (ss, fs) <- partitionM p xs + b <- p x + pure $ if b then (x : ss, fs) else (ss, x : fs) whenM :: Monad m => m Bool -> m () -> m () whenM mb action = mb >>= \b -> when b action - getDirectoryTree :: FilePath -> IO [FilePath] getDirectoryTree path = do - (dirs, files) <- partitionM isDirectory =<< contents - subfiles <- fmap concat . forM dirs $ \dir -> - map (dir ) <$> getDirectoryTree (path dir) - pure $ files ++ subfiles + (dirs, files) <- partitionM isDirectory =<< contents + subfiles <- fmap concat . forM dirs $ \dir -> + map (dir ) <$> getDirectoryTree (path dir) + pure $ files ++ subfiles where contents = filter realEntry <$> getDirectoryContents path isDirectory entry = doesDirectoryExist $ path entry realEntry entry = not $ entry == "." || entry == ".." - createEmptyDirectory :: FilePath -> IO () createEmptyDirectory path = do - whenM (doesDirectoryExist path) $ removeDirectoryRecursive path - createDirectory path - + whenM (doesDirectoryExist path) $ removeDirectoryRecursive path + createDirectory path -- | Just like 'copyFile' but output directory path is not required to exist. copyFile' :: FilePath -> FilePath -> IO () copyFile' old new = do - createDirectoryIfMissing True $ takeDirectory new - copyFile old new - + createDirectoryIfMissing True $ takeDirectory new + copyFile old new crlfToLf :: String -> String crlfToLf "" = "" crlfToLf ('\r' : '\n' : rest) = '\n' : crlfToLf rest -crlfToLf ('\r' : rest) = '\n' : crlfToLf rest +crlfToLf ('\r' : rest) = '\n' : crlfToLf rest crlfToLf (other : rest) = other : crlfToLf rest diff --git a/haddock-test/src/Test/Haddock/Xhtml.hs b/haddock-test/src/Test/Haddock/Xhtml.hs index 74d8c4f77f..8e2462eebb 100644 --- a/haddock-test/src/Test/Haddock/Xhtml.hs +++ b/haddock-test/src/Test/Haddock/Xhtml.hs @@ -1,8 +1,13 @@ module Test.Haddock.Xhtml - ( Xml - , parseXml, dumpXml - , stripLinks, stripLinksWhen, stripAnchorsWhen, stripIdsWhen, stripFooter - ) where + ( Xml + , parseXml + , dumpXml + , stripLinks + , stripLinksWhen + , stripAnchorsWhen + , stripIdsWhen + , stripFooter + ) where {- This module used to actually parse the HTML (using the `xml` parsing library) @@ -16,22 +21,22 @@ and since the `xhtml` library already handles the pretty-printing aspect, this would appear to be a reasonable compromise for now. -} -import Data.List ( stripPrefix, isPrefixOf ) -import Data.Char ( isSpace ) +import Data.Char (isSpace) +import Data.List (isPrefixOf, stripPrefix) -- | Simple wrapper around the pretty-printed HTML source -newtype Xml = Xml { unXml :: String } +newtype Xml = Xml {unXml :: String} -- | Part of parsing involves dropping the @DOCTYPE@ line -- and windows newline endings parseXml :: String -> Maybe Xml parseXml = Just . Xml . filter (/= '\r') . dropDocTypeLine where - dropDocTypeLine bs - | " String dumpXml = unXml @@ -44,27 +49,30 @@ type Value = String -- * match an attribute key -- * check something about the value -- * if the check succeeded, replace the value with a dummy value --- stripAttrValueWhen - :: Attr -- ^ attribute key - -> Value -- ^ dummy attribute value - -> (Value -> Bool) -- ^ determine whether we should modify the attribute - -> Xml -- ^ input XML - -> Xml -- ^ output XML + :: Attr + -- ^ attribute key + -> Value + -- ^ dummy attribute value + -> (Value -> Bool) + -- ^ determine whether we should modify the attribute + -> Xml + -- ^ input XML + -> Xml + -- ^ output XML stripAttrValueWhen key fallback p (Xml body) = Xml (filterAttrs body) where - keyEq = key ++ "=\"" + keyEq = key ++ "=\"" - filterAttrs "" = "" - filterAttrs b@(c:cs) + filterAttrs "" = "" + filterAttrs b@(c : cs) | Just valRest <- stripPrefix keyEq b - , Just (val,rest) <- spanToEndOfString valRest - = if p val - then keyEq ++ fallback ++ "\"" ++ filterAttrs rest - else keyEq ++ val ++ "\"" ++ filterAttrs rest - - | otherwise - = c : filterAttrs cs + , Just (val, rest) <- spanToEndOfString valRest = + if p val + then keyEq ++ fallback ++ "\"" ++ filterAttrs rest + else keyEq ++ val ++ "\"" ++ filterAttrs rest + | otherwise = + c : filterAttrs cs -- | Spans to the next (unescaped) @\"@ character. -- @@ -74,20 +82,18 @@ stripAttrValueWhen key fallback p (Xml body) = Xml (filterAttrs body) -- Just ("foo", " bar \"baz\"") -- >>> spanToEndOfString "foo\\\" bar \"baz\"" -- Just ("foo\\\" bar ", "baz\"") --- spanToEndOfString :: String -> Maybe (String, String) -spanToEndOfString ('"':rest) = Just ("", rest) -spanToEndOfString ('\\':c:rest) - | Just (str, rest') <- spanToEndOfString rest - = Just ('\\':c:str, rest') -spanToEndOfString (c:rest) - | Just (str, rest') <- spanToEndOfString rest - = Just (c:str, rest') +spanToEndOfString ('"' : rest) = Just ("", rest) +spanToEndOfString ('\\' : c : rest) + | Just (str, rest') <- spanToEndOfString rest = + Just ('\\' : c : str, rest') +spanToEndOfString (c : rest) + | Just (str, rest') <- spanToEndOfString rest = + Just (c : str, rest') spanToEndOfString _ = Nothing - -- | Replace hyperlink targets with @\"#\"@ if they match a predicate -stripLinksWhen :: (Value -> Bool) -> Xml -> Xml +stripLinksWhen :: (Value -> Bool) -> Xml -> Xml stripLinksWhen = stripAttrValueWhen "href" "#" -- | Replace all hyperlink targets with @\"#\"@ @@ -95,7 +101,7 @@ stripLinks :: Xml -> Xml stripLinks = stripLinksWhen (const True) -- | Replace id's with @\"\"@ if they match a predicate -stripIdsWhen :: (Value -> Bool) -> Xml -> Xml +stripIdsWhen :: (Value -> Bool) -> Xml -> Xml stripIdsWhen = stripAttrValueWhen "id" "" -- | Replace names's with @\"\"@ if they match a predicate @@ -106,22 +112,19 @@ stripAnchorsWhen = stripAttrValueWhen "name" "" stripFooter :: Xml -> Xml stripFooter (Xml body) = Xml (findDiv body) where - findDiv "" = "" - findDiv b@(c:cs) + findDiv "" = "" + findDiv b@(c : cs) | Just divRest <- stripPrefix "

    " valRest' - = Just valRest'' - - | otherwise - = dropToDiv cs - + , Just valRest'' <- stripPrefix ">" valRest' = + Just valRest'' + | otherwise = + dropToDiv cs