aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Theriault <alec.theriault@gmail.com>2018-01-13 03:12:37 -0800
committerAlexander Biehl <alexbiehl@gmail.com>2018-01-13 12:12:37 +0100
commitaa33be50e6292875b6afea8f97980c3a6e76ed87 (patch)
tree8ef2dc71b1f65ed3fedd435f56e1ac7d520e3460
parent24841386cff6fdccc11accf9daa815c2c7444d65 (diff)
Constructor and pattern synonym argument docs (#709)
* Support Haddocks on constructor arguments This is in conjunction with https://phabricator.haskell.org/D4094. Adds support for rendering Haddock's on (non-record) constructor arguments, both for regular and GADT constructors. * Support haddocks on pattern synonym arguments It appears that GHC already parsed these - we just weren't using them. In the process of doing this, I tried to deduplicate some code around handling patterns. * Update the markup guide Add some information about the new support for commenting constructor arguments, and mention pattern synonyms and GADT-style constructors. * Overhaul LaTeX support for data/pattern decls This includes at least * fixing several bugs that resulted in invalid LaTeX * fixing GADT data declaration headers * overhaul handling of record fields * overhaul handling of GADT constructors * overhaul handling of bundled patterns * add support for constructor argument docs * Support GADT record constructors This means changes what existing HTML docs look like. As for LaTeX, looks like GADT records were never even supported. Now they are. * Clean up code/comments Made code/comments consistent between the LaTeX and XHTML backend when possible. * Update changelog * Patch post-rebase regressions * Another post-rebase change We want return values to be documentable on record GADT constructors.
-rw-r--r--CHANGES.md3
-rw-r--r--doc/markup.rst14
-rw-r--r--haddock-api/src/Haddock/Backends/LaTeX.hs483
-rw-r--r--haddock-api/src/Haddock/Backends/Xhtml/Decl.hs401
-rw-r--r--haddock-api/src/Haddock/Backends/Xhtml/Utils.hs4
-rw-r--r--haddock-api/src/Haddock/Interface/Create.hs43
6 files changed, 595 insertions, 353 deletions
diff --git a/CHANGES.md b/CHANGES.md
index f4602e85..9ba8be07 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -22,6 +22,9 @@
* Overhaul Haddock's rendering of kind signatures so that invisible kind
parameters are not printed (#681) (Fixes #544)
+ * Overhaul handling of data declarations in XHTML and LaTeX. Adds support for
+ documenting individual arguments of constructors/patterns (#709)
+
## Changes in version 2.18.1
* Synopsis is working again (#599)
diff --git a/doc/markup.rst b/doc/markup.rst
index d0b9392d..4d56cc83 100644
--- a/doc/markup.rst
+++ b/doc/markup.rst
@@ -39,6 +39,8 @@ the following:
- A ``data`` declaration,
+- A ``pattern`` declaration,
+
- A ``newtype`` declaration,
- A ``type`` declaration
@@ -118,6 +120,15 @@ Constructors are documented like so: ::
or like this: ::
data T a b
+ = C1 -- ^ This is the documentation for the 'C1' constructor
+ a -- ^ This is the documentation for the argument of type 'a'
+ b -- ^ This is the documentation for the argument of type 'b'
+
+There is one edge case that is handled differently: only one ``-- ^``
+annotation occuring after the constructor and all its arguments is
+applied to the constructor, not its last argument: ::
+
+ data T a b
= C1 a b -- ^ This is the documentation for the 'C1' constructor
| C2 a b -- ^ This is the documentation for the 'C2' constructor
@@ -164,6 +175,9 @@ Individual arguments to a function may be documented like this: ::
-> Float -- ^ The 'Float' argument
-> IO () -- ^ The return value
+Pattern synonyms and GADT-style data constructors also support this
+style of documentation.
+
.. _module-description:
The Module Description
diff --git a/haddock-api/src/Haddock/Backends/LaTeX.hs b/haddock-api/src/Haddock/Backends/LaTeX.hs
index 793e40d8..51e183c7 100644
--- a/haddock-api/src/Haddock/Backends/LaTeX.hs
+++ b/haddock-api/src/Haddock/Backends/LaTeX.hs
@@ -179,13 +179,14 @@ string_txt (PStr s1) s2 = unpackFS s1 ++ s2
string_txt (ZStr s1) s2 = zString s1 ++ s2
string_txt (LStr s1 _) s2 = unpackLitString s1 ++ s2
-
+-- | Prints out an entry in a module export list.
exportListItem :: ExportItem DocNameI -> LaTeX
exportListItem ExportDecl { expItemDecl = decl, expItemSubDocs = subdocs }
- = sep (punctuate comma . map ppDocBinder $ declNames decl) <>
- case subdocs of
- [] -> empty
- _ -> parens (sep (punctuate comma (map (ppDocBinder . fst) subdocs)))
+ = let (leader, names) = declNames decl
+ in sep (punctuate comma [ leader <+> ppDocBinder name | name <- names ]) <>
+ case subdocs of
+ [] -> empty
+ _ -> parens (sep (punctuate comma (map (ppDocBinder . fst) subdocs)))
exportListItem (ExportNoDecl y [])
= ppDocBinder y
exportListItem (ExportNoDecl y subs)
@@ -249,13 +250,17 @@ ppDocGroup lev doc = sec lev <> braces doc
sec _ = text "\\paragraph"
-declNames :: LHsDecl DocNameI -> [DocName]
+-- | 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 (L _ decl) = case decl of
- TyClD d -> [tcdName d]
- SigD (TypeSig lnames _ ) -> map unLoc lnames
- SigD (PatSynSig lnames _) -> map unLoc lnames
- ForD (ForeignImport (L _ n) _ _ _) -> [n]
- ForD (ForeignExport (L _ n) _ _ _) -> [n]
+ TyClD d -> (empty, [tcdName 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"
@@ -278,47 +283,44 @@ moduleBasename mdl = map (\c -> if c == '.' then '-' else c)
-- * Decls
-------------------------------------------------------------------------------
-
-ppDecl :: LHsDecl DocNameI
- -> [(HsDecl DocNameI, DocForDecl DocName)]
- -> DocForDecl DocName
- -> [DocInstance DocNameI]
- -> [(DocName, DocForDecl DocName)]
- -> [(DocName, Fixity)]
+-- | 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 (L loc decl) pats (doc, fnArgsDoc) instances subdocs _fixities = case decl of
- TyClD d@(FamDecl {}) -> ppTyFam False loc doc d unicode
- TyClD d@(DataDecl {})
- -> ppDataDecl pats instances subdocs loc (Just doc) d unicode
- TyClD d@(SynDecl {}) -> ppTySyn loc (doc, fnArgsDoc) d unicode
+ppDecl decl pats (doc, fnArgsDoc) instances subdocs _fxts = case unLoc decl of
+ TyClD d@FamDecl {} -> ppTyFam False doc d unicode
+ TyClD d@DataDecl {} -> ppDataDecl pats instances subdocs (Just doc) d unicode
+ TyClD d@SynDecl {} -> ppTySyn (doc, fnArgsDoc) d unicode
-- Family instances happen via FamInst now
--- TyClD d@(TySynonym {})
+-- TyClD d@TySynonym{}
-- | Just _ <- tcdTyPats d -> ppTyInst False loc doc d unicode
-- Family instances happen via FamInst now
- TyClD d@(ClassDecl {}) -> ppClassDecl instances loc doc subdocs d unicode
- SigD (TypeSig lnames t) -> ppFunSig loc (doc, fnArgsDoc) (map unLoc lnames)
- (hsSigWcType t) unicode
- SigD (PatSynSig lnames ty) ->
- ppLPatSig loc (doc, fnArgsDoc) (map unLoc lnames) ty unicode
- ForD d -> ppFor loc (doc, fnArgsDoc) d unicode
- InstD _ -> empty
- DerivD _ -> empty
- _ -> error "declaration not supported by ppDecl"
+ TyClD d@ClassDecl{} -> ppClassDecl instances doc subdocs d unicode
+ SigD (TypeSig lnames ty) -> ppFunSig (doc, fnArgsDoc) (map unLoc lnames) (hsSigWcType 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"
where
unicode = False
-ppTyFam :: Bool -> SrcSpan -> Documentation DocName ->
+ppTyFam :: Bool -> Documentation DocName ->
TyClDecl DocNameI -> Bool -> LaTeX
-ppTyFam _ _ _ _ _ =
+ppTyFam _ _ _ _ =
error "type family declarations are currently not supported by --latex"
-ppFor :: SrcSpan -> DocForDecl DocName -> ForeignDecl DocNameI -> Bool -> LaTeX
-ppFor loc doc (ForeignImport (L _ name) typ _ _) unicode =
- ppFunSig loc doc [name] (hsSigType typ) unicode
-ppFor _ _ _ _ = error "ppFor error in Haddock.Backends.LaTeX"
+ppFor :: DocForDecl DocName -> ForeignDecl DocNameI -> Bool -> LaTeX
+ppFor doc (ForeignImport (L _ name) typ _ _) unicode =
+ ppFunSig doc [name] (hsSigType typ) unicode
+ppFor _ _ _ = error "ppFor error in Haddock.Backends.LaTeX"
-- error "foreign declarations are currently not supported by --latex"
@@ -328,18 +330,18 @@ ppFor _ _ _ _ = error "ppFor error in Haddock.Backends.LaTeX"
-- we skip type patterns for now
-ppTySyn :: SrcSpan -> DocForDecl DocName -> TyClDecl DocNameI -> Bool -> LaTeX
+ppTySyn :: DocForDecl DocName -> TyClDecl DocNameI -> Bool -> LaTeX
-ppTySyn loc doc (SynDecl { tcdLName = L _ name, tcdTyVars = ltyvars
+ppTySyn doc (SynDecl { tcdLName = L _ name, tcdTyVars = ltyvars
, tcdRhs = ltype }) unicode
- = ppTypeOrFunSig loc [name] (unLoc ltype) doc (full, hdr, char '=') unicode
+ = ppTypeOrFunSig (unLoc 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"
+ppTySyn _ _ _ = error "declaration not supported by ppTySyn"
-------------------------------------------------------------------------------
@@ -347,61 +349,98 @@ ppTySyn _ _ _ _ = error "declaration not supported by ppTySyn"
-------------------------------------------------------------------------------
-ppFunSig :: SrcSpan -> DocForDecl DocName -> [DocName] -> LHsType DocNameI
+ppFunSig :: DocForDecl DocName -> [DocName] -> LHsType DocNameI
-> Bool -> LaTeX
-ppFunSig loc doc docnames (L _ typ) unicode =
- ppTypeOrFunSig loc docnames typ doc
+ppFunSig doc docnames (L _ typ) unicode =
+ ppTypeOrFunSig typ doc
( ppTypeSig names typ False
, hsep . punctuate comma $ map ppSymName names
- , dcolon unicode)
+ , dcolon unicode
+ )
unicode
where
names = map getName docnames
-ppLPatSig :: SrcSpan -> DocForDecl DocName -> [DocName]
- -> LHsSigType DocNameI
- -> Bool -> LaTeX
-ppLPatSig _loc (doc, _argDocs) docnames ty unicode
- = declWithDoc pref1 (documentationToLaTeX doc)
+-- | 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
+ = ppTypeOrFunSig typ doc
+ ( keyword "pattern" <+> ppTypeSig names typ False
+ , keyword "pattern" <+> (hsep . punctuate comma $ map ppSymName names)
+ , dcolon unicode
+ )
+ unicode
where
- pref1 = hsep [ keyword "pattern"
- , hsep $ punctuate comma $ map ppDocBinder docnames
- , dcolon unicode
- , ppLType unicode (hsSigType ty)
- ]
-
-ppTypeOrFunSig :: SrcSpan -> [DocName] -> HsType DocNameI
- -> DocForDecl DocName -> (LaTeX, LaTeX, LaTeX)
- -> Bool -> LaTeX
-ppTypeOrFunSig _ _ typ (doc, argDocs) (pref1, pref2, sep0)
- unicode
- | Map.null argDocs =
- declWithDoc pref1 (documentationToLaTeX doc)
- | otherwise =
- declWithDoc pref2 $ Just $
+ typ = unLoc (hsSigType ty)
+ names = map getName docnames
+
+-- | Pretty-print a type, adding documentation to the whole type and its
+-- arguments as needed.
+ppTypeOrFunSig :: HsType 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" $$
- do_args 0 sep0 typ $$
+ 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
+ -> HsType 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_args 0 leader typ
where
- do_largs n leader (L _ t) = do_args n leader t
-
- arg_doc n = rDoc . fmap _doc $ Map.lookup n argDocs
-
- do_args :: Int -> LaTeX -> HsType DocNameI -> LaTeX
- do_args _n leader (HsForAllTy tvs ltype)
- = decltt leader
- <-> decltt (hsep (forallSymbol unicode : ppTyVars tvs ++ [dot]))
- <+> ppLType unicode ltype
- do_args n leader (HsQualTy lctxt ltype)
- = decltt leader
- <-> ppLContextNoArrow lctxt unicode <+> nl $$
- do_largs n (darrow unicode) ltype
- do_args n leader (HsFunTy 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_largs n leader (L _ t) = do_args n leader t
+
+ arg_doc n = rDoc . fmap _doc $ Map.lookup n argDocs
+
+ do_args :: Int -> LaTeX -> HsType DocNameI -> [(LaTeX, LaTeX)]
+ do_args _n leader (HsForAllTy tvs ltype)
+ = [ ( decltt leader
+ , decltt (hsep (forallSymbol unicode : ppTyVars tvs ++ [dot]))
+ <+> ppLType unicode ltype
+ ) ]
+ do_args n leader (HsQualTy lctxt ltype)
+ = (decltt leader, ppLContextNoArrow lctxt unicode <+> nl)
+ : do_largs n (darrow unicode) ltype
+
+ do_args n leader (HsFunTy (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 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
+ --
+ -- We need 'gadtComma' and 'gadtEnd' to line up with the `{` from
+ -- 'gadtOpen', so we add 3 spaces to cover for `-> `/`:: ` (3 in unicode
+ -- mode since `->` and `::` are rendered as single characters.
+ gadtComma = hcat (replicate (if unicode then 3 else 4) (text "\\ ")) <> text ","
+ gadtEnd = hcat (replicate (if unicode then 3 else 4) (text "\\ ")) <> text "\\}"
+ gadtOpen = text "\\{"
ppTypeSig :: [Name] -> HsType DocNameI -> Bool -> LaTeX
@@ -483,10 +522,10 @@ ppFds fds unicode =
hsep (map (ppDocName . unLoc) vars2)
-ppClassDecl :: [DocInstance DocNameI] -> SrcSpan
+ppClassDecl :: [DocInstance DocNameI]
-> Documentation DocName -> [(DocName, DocForDecl DocName)]
-> TyClDecl DocNameI -> Bool -> LaTeX
-ppClassDecl instances loc doc subdocs
+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)) $$
@@ -508,7 +547,7 @@ ppClassDecl instances loc doc subdocs
methodTable =
text "\\haddockpremethods{}\\textbf{Methods}" $$
- vcat [ ppFunSig loc doc names (hsSigWcType typ) unicode
+ vcat [ ppFunSig doc names (hsSigWcType typ) unicode
| L _ (TypeSig lnames typ) <- lsigs
, let doc = lookupAnySubdoc (head names) subdocs
names = map unLoc lnames ]
@@ -518,7 +557,7 @@ ppClassDecl instances loc doc subdocs
instancesBit = ppDocInstances unicode instances
-ppClassDecl _ _ _ _ _ _ = error "declaration type not supported by ppShortClassDecl"
+ppClassDecl _ _ _ _ _ = error "declaration type not supported by ppShortClassDecl"
ppDocInstances :: Bool -> [DocInstance DocNameI] -> LaTeX
ppDocInstances _unicode [] = empty
@@ -567,15 +606,17 @@ lookupAnySubdoc n subdocs = case lookup n subdocs of
-- * Data & newtype declarations
-------------------------------------------------------------------------------
-
-ppDataDecl :: [(HsDecl DocNameI, DocForDecl DocName)] -> [DocInstance DocNameI] ->
- [(DocName, DocForDecl DocName)] -> SrcSpan ->
- Maybe (Documentation DocName) -> TyClDecl DocNameI -> Bool ->
- LaTeX
-ppDataDecl pats instances subdocs _loc doc dataDecl unicode
-
- = declWithDoc (ppDataHeader dataDecl unicode <+> whereBit)
- (if null body then Nothing else Just (vcat body))
+-- | 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 pats instances subdocs doc dataDecl unicode =
+ declWithDoc (ppDataHeader dataDecl unicode <+> whereBit)
+ (if null body then Nothing else Just (vcat body))
$$ instancesBit
where
@@ -587,28 +628,26 @@ ppDataDecl pats instances subdocs _loc doc dataDecl unicode
(whereBit, leaders)
| null cons
, null pats = (empty,[])
- | null cons = (decltt (keyword "where"), repeat empty)
+ | null cons = (text "where", repeat empty)
| otherwise = case resTy of
- ConDeclGADT{} -> (decltt (keyword "where"), repeat empty)
+ 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 cons) $$
text "\\end{tabulary}\\par"
patternBit
- | null cons = Nothing
- | otherwise = Just $
+ | null pats = Nothing
+ | otherwise = Just $
+ text "\\enspace" <+> emph (text "Bundled Patterns") <> text "\\par" $$
text "\\haddockbeginconstrs" $$
- vcat [ hsep [ keyword "pattern"
- , hsep $ punctuate comma $ map (ppDocBinder . unLoc) lnames
- , dcolon unicode
- , ppLType unicode (hsSigType ty)
- ] <-> rDoc (fmap _doc . combineDocumentation . fst $ d)
- | (SigD (PatSynSig lnames ty),d) <- pats
+ vcat [ empty <-> ppSideBySidePat lnames typ d unicode
+ | (SigD (PatSynSig lnames typ), d) <- pats
] $$
text "\\end{tabulary}\\par"
@@ -627,41 +666,100 @@ ppConstrHdr forall tvs ctxt unicode
False -> empty
-ppSideBySideConstr :: [(DocName, DocForDecl DocName)] -> Bool -> LaTeX
- -> LConDecl DocNameI -> LaTeX
-ppSideBySideConstr subdocs unicode leader (L _ con@(ConDeclH98 {})) =
- leader <->
- case con_args con of
-
- PrefixCon args ->
- decltt (hsep ((header_ unicode <+> ppOcc) :
- map (ppLParendType unicode) args))
- <-> rDoc mbDoc <+> nl
-
- RecCon (L _ fields) ->
- (decltt (header_ unicode <+> ppOcc)
- <-> rDoc mbDoc <+> nl)
- $$
- doRecordFields fields
-
- InfixCon arg1 arg2 ->
- decltt (hsep [ header_ unicode <+> ppLParendType unicode arg1,
- ppOcc,
- ppLParendType unicode arg2 ])
- <-> rDoc mbDoc <+> nl
+-- | Pretty-print a constructor
+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
+ where
+ -- Find the name of a constructors in the decl (`getConName` always returns
+ -- a non-empty list)
+ aConName = unLoc (head (getConNames con))
+
+ occ = map (nameOccName . getName . unLoc) $ getConNames con
+
+ 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
+ argDocs = maybe Map.empty snd (lookup aConName subdocs)
+ hasArgDocs = not $ Map.null argDocs
+
+ -- First line of the constructor (no doc, no fields, single-line)
+ decl = case con of
+ ConDeclH98{ con_args = det
+ , con_ex_tvs = vars
+ , con_mb_cxt = cxt
+ } -> let tyVars = map (getName . hsLTyVarName) vars
+ context = unLoc (fromMaybe (noLoc []) cxt)
+ forall_ = False
+ 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) 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 arg1
+ , ppOccInfix
+ , ppLParendType unicode arg2
+ ]
+
+ ConDeclGADT{}
+ | hasArgDocs || not (isEmpty fieldPart) -> ppOcc
+ | otherwise -> hsep [ ppOcc
+ , dcolon unicode
+ -- ++AZ++ make this prepend "{..}" when it is a record style GADT
+ , ppLType unicode (getGADTConType con)
+ ]
+
+ fieldPart = case (con, getConArgs con) of
+ -- Record style GADTs
+ (ConDeclGADT{}, RecCon _) -> doConstrArgsWithDocs []
+
+ -- Regular record declarations
+ (_, RecCon (L _ fields)) -> doRecordFields fields
+
+ -- Any GADT or a regular H98 prefix data constructor
+ (_, PrefixCon args) | hasArgDocs -> doConstrArgsWithDocs args
+
+ -- An infix H98 data constructor
+ (_, InfixCon arg1 arg2) | hasArgDocs -> doConstrArgsWithDocs [arg1,arg2]
+
+ _ -> empty
- where
doRecordFields fields =
- vcat (map (ppSideBySideField subdocs unicode) (map unLoc fields))
+ 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
+ , let mdoc = Map.lookup i argDocs
+ ]
+ ConDeclGADT{} ->
+ [ l <+> text "\\enspace" <+> r
+ | (l,r) <- ppSubSigLike unicode (unLoc (getGADTConType con)) argDocs subdocs (dcolon unicode)
+ ]
- header_ = ppConstrHdr False tyVars context
- occ = map (nameOccName . getName . unLoc) $ getConNames con
- ppOcc = case occ of
- [one] -> ppBinder one
- _ -> cat (punctuate comma (map ppBinder occ))
- tyVars = map (getName . hsLTyVarName) (con_ex_tvs con)
- context = unLoc (fromMaybe (noLoc []) (con_mb_cxt con))
-- 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.
@@ -670,27 +768,8 @@ ppSideBySideConstr subdocs unicode leader (L _ con@(ConDeclH98 {})) =
(cn:_) -> lookup (unLoc cn) subdocs >>=
fmap _doc . combineDocumentation . fst
-ppSideBySideConstr subdocs unicode leader (L _ con@(ConDeclGADT {})) =
- leader <->
- doGADTCon (getGADTConType con)
-
- where
- doGADTCon resTy = decltt (ppOcc <+> dcolon unicode <+>
- ppLType unicode resTy
- ) <-> rDoc mbDoc
-
- occ = map (nameOccName . getName . unLoc) $ getConNames con
- ppOcc = case occ of
- [one] -> ppBinder one
- _ -> cat (punctuate comma (map ppBinder occ))
-
- -- 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 getConNames con of
- [] -> panic "empty con_names"
- (cn:_) -> lookup (unLoc cn) subdocs >>=
- fmap _doc . combineDocumentation . fst
+-- | Pretty-print a record field
ppSideBySideField :: [(DocName, DocForDecl DocName)] -> Bool -> ConDeclField DocNameI -> LaTeX
ppSideBySideField subdocs unicode (ConDeclField names ltype _) =
decltt (cat (punctuate comma (map (ppBinder . rdrNameOcc . unLoc . rdrNameFieldOcc . unLoc) names))
@@ -700,51 +779,37 @@ ppSideBySideField subdocs unicode (ConDeclField names ltype _) =
-- Where there is more than one name, they all have the same documentation
mbDoc = lookup (selectorFieldOcc $ unLoc $ head names) subdocs >>= fmap _doc . combineDocumentation . fst
--- {-
--- ppHsFullConstr :: HsConDecl -> LaTeX
--- ppHsFullConstr (HsConDecl _ nm tvs ctxt typeList doc) =
--- declWithDoc False doc (
--- hsep ((ppHsConstrHdr tvs ctxt +++
--- ppHsBinder False nm) : map ppHsBangType typeList)
--- )
--- ppHsFullConstr (HsRecDecl _ nm tvs ctxt fields doc) =
--- td << vanillaTable << (
--- case doc of
--- Nothing -> aboves [hdr, fields_html]
--- Just _ -> aboves [hdr, constr_doc, fields_html]
--- )
---
--- where hdr = declBox (ppHsConstrHdr tvs ctxt +++ ppHsBinder False nm)
---
--- constr_doc
--- | isJust doc = docBox (docToLaTeX (fromJust doc))
--- | otherwise = LaTeX.emptyTable
---
--- fields_html =
--- td <<
--- table ! [width "100%", cellpadding 0, cellspacing 8] << (
--- aboves (map ppFullField (concat (map expandField fields)))
--- )
--- -}
---
--- ppShortField :: Bool -> Bool -> ConDeclField DocName -> LaTeX
--- ppShortField summary unicode (ConDeclField (L _ name) ltype _)
--- = tda [theclass "recfield"] << (
--- ppBinder summary (docNameOcc name)
--- <+> dcolon unicode <+> ppLType unicode ltype
--- )
---
--- {-
--- ppFullField :: HsFieldDecl -> LaTeX
--- ppFullField (HsFieldDecl [n] ty doc)
--- = declWithDoc False doc (
--- ppHsBinder False n <+> dcolon <+> ppHsBangType ty
--- )
--- ppFullField _ = error "ppFullField"
---
--- expandField :: HsFieldDecl -> [HsFieldDecl]
--- expandField (HsFieldDecl ns ty doc) = [ HsFieldDecl [n] ty doc | n <- ns ]
--- -}
+
+-- | Pretty-print a bundled pattern synonym
+ppSideBySidePat :: [Located 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
+ 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
+ , ppLType unicode (hsSigType typ)
+ ]
+
+ fieldPart
+ | not hasArgDocs = empty
+ | otherwise = vcat
+ [ empty <-> text "\\qquad" <+> l <+> text "\\enspace" <+> r
+ | (l,r) <- ppSubSigLike unicode (unLoc patTy) argDocs [] (dcolon unicode)
+ ]
+
+ patTy = hsSigType typ
+
+ mDoc = fmap _doc $ combineDocumentation doc
-- | Print the LHS of a data\/newtype declaration.
@@ -760,6 +825,7 @@ ppDataHeader (DataDecl { tcdLName = L _ name, tcdTyVars = tyvars
ppAppDocNameNames False name (tyvarNames tyvars)
ppDataHeader _ _ = error "ppDataHeader: illegal argument"
+
--------------------------------------------------------------------------------
-- * Type applications
--------------------------------------------------------------------------------
@@ -911,7 +977,7 @@ ppr_mono_ty _ (HsListTy ty) u = brackets (ppr_mono_lty pREC_TOP ty
ppr_mono_ty _ (HsPArrTy ty) u = pabrackets (ppr_mono_lty pREC_TOP ty u)
ppr_mono_ty _ (HsIParamTy (L _ n) ty) u = brackets (ppIPName n <+> dcolon u <+> ppr_mono_lty pREC_TOP ty u)
ppr_mono_ty _ (HsSpliceTy {}) _ = error "ppr_mono_ty HsSpliceTy"
-ppr_mono_ty _ (HsRecTy {}) _ = error "ppr_mono_ty HsRecTy"
+ppr_mono_ty _ (HsRecTy {}) _ = text "{..}"
ppr_mono_ty _ (HsCoreTy {}) _ = error "ppr_mono_ty HsCoreTy"
ppr_mono_ty _ (HsExplicitListTy Promoted _ 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
@@ -972,6 +1038,11 @@ ppBinder n
| isInfixName n = parens $ ppOccName n
| otherwise = ppOccName n
+ppBinderInfix :: OccName -> LaTeX
+ppBinderInfix n
+ | isInfixName n = ppOccName n
+ | otherwise = cat [ char '`', ppOccName n, char '`' ]
+
isInfixName :: OccName -> Bool
isInfixName n = isVarSym n || isConSym n
diff --git a/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs b/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs
index bf71fec4..fcc52a99 100644
--- a/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs
+++ b/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs
@@ -40,10 +40,19 @@ import Name
import BooleanFormula
import RdrName ( rdrNameOcc )
-ppDecl :: Bool -> LinksInfo -> LHsDecl DocNameI
- -> [(HsDecl DocNameI, DocForDecl DocName)]
- -> DocForDecl DocName -> [DocInstance DocNameI] -> [(DocName, Fixity)]
- -> [(DocName, DocForDecl DocName)] -> Splice -> Unicode -> Qualification -> Html
+-- | 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
+ -> Qualification
+ -> Html
ppDecl summ links (L loc decl) pats (mbDoc, fnArgsDoc) instances fixities subdocs splice unicode qual = case decl of
TyClD (FamDecl d) -> ppTyFam summ False links instances fixities loc mbDoc d splice unicode qual
TyClD d@(DataDecl {}) -> ppDataDecl summ links instances fixities subdocs loc mbDoc d pats splice unicode qual
@@ -51,8 +60,8 @@ ppDecl summ links (L loc decl) pats (mbDoc, fnArgsDoc) instances fixities subdoc
TyClD d@(ClassDecl {}) -> ppClassDecl summ links instances fixities loc mbDoc subdocs d splice unicode qual
SigD (TypeSig lnames lty) -> ppLFunSig summ links loc (mbDoc, fnArgsDoc) lnames
(hsSigWcType lty) fixities splice unicode qual
- SigD (PatSynSig lnames ty) -> ppLPatSig summ links loc (mbDoc, fnArgsDoc) lnames
- ty fixities splice unicode qual
+ SigD (PatSynSig lnames lty) -> ppLPatSig summ links loc (mbDoc, fnArgsDoc) lnames
+ (hsSigType lty) fixities splice unicode qual
ForD d -> ppFor summ links loc (mbDoc, fnArgsDoc) d fixities splice unicode qual
InstD _ -> noHtml
DerivD _ -> noHtml
@@ -75,20 +84,18 @@ ppFunSig summary links loc doc docnames typ fixities splice unicode qual =
where
pp_typ = ppLType unicode qual HideEmptyContexts typ
-ppLPatSig :: Bool -> LinksInfo -> SrcSpan -> DocForDecl DocName ->
- [Located DocName] -> LHsSigType DocNameI ->
- [(DocName, Fixity)] ->
- Splice -> Unicode -> Qualification -> Html
-ppLPatSig summary links loc (doc, _argDocs) docnames typ fixities splice unicode qual
- | summary = pref1
- | otherwise = topDeclElem links loc splice (map unLoc docnames) (pref1 <+> ppFixities fixities qual)
- +++ docSection Nothing qual doc
+-- | Pretty print a pattern synonym
+ppLPatSig :: Bool -> LinksInfo -> SrcSpan -> DocForDecl DocName
+ -> [Located DocName] -- ^ names of patterns in declaration
+ -> LHsType DocNameI -- ^ type of patterns in declaration
+ -> [(DocName, Fixity)]
+ -> Splice -> Unicode -> Qualification -> Html
+ppLPatSig summary links loc doc lnames typ fixities splice unicode qual =
+ ppSigLike summary links loc (keyword "pattern") doc (map unLoc lnames) fixities
+ (unLoc typ, pp_typ) splice unicode qual (patSigContext typ)
where
- pref1 = hsep [ keyword "pattern"
- , hsep $ punctuate comma $ map (ppBinder summary . getOccName) docnames
- , dcolon unicode
- , ppPatSigType unicode qual (hsSigType typ)
- ]
+ pp_typ = ppPatSigType unicode qual typ
+
ppSigLike :: Bool -> LinksInfo -> SrcSpan -> Html -> DocForDecl DocName ->
[DocName] -> [(DocName, Fixity)] -> (HsType DocNameI, Html) ->
@@ -97,7 +104,7 @@ ppSigLike summary links loc leader doc docnames fixities (typ, pp_typ)
splice unicode qual emptyCtxts =
ppTypeOrFunSig summary links loc docnames typ doc
( addFixities $ leader <+> ppTypeSig summary occnames pp_typ unicode
- , addFixities . concatHtml . punctuate comma $ map (ppBinder False) occnames
+ , (leader <+>) . addFixities . concatHtml . punctuate comma $ map (ppBinder False) occnames
, dcolon unicode
)
splice unicode qual emptyCtxts
@@ -114,10 +121,26 @@ ppTypeOrFunSig :: Bool -> LinksInfo -> SrcSpan -> [DocName] -> HsType DocNameI
ppTypeOrFunSig summary links loc docnames typ (doc, argDocs) (pref1, pref2, sep) splice unicode qual emptyCtxts
| summary = pref1
| Map.null argDocs = topDeclElem links loc splice docnames pref1 +++ docSection curName qual doc
- | otherwise = topDeclElem links loc splice docnames pref2 +++
- subArguments qual (do_args 0 sep typ) +++ docSection curName qual doc
+ | otherwise = topDeclElem links loc splice docnames pref2
+ +++ subArguments qual (ppSubSigLike unicode qual typ argDocs [] sep emptyCtxts)
+ +++ docSection curName 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
+ -> HsType 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_args 0 sep typ
+ where
argDoc n = Map.lookup n argDocs
do_largs n leader (L _ t) = do_args n leader t
@@ -135,12 +158,32 @@ ppTypeOrFunSig summary links loc docnames typ (doc, argDocs) (pref1, pref2, sep)
= (leader <+> ppLContextNoArrow lctxt unicode qual emptyCtxts, Nothing, [])
: do_largs n (darrow unicode) ltype
+ do_args n leader (HsFunTy (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 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
+ --
+ -- We need 'gadtComma' and 'gadtEnd' to line up with the `{` from
+ -- 'gadtOpen', so we add 3 spaces to cover for `-> `/`:: ` (3 in unicode
+ -- mode since `->` and `::` are rendered as single characters.
+ gadtComma = concatHtml (replicate (if unicode then 2 else 3) spaceHtml) <> toHtml ","
+ gadtEnd = concatHtml (replicate (if unicode then 2 else 3) spaceHtml) <> toHtml "}"
+ gadtOpen = toHtml "{"
+
+
+
ppForAll :: [LHsTyVarBndr DocNameI] -> Unicode -> Qualification -> Html
ppForAll tvs unicode qual =
case [ppKTv n k | L _ (KindedTyVar (L _ n) k) <- tvs] of
@@ -707,11 +750,16 @@ ppShortDataDecl summary dataInst dataDecl pats unicode qual
]
-ppDataDecl :: Bool -> LinksInfo -> [DocInstance DocNameI] -> [(DocName, Fixity)] ->
- [(DocName, DocForDecl DocName)] ->
- SrcSpan -> Documentation DocName -> TyClDecl DocNameI ->
- [(HsDecl DocNameI, DocForDecl DocName)] ->
- Splice -> Unicode -> Qualification -> Html
+-- | 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 -> Qualification -> Html
ppDataDecl summary links instances fixities subdocs loc doc dataDecl pats
splice unicode qual
@@ -740,25 +788,20 @@ ppDataDecl summary links instances fixities subdocs loc doc dataDecl pats
[ ppSideBySideConstr subdocs subfixs unicode qual c
| c <- cons
, let subfixs = filter (\(n,_) -> any (\cn -> cn == n)
- (map unLoc (getConNames (unLoc c)))) fixities
+ (map unLoc (getConNames (unLoc c)))) fixities
]
patternBit = subPatterns qual
- [ (hsep [ keyword "pattern"
- , hsep $ punctuate comma $ map (ppBinder summary . getOccName) lnames
- , dcolon unicode
- , ppPatSigType unicode qual (hsSigType typ)
- ] <+> ppFixities subfixs qual
- ,combineDocumentation (fst d), [])
- | (SigD (PatSynSig lnames typ),d) <- pats
- , let subfixs = filter (\(n,_) -> any (\cn -> cn == n) (map unLoc lnames)) fixities
+ [ 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 qual
-
ppShortConstr :: Bool -> ConDecl DocNameI -> Unicode -> Qualification -> Html
ppShortConstr summary con unicode qual = cHead <+> cBody <+> cFoot
where
@@ -768,121 +811,180 @@ ppShortConstr summary con unicode qual = cHead <+> cBody <+> cFoot
-- 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{} -> case con_args con of
- PrefixCon args ->
- (header_ unicode qual +++ hsep (ppOcc
- : map (ppLParendType unicode qual HideEmptyContexts) args), noHtml, noHtml)
- RecCon (L _ fields) ->
- (header_ unicode qual +++ ppOcc <+> char '{',
- doRecordFields fields,
- char '}')
- InfixCon arg1 arg2 ->
- (header_ unicode qual +++ hsep [ppLParendType unicode qual HideEmptyContexts arg1,
- ppOccInfix, ppLParendType unicode qual HideEmptyContexts arg2],
- noHtml, noHtml)
-
- ConDeclGADT {} -> (ppOcc <+> dcolon unicode
- <+> ppLType unicode qual HideEmptyContexts (getGADTConType con)
- , noHtml, noHtml)
-
- where
- doRecordFields fields = shortSubDecls dataInst $
- map (ppShortField summary unicode qual) (map unLoc fields)
-
- header_ = ppConstrHdr forall_ tyVars context
- occ = map (nameOccName . getName . unLoc) $ getConNames con
-
- ppOcc = case occ of
- [one] -> ppBinder summary one
- _ -> hsep (punctuate comma (map (ppBinder summary) occ))
+ppShortConstrParts summary dataInst con unicode qual
+ = case con of
+ ConDeclH98{ con_args = det
+ , con_ex_tvs = vars
+ , con_mb_cxt = cxt
+ } -> let tyVars = map (getName . hsLTyVarName) vars
+ context = unLoc (fromMaybe (noLoc []) cxt)
+ forall_ = False
+ 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) args)
+ , noHtml
+ , noHtml
+ )
- ppOccInfix = case occ of
- [one] -> ppBinderInfix summary one
- _ -> hsep (punctuate comma (map (ppBinderInfix summary) occ))
+ -- Record constructor, e.g. 'Identity { runIdentity :: a }'
+ RecCon (L _ fields) ->
+ ( header_ +++ ppOcc <+> char '{'
+ , shortSubDecls dataInst [ ppShortField summary unicode qual field
+ | L _ field <- fields
+ ]
+ , char '}'
+ )
- -- Used for H98 syntax only
- tyVars = map (getName . hsLTyVarName) (con_ex_tvs con)
- lcontext = fromMaybe (noLoc []) (con_mb_cxt con)
- context = unLoc lcontext
- forall_ = False
+ -- Infix constructor, e.g. 'a :| [a]'
+ InfixCon arg1 arg2 ->
+ ( header_ +++ hsep [ ppLParendType unicode qual HideEmptyContexts arg1
+ , ppOccInfix
+ , ppLParendType unicode qual HideEmptyContexts arg2
+ ]
+ , noHtml
+ , noHtml
+ )
+ -- GADT constructor, e.g. 'Foo :: Int -> Foo'
+ ConDeclGADT {} ->
+ ( hsep [ ppOcc, dcolon unicode, ppLType unicode qual HideEmptyContexts (getGADTConType con) ]
+ , noHtml
+ , noHtml
+ )
--- ppConstrHdr is for (non-GADT) existentials constructors' syntax
-ppConstrHdr :: Bool -> [Name] -> HsContext DocNameI -> Unicode
- -> Qualification -> Html
-ppConstrHdr forall_ tvs ctxt unicode qual
- = (if null tvs then noHtml else ppForall)
- +++
- (if null ctxt then noHtml
- else ppContextNoArrow ctxt unicode qual HideEmptyContexts
- <+> darrow unicode +++ toHtml " ")
where
- ppForall | forall_ = forallSymbol unicode <+> hsep (map (ppName Prefix) tvs)
- <+> toHtml ". "
- | otherwise = noHtml
+ occ = map (nameOccName . getName . unLoc) $ getConNames 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 -> Qualification -> LConDecl DocNameI -> SubDecl
+ -> Unicode -> Qualification
+ -> LConDecl DocNameI -- ^ constructor declaration to print
+ -> SubDecl
ppSideBySideConstr subdocs fixities unicode qual (L _ con)
- = (decl, mbDoc, fieldPart)
+ = ( decl -- Constructor header (name, fixity)
+ , mbDoc -- Docs on the whole constructor
+ , fieldPart -- Information on the fields (or arguments, if they have docs)
+ )
where
- decl = case con of
- ConDeclH98{} -> case con_args con of
- PrefixCon args ->
- hsep ((header_ +++ ppOcc)
- : map (ppLParendType unicode qual HideEmptyContexts) args)
- <+> fixity
+ -- Find the name of a constructors in the decl (`getConName` always returns a non-empty list)
+ aConName = unLoc (head (getConNames con))
- RecCon _ -> header_ +++ ppOcc <+> fixity
+ fixity = ppFixities fixities qual
+ occ = map (nameOccName . getName . unLoc) $ getConNames con
- InfixCon arg1 arg2 ->
- hsep [header_ +++ ppLParendType unicode qual HideEmptyContexts arg1,
- ppOccInfix,
- ppLParendType unicode qual HideEmptyContexts arg2]
- <+> fixity
+ 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
+ argDocs = maybe Map.empty snd (lookup aConName subdocs)
+ hasArgDocs = not $ Map.null argDocs
+
+ decl = case con of
+ ConDeclH98{ con_args = det
+ , con_ex_tvs = vars
+ , con_mb_cxt = cxt
+ } -> let tyVars = map (getName . hsLTyVarName) vars
+ context = unLoc (fromMaybe (noLoc []) cxt)
+ forall_ = False
+ 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) args)
+ , fixity
+ ]
+
+ -- Record constructor, e.g. 'Identity { runIdentity :: a }'
+ RecCon _ -> header_ +++ ppOcc <+> fixity
- ConDeclGADT{} -> doGADTCon (getGADTConType con)
+ -- Infix constructor, e.g. 'a :| [a]'
+ InfixCon arg1 arg2
+ | hasArgDocs -> header_ +++ ppOcc <+> fixity
+ | otherwise -> hsep [ header_ +++ ppLParendType unicode qual HideEmptyContexts arg1
+ , ppOccInfix
+ , ppLParendType unicode qual HideEmptyContexts 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
+ , ppLType unicode qual HideEmptyContexts (getGADTConType con)
+ , fixity
+ ]
+
+ fieldPart = case (con, getConArgs con) of
+ -- Record style GADTs
+ (ConDeclGADT{}, RecCon _) -> [ doConstrArgsWithDocs [] ]
+
+ -- Regular record declarations
+ (_, RecCon (L _ fields)) -> [ doRecordFields fields ]
+
+ -- Any GADT or a regular H98 prefix data constructor
+ (_, PrefixCon args) | hasArgDocs -> [ doConstrArgsWithDocs args ]
+
+ -- An infix H98 data constructor
+ (_, InfixCon arg1 arg2) | hasArgDocs -> [ doConstrArgsWithDocs [arg1,arg2] ]
- fieldPart = case getConArgs con of
- RecCon (L _ fields) -> [doRecordFields fields]
_ -> []
doRecordFields fields = subFields qual
(map (ppSideBySideField subdocs unicode qual) (map unLoc fields))
- doGADTCon :: Located (HsType DocNameI) -> Html
- doGADTCon ty = ppOcc <+> dcolon unicode
- -- ++AZ++ make this prepend "{..}" when it is a record style GADT
- <+> ppLType unicode qual HideEmptyContexts ty
- <+> fixity
+ doConstrArgsWithDocs args = subFields qual $ case con of
+ ConDeclH98{} ->
+ [ (ppLParendType unicode qual HideEmptyContexts arg, mdoc, [])
+ | (i, arg) <- zip [0..] args
+ , let mdoc = Map.lookup i argDocs
+ ]
+ ConDeclGADT{} ->
+ ppSubSigLike unicode qual (unLoc (getGADTConType con))
+ argDocs subdocs (dcolon unicode) HideEmptyContexts
- fixity = ppFixities fixities qual
- header_ = ppConstrHdr forall_ tyVars context unicode qual
- occ = map (nameOccName . getName . unLoc) $ getConNames con
-
- ppOcc = case occ of
- [one] -> ppBinder False one
- _ -> hsep (punctuate comma (map (ppBinder False) occ))
-
- ppOccInfix = case occ of
- [one] -> ppBinderInfix False one
- _ -> hsep (punctuate comma (map (ppBinderInfix False) occ))
-
- -- Used for H98 syntax only
- tyVars = map (getName . hsLTyVarName) (con_ex_tvs con)
- context = unLoc (fromMaybe (noLoc []) (con_mb_cxt con))
- forall_ = False
-- 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 (unLoc $ head $ getConNames con) subdocs >>=
combineDocumentation . fst
+-- ppConstrHdr is for (non-GADT) existentials constructors' syntax
+ppConstrHdr :: Bool -- ^ print explicit foralls
+ -> [Name] -- ^ type variables
+ -> HsContext DocNameI -- ^ context
+ -> Unicode -> Qualification -> Html
+ppConstrHdr forall_ tvs ctxt unicode qual = ppForall +++ ppCtxt
+ where
+ ppForall
+ | null tvs || not forall_ = noHtml
+ | otherwise = forallSymbol unicode
+ <+> hsep (map (ppName Prefix) tvs)
+ <+> toHtml ". "
+
+ ppCtxt
+ | null ctxt = noHtml
+ | otherwise = ppContextNoArrow ctxt unicode qual HideEmptyContexts
+ <+> darrow unicode +++ toHtml " "
+
+
+-- | Pretty-print a record field
ppSideBySideField :: [(DocName, DocForDecl DocName)] -> Unicode -> Qualification
-> ConDeclField DocNameI -> SubDecl
ppSideBySideField subdocs unicode qual (ConDeclField names ltype _) =
- ( hsep (punctuate comma (map ((ppBinder False) . rdrNameOcc . unLoc . rdrNameFieldOcc . unLoc) names))
+ ( hsep (punctuate comma [ ppBinder False (rdrNameOcc field)
+ | L _ name <- names
+ , let field = (unLoc . rdrNameFieldOcc) name
+ ])
<+> dcolon unicode
<+> ppLType unicode qual HideEmptyContexts ltype
, mbDoc
@@ -900,6 +1002,40 @@ ppShortField summary unicode qual (ConDeclField names ltype _)
<+> dcolon unicode <+> ppLType unicode qual HideEmptyContexts ltype
+-- | Pretty print an expanded pattern (for bundled patterns)
+ppSideBySidePat :: [(DocName, Fixity)] -> Unicode -> Qualification
+ -> [Located 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
+ , fieldPart
+ )
+ where
+ hasArgDocs = not $ Map.null 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 (hsSigType typ)
+ , fixity
+ ]
+
+ fieldPart
+ | not hasArgDocs = []
+ | otherwise = [ subFields qual (ppSubSigLike unicode qual (unLoc patTy)
+ argDocs [] (dcolon unicode)
+ emptyCtxt) ]
+
+ patTy = hsSigType typ
+ emptyCtxt = patSigContext patTy
+
+
-- | 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
@@ -990,13 +1126,9 @@ ppLKind unicode qual y = ppKind unicode qual (unLoc y)
ppKind :: Unicode -> Qualification -> HsKind DocNameI -> Html
ppKind unicode qual ki = ppr_mono_ty pREC_TOP ki unicode qual HideEmptyContexts
-ppPatSigType :: Unicode -> Qualification -> LHsType DocNameI -> Html
-ppPatSigType unicode qual typ =
- let emptyCtxts =
- if hasNonEmptyContext typ && isFirstContextEmpty typ
- then ShowEmptyToplevelContexts
- else HideEmptyContexts
- in ppLType unicode qual emptyCtxts typ
+patSigContext :: LHsType name -> HideEmptyContexts
+patSigContext typ | hasNonEmptyContext typ && isFirstContextEmpty typ = ShowEmptyToplevelContexts
+ | otherwise = HideEmptyContexts
where
hasNonEmptyContext :: LHsType name -> Bool
hasNonEmptyContext t =
@@ -1013,6 +1145,13 @@ ppPatSigType unicode qual typ =
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 -> LHsType DocNameI -> Html
+ppPatSigType unicode qual typ =
+ let emptyCtxts = patSigContext typ in ppLType unicode qual emptyCtxts typ
+
ppForAllPart :: Unicode -> Qualification -> [LHsTyVarBndr DocNameI] -> Html
ppForAllPart unicode qual tvs = hsep (forallSymbol unicode : ppTyVars unicode qual tvs) +++ dot
diff --git a/haddock-api/src/Haddock/Backends/Xhtml/Utils.hs b/haddock-api/src/Haddock/Backends/Xhtml/Utils.hs
index a75c4b9a..7fbaec6d 100644
--- a/haddock-api/src/Haddock/Backends/Xhtml/Utils.hs
+++ b/haddock-api/src/Haddock/Backends/Xhtml/Utils.hs
@@ -110,7 +110,7 @@ renderToString debug html
hsep :: [Html] -> Html
hsep [] = noHtml
-hsep htmls = foldr1 (\a b -> a+++" "+++b) htmls
+hsep htmls = foldr1 (<+>) htmls
-- | Concatenate a series of 'Html' values vertically, with linebreaks in between.
vcat :: [Html] -> Html
@@ -232,4 +232,4 @@ collapseToggle id_ classes = [ theclass cs, strAttr "data-details-id" id_ ]
-- and displays a control.
collapseControl :: String -> String -> [HtmlAttr]
collapseControl id_ classes = collapseToggle id_ cs
- where cs = unwords (words classes ++ ["details-toggle-control"]) \ No newline at end of file
+ where cs = unwords (words classes ++ ["details-toggle-control"])
diff --git a/haddock-api/src/Haddock/Interface/Create.hs b/haddock-api/src/Haddock/Interface/Create.hs
index 52a983a8..f673e23b 100644
--- a/haddock-api/src/Haddock/Interface/Create.hs
+++ b/haddock-api/src/Haddock/Interface/Create.hs
@@ -380,7 +380,7 @@ mkMaps dflags gre instances decls = do
m' <- traverse (processDocStringParas dflags gre) m
pure (doc', m')
- (doc, args) <- declDoc docStrs (typeDocs decl)
+ (doc, args) <- declDoc docStrs (declTypeDocs decl)
let
subs :: [(Name, [HsDocString], Map Int HsDocString)]
@@ -445,14 +445,14 @@ subordinates instMap decl = case decl of
| isDataDecl d -> dataSubs (tcdDataDefn d)
_ -> []
where
- classSubs dd = [ (name, doc, typeDocs d) | (L _ d, doc) <- classDecls dd
+ classSubs dd = [ (name, doc, declTypeDocs d) | (L _ d, doc) <- classDecls dd
, name <- getMainDeclBinder d, not (isValD d)
]
dataSubs :: HsDataDefn GhcRn -> [(Name, [HsDocString], Map Int HsDocString)]
dataSubs dd = constrs ++ fields ++ derivs
where
cons = map unL $ (dd_cons dd)
- constrs = [ (unL cname, maybeToList $ fmap unL $ con_doc c, M.empty)
+ constrs = [ (unL cname, maybeToList $ fmap unL $ con_doc c, conArgDocs c)
| c <- cons, cname <- getConNames c ]
fields = [ (selectorFieldOcc n, maybeToList $ fmap unL doc, M.empty)
| RecCon flds <- map getConArgs cons
@@ -464,17 +464,33 @@ subordinates instMap decl = case decl of
unLoc $ dd_derivs dd
, Just instName <- [M.lookup l instMap] ]
+-- | Extract constructor argument docs from inside constructor decls.
+conArgDocs :: ConDecl GhcRn -> Map Int HsDocString
+conArgDocs con = case getConArgs con of
+ PrefixCon args -> go 0 (map unLoc args ++ ret)
+ InfixCon arg1 arg2 -> go 0 ([unLoc arg1, unLoc arg2] ++ ret)
+ RecCon _ -> go 1 ret
+ where
+ go n (HsDocTy _ (L _ ds) : tys) = M.insert n ds $ go (n+1) tys
+ go n (_ : tys) = go (n+1) tys
+ go _ [] = M.empty
+
+ ret = case con of
+ ConDeclGADT { con_res_ty = res_ty } -> [ unLoc res_ty ]
+ _ -> []
+
+-- | Extract function argument docs from inside top-level decls.
+declTypeDocs :: HsDecl GhcRn -> Map Int HsDocString
+declTypeDocs (SigD (TypeSig _ ty)) = typeDocs (unLoc (hsSigWcType ty))
+declTypeDocs (SigD (ClassOpSig _ _ ty)) = typeDocs (unLoc (hsSigType ty))
+declTypeDocs (SigD (PatSynSig _ ty)) = typeDocs (unLoc (hsSigType ty))
+declTypeDocs (ForD (ForeignImport _ ty _ _)) = typeDocs (unLoc (hsSigType ty))
+declTypeDocs (TyClD (SynDecl { tcdRhs = ty })) = typeDocs (unLoc ty)
+declTypeDocs _ = M.empty
+
-- | Extract function argument docs from inside types.
-typeDocs :: HsDecl GhcRn -> Map Int HsDocString
-typeDocs d =
- let docs = go 0 in
- case d of
- SigD (TypeSig _ ty) -> docs (unLoc (hsSigWcType ty))
- SigD (ClassOpSig _ _ ty) -> docs (unLoc (hsSigType ty))
- SigD (PatSynSig _ ty) -> docs (unLoc (hsSigType ty))
- ForD (ForeignImport _ ty _ _) -> docs (unLoc (hsSigType ty))
- TyClD (SynDecl { tcdRhs = ty }) -> docs (unLoc ty)
- _ -> M.empty
+typeDocs :: HsType GhcRn -> Map Int HsDocString
+typeDocs = go 0
where
go n (HsForAllTy { hst_body = ty }) = go n (unLoc ty)
go n (HsQualTy { hst_body = ty }) = go n (unLoc ty)
@@ -483,7 +499,6 @@ typeDocs d =
go n (HsDocTy _ (L _ doc)) = M.singleton n doc
go _ _ = M.empty
-
-- | All the sub declarations of a class (that we handle), ordered by
-- source location, with documentation attached if it exists.
classDecls :: TyClDecl GhcRn -> [(LHsDecl GhcRn, [HsDocString])]