haddock-api 2.17.4 → 2.29.1
raw patch · 62 files changed
Files
- CHANGES.md +1/−0
- LICENSE +21/−18
- haddock-api.cabal +111/−25
- resources/html/Classic.theme/xhaddock.css +16/−0
- resources/html/Linuwial.std-theme/linuwial.css +881/−0
- resources/html/Linuwial.std-theme/synopsis.png binary
- resources/html/Ocean.std-theme/hslogo-16.png binary
- resources/html/Ocean.std-theme/minus.gif binary
- resources/html/Ocean.std-theme/ocean.css +0/−612
- resources/html/Ocean.std-theme/plus.gif binary
- resources/html/Ocean.std-theme/synopsis.png binary
- resources/html/Ocean.theme/hslogo-16.png binary
- resources/html/Ocean.theme/minus.gif binary
- resources/html/Ocean.theme/ocean.css +647/−0
- resources/html/Ocean.theme/plus.gif binary
- resources/html/Ocean.theme/synopsis.png binary
- resources/html/haddock-bundle.min.js +2/−0
- resources/html/haddock-util.js +0/−316
- resources/html/quick-jump.css +221/−0
- resources/html/quick-jump.min.js +2/−0
- resources/html/solarized.css +42/−0
- src/Documentation/Haddock.hs +4/−6
- src/Haddock.hs +429/−215
- src/Haddock/Backends/HaddockDB.hs +10/−5
- src/Haddock/Backends/Hoogle.hs +170/−137
- src/Haddock/Backends/Hyperlinker.hs +63/−13
- src/Haddock/Backends/Hyperlinker/Ast.hs +0/−185
- src/Haddock/Backends/Hyperlinker/Parser.hs +385/−193
- src/Haddock/Backends/Hyperlinker/Renderer.hs +210/−105
- src/Haddock/Backends/Hyperlinker/Types.hs +12/−49
- src/Haddock/Backends/Hyperlinker/Utils.hs +87/−11
- src/Haddock/Backends/LaTeX.hs +1449/−1265
- src/Haddock/Backends/Xhtml.hs +434/−194
- src/Haddock/Backends/Xhtml/Decl.hs +1309/−1048
- src/Haddock/Backends/Xhtml/DocMarkup.hs +79/−49
- src/Haddock/Backends/Xhtml/Layout.hs +79/−60
- src/Haddock/Backends/Xhtml/Meta.hs +28/−0
- src/Haddock/Backends/Xhtml/Names.hs +39/−17
- src/Haddock/Backends/Xhtml/Themes.hs +5/−4
- src/Haddock/Backends/Xhtml/Types.hs +12/−1
- src/Haddock/Backends/Xhtml/Utils.hs +35/−28
- src/Haddock/Convert.hs +986/−488
- src/Haddock/GhcUtils.hs +649/−119
- src/Haddock/Interface.hs +317/−127
- src/Haddock/Interface/AttachInstances.hs +164/−133
- src/Haddock/Interface/Create.hs +1274/−898
- src/Haddock/Interface/Json.hs +268/−0
- src/Haddock/Interface/LexParseRn.hs +234/−82
- src/Haddock/Interface/ParseModuleHeader.hs +126/−86
- src/Haddock/Interface/Rename.hs +568/−352
- src/Haddock/Interface/Specialize.hs +200/−199
- src/Haddock/InterfaceFile.hs +206/−189
- src/Haddock/ModuleTree.hs +24/−24
- src/Haddock/Options.hs +143/−13
- src/Haddock/Parser.hs +35/−23
- src/Haddock/Syb.hs +42/−24
- src/Haddock/Types.hs +664/−202
- src/Haddock/Utils.hs +56/−239
- src/Haddock/Utils/Json.hs +558/−0
- src/Haddock/Utils/Json/Parser.hs +102/−0
- src/Haddock/Utils/Json/Types.hs +42/−0
- test/Haddock/Backends/Hyperlinker/ParserSpec.hs +107/−43
+ CHANGES.md view
@@ -0,0 +1,1 @@+See [`haddock`'s changelog](https://hackage.haskell.org/package/haddock/changelog).
LICENSE view
@@ -1,23 +1,26 @@-Copyright 2002-2010, Simon Marlow. All rights reserved.+Copyright (c) 2002-2010, Simon Marlow+All rights reserved. Redistribution and use in source and binary forms, with or without-modification, are permitted provided that the following conditions are met:+modification, are permitted provided that the following conditions are+met: -- Redistributions of source code must retain the above copyright notice,-this list of conditions and the following disclaimer.+1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer. -- Redistributions in binary form must reproduce the above copyright notice,-this list of conditions and the following disclaimer in the documentation-and/or other materials provided with the distribution.+2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the+ distribution. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR-PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
haddock-api.cabal view
@@ -1,47 +1,54 @@+cabal-version: 3.0 name: haddock-api-version: 2.17.4+version: 2.29.1 synopsis: A documentation-generation tool for Haskell libraries description: Haddock is a documentation-generation tool for Haskell libraries-license: BSD3+license: BSD-2-Clause license-file: LICENSE author: Simon Marlow, David Waern-maintainer: Alex Biehl <alexbiehl@gmail.com>, Simon Hengel <sol@typeful.net>, Mateusz Kowalczyk <fuuzetsu@fuuzetsu.co.uk>+maintainer: Alec Theriault <alec.theriault@gmail.com>, Alex Biehl <alexbiehl@gmail.com>, Simon Hengel <sol@typeful.net>, Mateusz Kowalczyk <fuuzetsu@fuuzetsu.co.uk> homepage: http://www.haskell.org/haddock/ bug-reports: https://github.com/haskell/haddock/issues copyright: (c) Simon Marlow, David Waern category: Documentation build-type: Simple-cabal-version: >= 1.10-stability: experimental+tested-with: GHC==9.6.* +extra-source-files:+ CHANGES.md+ data-dir: resources data-files:+ html/quick-jump.min.js+ html/haddock-bundle.min.js+ html/quick-jump.css html/solarized.css- html/haddock-util.js html/highlight.js html/Classic.theme/haskell_icon.gif html/Classic.theme/minus.gif html/Classic.theme/plus.gif html/Classic.theme/xhaddock.css- html/Ocean.std-theme/hslogo-16.png- html/Ocean.std-theme/minus.gif- html/Ocean.std-theme/ocean.css- html/Ocean.std-theme/plus.gif- html/Ocean.std-theme/synopsis.png+ html/Ocean.theme/hslogo-16.png+ html/Ocean.theme/minus.gif+ html/Ocean.theme/ocean.css+ html/Ocean.theme/plus.gif+ html/Ocean.theme/synopsis.png+ html/Linuwial.std-theme/linuwial.css+ html/Linuwial.std-theme/synopsis.png latex/haddock.sty library default-language: Haskell2010 -- this package typically supports only single major versions- build-depends: base == 4.9.*- , Cabal == 1.24.*- , ghc == 8.0.*- , ghc-paths == 0.1.*- , haddock-library >= 1.4.2 && < 1.5- , xhtml == 3000.2.*+ build-depends: base ^>= 4.16.0+ , ghc ^>= 9.6+ , ghc-paths ^>= 0.1.0.9+ , haddock-library ^>= 1.11+ , xhtml ^>= 3000.2.2+ , parsec ^>= 3.1.13.0 -- Versions for the dependencies below are transitively pinned by -- the non-reinstallable `ghc` package and hence need no version@@ -51,14 +58,26 @@ , containers , deepseq , directory+ , exceptions , filepath , ghc-boot+ , mtl , transformers hs-source-dirs: src - ghc-options: -funbox-strict-fields -Wall -fwarn-tabs -O2+ ghc-options: -funbox-strict-fields -O2+ -Wall+ -Wcompat+ -Wcompat-unqualified-imports+ -Widentities+ -Wredundant-constraints+ -Wnoncanonical-monad-instances+ -Wmissing-home-modules+ -Wincomplete-uni-patterns+ -Wincomplete-record-updates + exposed-modules: Documentation.Haddock @@ -68,15 +87,20 @@ Haddock.Interface.Rename Haddock.Interface.Create Haddock.Interface.AttachInstances+ Haddock.Interface.Json Haddock.Interface.LexParseRn Haddock.Interface.ParseModuleHeader Haddock.Interface.Specialize Haddock.Parser Haddock.Utils+ Haddock.Utils.Json+ Haddock.Utils.Json.Types+ Haddock.Utils.Json.Parser Haddock.Backends.Xhtml Haddock.Backends.Xhtml.Decl Haddock.Backends.Xhtml.DocMarkup Haddock.Backends.Xhtml.Layout+ Haddock.Backends.Xhtml.Meta Haddock.Backends.Xhtml.Names Haddock.Backends.Xhtml.Themes Haddock.Backends.Xhtml.Types@@ -85,7 +109,6 @@ Haddock.Backends.HaddockDB Haddock.Backends.Hoogle Haddock.Backends.Hyperlinker- Haddock.Backends.Hyperlinker.Ast Haddock.Backends.Hyperlinker.Parser Haddock.Backends.Hyperlinker.Renderer Haddock.Backends.Hyperlinker.Types@@ -101,6 +124,9 @@ Haddock.Convert Paths_haddock_api + autogen-modules:+ Paths_haddock_api+ test-suite spec type: exitcode-stdio-1.0 default-language: Haskell2010@@ -112,14 +138,74 @@ , src other-modules:+ Haddock+ Haddock.Backends.Hoogle+ Haddock.Backends.Hyperlinker+ Haddock.Backends.Hyperlinker.Renderer+ Haddock.Backends.Hyperlinker.Utils+ Haddock.Backends.LaTeX+ Haddock.Backends.Xhtml+ Haddock.Backends.Xhtml.Decl+ Haddock.Backends.Xhtml.DocMarkup+ Haddock.Backends.Xhtml.Layout+ Haddock.Backends.Xhtml.Meta+ Haddock.Backends.Xhtml.Names+ Haddock.Backends.Xhtml.Themes+ Haddock.Backends.Xhtml.Types+ Haddock.Backends.Xhtml.Utils+ Haddock.Convert+ Haddock.Doc+ Haddock.GhcUtils+ Haddock.Interface+ Haddock.Interface.AttachInstances+ Haddock.Interface.Create+ Haddock.Interface.Json+ Haddock.Interface.LexParseRn+ Haddock.Interface.ParseModuleHeader+ Haddock.Interface.Rename+ Haddock.Interface.Specialize+ Haddock.InterfaceFile+ Haddock.ModuleTree+ Haddock.Options+ Haddock.Parser+ Haddock.Syb+ Haddock.Types+ Haddock.Utils+ Haddock.Utils.Json+ Haddock.Utils.Json.Types+ Haddock.Utils.Json.Parser+ Haddock.Version+ Paths_haddock_api Haddock.Backends.Hyperlinker.ParserSpec+ Haddock.Backends.Hyperlinker.Parser+ Haddock.Backends.Hyperlinker.Types - build-depends:- base- , containers- , ghc- , hspec- , QuickCheck == 2.*+ build-depends: ghc ^>= 9.6+ , ghc-paths ^>= 0.1.0.12+ , haddock-library ^>= 1.11+ , xhtml ^>= 3000.2.2+ , hspec ^>= 2.9+ , parsec ^>= 3.1.13.0+ , QuickCheck >= 2.11 && ^>= 2.14++ -- Versions for the dependencies below are transitively pinned by+ -- the non-reinstallable `ghc` package and hence need no version+ -- bounds+ build-depends: base+ , array+ , bytestring+ , containers+ , deepseq+ , directory+ , exceptions+ , filepath+ , ghc-boot+ , ghc-boot-th+ , mtl+ , transformers++ build-tool-depends:+ hspec-discover:hspec-discover ^>= 2.9 source-repository head type: git
resources/html/Classic.theme/xhaddock.css view
@@ -153,6 +153,7 @@ text-align: center; right: 0; padding: 2px 2px 1px;+ top: 1.25em; } #style-menu li {@@ -285,6 +286,7 @@ padding: 0 8px 2px 5px; margin-right: -3px; background-color: #f0f0f0;+ -moz-user-select: none; } div.subs {@@ -391,6 +393,20 @@ } +.doc table {+ border-collapse: collapse;+ border-spacing: 0px;+}++.doc th,+.doc td {+ padding: 5px;+ border: 1px solid #ddd;+}++.doc th {+ background-color: #f0f0f0;+} #footer { background-color: #000099;
+ resources/html/Linuwial.std-theme/linuwial.css view
@@ -0,0 +1,881 @@+/* @group Fundamentals */++* { margin: 0; padding: 0 }++/* Is this portable? */+html {+ background-color: white;+ width: 100%;+ height: 100%;+}++body {+ background: #fefefe;+ color: #111;+ text-align: left;+ min-height: 100vh;+ position: relative;+ -webkit-text-size-adjust: 100%;+ -webkit-font-feature-settings: "kern" 1, "liga" 0;+ -moz-font-feature-settings: "kern" 1, "liga" 0;+ -o-font-feature-settings: "kern" 1, "liga" 0;+ font-feature-settings: "kern" 1, "liga" 0;+ letter-spacing: 0.0015rem;+}++#content a {+ overflow-wrap: break-word;+}++p {+ margin: 0.8em 0;+}++ul, ol {+ margin: 0.8em 0 0.8em 2em;+}++dl {+ margin: 0.8em 0;+}++dt {+ font-weight: bold;+}+dd {+ margin-left: 2em;+}++a { text-decoration: none; }+a[href]:link { color: #9E358F; }+a[href]:visited {color: #6F5F9C; }+a[href]:hover { text-decoration:underline; }++a[href].def:link, a[href].def:visited { color: rgba(69, 59, 97, 0.8); }+a[href].def:hover { color: rgb(78, 98, 114); }++/* @end */++/* @group Show and hide with JS */++body.js-enabled .hide-when-js-enabled {+ display: none;+}++/* @end */+++/* @group responsive */++#package-header .caption {+ margin: 0px 1em 0 2em;+}++@media only screen and (min-width: 1280px) {+ #content {+ width: 63vw;+ max-width: 1450px;+ }++ #table-of-contents {+ position: fixed;+ max-width: 10vw;+ top: 10.2em;+ left: 2em;+ bottom: 1em;+ overflow-y: auto;+ }++ #synopsis {+ display: block;+ position: fixed;+ float: left;+ top: 5em;+ bottom: 1em;+ right: 0;+ max-width: 65vw;+ overflow-y: auto;+ /* Ensure that synopsis covers everything (including MathJAX markup) */+ z-index: 1;+ }++ #synopsis .show {+ border: 1px solid #5E5184;+ padding: 0.7em;+ max-height: 65vh;+ }++}++@media only screen and (max-width: 1279px) {+ #content {+ width: 80vw;+ }++ #synopsis {+ display: block;+ padding: 0;+ position: relative;+ margin: 0;+ width: 100%;+ }+}++@media only screen and (max-width: 999px) {+ #content {+ width: 93vw;+ }+}+++/* menu for wider screens++ Display the package name at the left and the menu links at the right,+ inline with each other:+ The package name Source . Contents . Index+*/+@media only screen and (min-width: 1000px) {+ #package-header {+ text-align: left;+ white-space: nowrap;+ height: 40px;+ padding: 4px 1.5em 0px 1.5em;+ overflow: visible;++ display: flex;+ justify-content: space-between;+ align-items: center;+ }++ #package-header .caption {+ display: inline-block;+ margin: 0;+ }++ #package-header ul.links {+ margin: 0;+ display: inline-table;+ }++ #package-header .caption + ul.links {+ margin-left: 1em;+ }+}++/* menu for smaller screens++Display the package name on top of the menu links and center both elements:+ The package name+ Source . Contents . Index+*/+@media only screen and (max-width: 999px) {+ #package-header {+ text-align: center;+ padding: 6px 0 4px 0;+ overflow: hidden;+ }++ #package-header ul.links {+ display: block;+ text-align: center;+ margin: 0;++ /* Hide scrollbar but allow scrolling menu links horizontally */+ white-space: nowrap;+ overflow-x: auto;+ overflow-y: hidden;+ margin-bottom: -17px;+ height: 50px;+ }++ #package-header .caption {+ display: block;+ margin: 4px 0;+ text-align: center;+ }++ #package-header ul.links::-webkit-scrollbar {+ display: none;+ }++ #package-header ul.links li:first-of-type {+ padding-left: 1em;+ }++ #package-header ul.links li:last-of-type {+ /*+ The last link of the menu should offer the same distance to the right+ as the #package-header enforces at the left.+ */+ padding-right: 1em;+ }++ #package-header .caption + ul.links {+ padding-top: 9px;+ }++ #module-header table.info {+ float: none;+ top: 0;+ margin: 0 auto;+ overflow: hidden;+ max-width: 80vw;+ }+}++/* @end */+++/* @group Fonts & Sizes */++/* Basic technique & IE workarounds from YUI 3+ For reasons, see:+ http://yui.yahooapis.com/3.1.1/build/cssfonts/fonts.css+ */++ body, button {+ font: 400 14px/1.4 'PT Sans',+ /* Fallback Font Stack */+ -apple-system,+ BlinkMacSystemFont,+ 'Segoe UI',+ Roboto,+ Oxygen-Sans,+ Cantarell,+ 'Helvetica Neue',+ sans-serif;+ *font-size: medium; /* for IE */+ *font:x-small; /* for IE in quirks mode */+ }++h1 { font-size: 146.5%; /* 19pt */ }+h2 { font-size: 131%; /* 17pt */ }+h3 { font-size: 116%; /* 15pt */ }+h4 { font-size: 100%; /* 13pt */ }+h5 { font-size: 100%; /* 13pt */ }++table {+ font-size:inherit;+ font:100%;+}++pre, code, kbd, samp, tt, .src {+ font-family:monospace;+}++.links, .link {+ font-size: 85%; /* 11pt */+}++#module-header .caption {+ font-size: 182%; /* 24pt */+}++#module-header .caption sup {+ font-size: 80%;+ font-weight: normal;+}++#package-header #page-menu a:link, #package-header #page-menu a:visited { color: white; }+++.info {+ font-size: 90%;+}+++/* @end */++/* @group Common */++.caption, h1, h2, h3, h4, h5, h6, summary {+ font-weight: bold;+ color: #5E5184;+ margin: 1.5em 0 1em 0;+}+++* + h1, * + h2, * + h3, * + h4, * + h5, * + h6 {+ margin-top: 2em;+}++h1 + h2, h2 + h3, h3 + h4, h4 + h5, h5 + h6 {+ margin-top: inherit;+}++ul li + li {+ margin-top: 0.2rem;+}++ul + p {+ margin-top: 0.93em;+}++p + ul {+ margin-top: 0.5em;+}++p {+ margin-top: 0.7rem;+}++ul, ol {+ margin: 0.8em 0 0.8em 2em;+}++ul.links {+ list-style: none;+ text-align: left;+ font-size: 0.95em;+}++#package-header ul.links, #package-header ul.links button {+ font-size: 1rem;+}++ul.links li {+ display: inline;+ white-space: nowrap;+ padding: 0;+}++ul.links > li + li:before {+ content: '\00B7';+}++ul.links li a {+ padding: 0.2em 0.5em;+}++.hide { display: none; }+.show { display: inherit; }+.clear { clear: both; }++.collapser:before, .expander:before, .noexpander:before {+ font-size: 1.2em;+ color: #9C5791;+ display: inline-block;+ padding-right: 7px;+}++.collapser:before {+ content: '▿';+}+.expander:before {+ content: '▹';+}+.noexpander:before {+ content: '▿';+ visibility: hidden;+}++.collapser, .expander {+ cursor: pointer;+}++.instance.collapser, .instance.expander {+ margin-left: 0px;+ background-position: left center;+ min-width: 9px;+ min-height: 9px;+}++summary {+ cursor: pointer;+ outline: none;+}++pre {+ padding: 0.5rem 1rem;+ margin: 1em 0 0 0;+ background-color: #f7f7f7;+ overflow: auto;+ border: 1px solid #ddd;+ border-radius: 0.3em;+}++pre + p {+ margin-top: 1em;+}++pre + pre {+ margin-top: 0.5em;+}++blockquote {+ border-left: 3px solid #c7a5d3;+ background-color: #eee4f1;+ margin: 0.5em;+ padding: 0.0005em 0.3em 0.5em 0.5em;+}++.src {+ background: #f2f2f2;+ padding: 0.2em 0.5em;+}++.keyword { font-weight: normal; }+.def { font-weight: bold; }++@media print {+ #footer { display: none; }+}++/* @end */++/* @group Page Structure */++#content {+ margin: 3em auto 6em auto;+ padding: 0;+}++#package-header {+ background: #5E5184;+ border-bottom: 5px solid rgba(69, 59, 97, 0.5);+ color: #ddd;+ position: relative;+ font-size: 1.2em;+ text-align: left;+ margin: 0 auto;+}++#package-header .caption {+ color: white;+ font-style: normal;+ font-size: 1rem;+ font-weight: bold;+}++#module-header .caption {+ font-weight: bold;+ border-bottom: 1px solid #ddd;+}++table.info {+ float: right;+ padding: 0.5em 1em;+ border: 1px solid #ddd;+ color: rgb(78,98,114);+ background-color: #fff;+ max-width: 60%;+ border-spacing: 0;+ position: relative;+ top: -0.78em;+ margin: 0 0 0 2em;+}++.info th {+ padding: 0 1em 0 0;+ text-align: right;+}++#style-menu li {+ display: block;+ border-style: none;+ list-style-type: none;+}++#footer {+ background: #ededed;+ border-top: 1px solid #aaa;+ padding: 0.5em 0;+ color: #222;+ text-align: center;+ width: 100%;+ height: 3em;+ margin-top: 3em;+ position: relative;+ clear: both;+}++/* @end */++/* @group Front Matter */++#synopsis .caption,+#contents-list .caption {+ font-size: 1rem;+}++#synopsis, #table-of-contents {+ font-size: 16px;+}++#contents-list {+ background: #f4f4f4;+ padding: 1em;+ margin: 0;+}++#contents-list .caption {+ text-align: left;+ margin: 0;+}++#contents-list ul {+ list-style: none;+ margin: 0;+ margin-top: 10px;+ font-size: 14px;+}++#contents-list ul ul {+ margin-left: 1.5em;+}++#description .caption {+ display: none;+}++#synopsis summary {+ display: block;+ float: right;+ width: 29px;+ color: rgba(255,255,255,0);+ height: 110px;+ margin: 0;+ font-size: 1px;+ padding: 0;+ background: url(synopsis.png) no-repeat 0px -8px;+}++#synopsis details[open] > summary {+ background: url(synopsis.png) no-repeat -75px -8px;+}++#synopsis details:not([open]) > ul {+ visibility: hidden;+}++#synopsis ul {+ height: 100%;+ overflow: auto;+ padding: 0.5em;+ margin: 0;+}++#synopsis ul ul {+ overflow: hidden;+}++#synopsis ul,+#synopsis ul li.src {+ background-color: rgb(250,247,224);+ white-space: nowrap;+ list-style: none;+ margin-left: 0;+}++#interface td.src {+ white-space: nowrap;+}++/* @end */++/* @group Main Content */++#interface div.top + div.top {+ margin-top: 1.5em;+}++#interface p + div.top,+#interface h1 + div.top,+#interface h2 + div.top,+#interface h3 + div.top,+#interface h4 + div.top,+#interface h5 + div.top {+ margin-top: 1em;+}+#interface .src .selflink,+#interface .src .link {+ float: right;+ color: #888;+ padding: 0 7px;+ -moz-user-select: none;+ font-weight: bold;+ line-height: 30px;+}+#interface .src .selflink {+ margin: 0 -0.5em 0 0.5em;+}++#interface span.fixity {+ color: #919191;+ border-left: 1px solid #919191;+ padding: 0.2em 0.5em 0.2em 0.5em;+ margin: 0 -1em 0 1em;+}++#interface span.rightedge {+ border-left: 1px solid #919191;+ padding: 0.2em 0 0.2em 0;+ margin: 0 0 0 1em;+}++#interface table { border-spacing: 2px; }+#interface td {+ vertical-align: top;+ padding-left: 0.5em;+}++#interface td.doc p {+ margin: 0;+}+#interface td.doc p + p {+ margin-top: 0.8em;+}++.doc table {+ border-collapse: collapse;+ border-spacing: 0px;+}++.doc th,+.doc td {+ padding: 5px;+ border: 1px solid #ddd;+}++.doc th {+ background-color: #f0f0f0;+}++.clearfix:after {+ clear: both;+ content: " ";+ display: block;+ height: 0;+ visibility: hidden;+}++.subs, .top > .doc, .subs > .doc {+ padding-left: 1em;+ border-left: 1px solid gainsboro;+ margin-bottom: 1em;+}++.top .subs {+ margin-bottom: 0.6em;+}++.subs.fields ul {+ list-style: none;+ display: table;+ margin: 0;+}++.subs.fields ul li {+ display: table-row;+}++.subs ul li dfn {+ display: table-cell;+ font-style: normal;+ font-weight: bold;+ margin: 1px 0;+ white-space: nowrap;+}++.subs ul li > .doc {+ display: table-cell;+ padding-left: 0.5em;+ margin-bottom: 0.5em;+}++.subs ul li > .doc p {+ margin: 0;+}++.subs .subs p.src {+ border: none;+ background-color: #f8f8f8;+}++.subs .subs .caption {+ margin-top: 1em ;+ margin-bottom: 0px;+}++.subs p.caption {+ margin-top: 0;+}++.subs .subs .caption + .src {+ margin: 0px;+ margin-top: 8px;+}++.subs .subs .src + .src {+ margin: 7px 0 0 0;+}++/* Render short-style data instances */+.inst ul {+ height: 100%;+ padding: 0.5em;+ margin: 0;+}++.inst, .inst li {+ list-style: none;+ margin-left: 1em;+}++/* Workaround for bug in Firefox (issue #384) */+.inst-left {+ float: left;+}++.top p.src {+ border-bottom: 3px solid #e5e5e5;+ line-height: 2rem;+ margin-bottom: 1em;+}++.warning {+ color: red;+}++.arguments {+ margin-top: -0.4em;+}+.arguments .caption {+ display: none;+}++.fields { padding-left: 1em; }++.fields .caption { display: none; }++.fields p { margin: 0 0; }++/* this seems bulky to me+.methods, .constructors {+ background: #f8f8f8;+ border: 1px solid #eee;+}+*/++/* @end */++/* @group Auxillary Pages */+++.extension-list {+ list-style-type: none;+ margin-left: 0;+}++#mini {+ margin: 0 auto;+ padding: 0 1em 1em;+}++#mini > * {+ font-size: 93%; /* 12pt */+}++#mini #module-list .caption,+#mini #module-header .caption {+ font-size: 125%; /* 15pt */+}++#mini #interface h1,+#mini #interface h2,+#mini #interface h3,+#mini #interface h4 {+ font-size: 109%; /* 13pt */+ margin: 1em 0 0;+}++#mini #interface .top,+#mini #interface .src {+ margin: 0;+}++#mini #module-list ul {+ list-style: none;+ margin: 0;+}++#alphabet ul {+ list-style: none;+ padding: 0;+ margin: 0.5em 0 0;+ text-align: center;+}++#alphabet li {+ display: inline;+ margin: 0 0.25em;+}++#alphabet a {+ font-weight: bold;+}++#index .caption,+#module-list .caption { font-size: 131%; /* 17pt */ }++#index table {+ margin-left: 2em;+}++#index .src {+ font-weight: bold;+}+#index .alt {+ font-size: 77%; /* 10pt */+ font-style: italic;+ padding-left: 2em;+}++#index td + td {+ padding-left: 1em;+}++#module-list ul {+ list-style: none;+ margin: 0 0 0 2em;+}++#module-list li {+ clear: right;+}++#module-list span.collapser,+#module-list span.expander {+ background-position: 0 0.3em;+}++#module-list .package {+ float: right;+}++:target {+ background: -webkit-linear-gradient(top, transparent 0%, transparent 65%, #fbf36d 60%, #fbf36d 100%);+ background: -moz-linear-gradient(top, transparent 0%, transparent 65%, #fbf36d 60%, #fbf36d 100%);+ background: -o-linear-gradient(top, transparent 0%, transparent 65%, #fbf36d 60%, #fbf36d 100%);+ background: -ms-linear-gradient(top, transparent 0%, transparent 65%, #fbf36d 60%, #fbf36d 100%);+ background: linear-gradient(to bottom, transparent 0%, transparent 65%, #fbf36d 60%, #fbf36d 100%);+}++:target:hover {+ background: -webkit-linear-gradient(top, transparent 0%, transparent 0%, #fbf36d 0%, #fbf36d 100%);+ background: -moz-linear-gradient(top, transparent 0%, transparent 0%, #fbf36d 0%, #fbf36d 100%);+ background: -o-linear-gradient(top, transparent 0%, transparent 0%, #fbf36d 0%, #fbf36d 100%);+ background: -ms-linear-gradient(top, transparent 0%, transparent 0%, #fbf36d 0%, #fbf36d 100%);+ background: linear-gradient(to bottom, transparent 0%, transparent 0%, #fbf36d 0%, #fbf36d 100%);+}++/* @end */++/* @group Dropdown menus */++#preferences-menu, #style-menu {+ width: 25em;+ overflow-y: auto;+}++/* @end */
+ resources/html/Linuwial.std-theme/synopsis.png view
binary file changed (absent → 11327 bytes)
− resources/html/Ocean.std-theme/hslogo-16.png
binary file changed (1684 → absent bytes)
− resources/html/Ocean.std-theme/minus.gif
binary file changed (56 → absent bytes)
− resources/html/Ocean.std-theme/ocean.css
@@ -1,612 +0,0 @@-/* @group Fundamentals */--* { margin: 0; padding: 0 }--/* Is this portable? */-html {- background-color: white;- width: 100%;- height: 100%;-}--body {- background: white;- color: black;- text-align: left;- min-height: 100%;- position: relative;-}--p {- margin: 0.8em 0;-}--ul, ol {- margin: 0.8em 0 0.8em 2em;-}--dl {- margin: 0.8em 0;-}--dt {- font-weight: bold;-}-dd {- margin-left: 2em;-}--a { text-decoration: none; }-a[href]:link { color: rgb(196,69,29); }-a[href]:visited { color: rgb(171,105,84); }-a[href]:hover { text-decoration:underline; }--a[href].def:link, a[href].def:visited { color: black; }-a[href].def:hover { color: rgb(78, 98, 114); }--/* @end */--/* @group Fonts & Sizes */--/* Basic technique & IE workarounds from YUI 3- For reasons, see:- http://yui.yahooapis.com/3.1.1/build/cssfonts/fonts.css- */--body {- font:13px/1.4 sans-serif;- *font-size:small; /* for IE */- *font:x-small; /* for IE in quirks mode */-}--h1 { font-size: 146.5%; /* 19pt */ }-h2 { font-size: 131%; /* 17pt */ }-h3 { font-size: 116%; /* 15pt */ }-h4 { font-size: 100%; /* 13pt */ }-h5 { font-size: 100%; /* 13pt */ }--select, input, button, textarea {- font:99% sans-serif;-}--table {- font-size:inherit;- font:100%;-}--pre, code, kbd, samp, tt, .src {- font-family:monospace;- *font-size:108%;- line-height: 124%;-}--.links, .link {- font-size: 85%; /* 11pt */-}--#module-header .caption {- font-size: 182%; /* 24pt */-}--.info {- font-size: 85%; /* 11pt */-}--#table-of-contents, #synopsis {- /* font-size: 85%; /* 11pt */-}---/* @end */--/* @group Common */--.caption, h1, h2, h3, h4, h5, h6 {- font-weight: bold;- color: rgb(78,98,114);- margin: 0.8em 0 0.4em;-}--* + h1, * + h2, * + h3, * + h4, * + h5, * + h6 {- margin-top: 2em;-}--h1 + h2, h2 + h3, h3 + h4, h4 + h5, h5 + h6 {- margin-top: inherit;-}--ul.links {- list-style: none;- text-align: left;- float: right;- display: inline-table;- margin: 0 0 0 1em;-}--ul.links li {- display: inline;- border-left: 1px solid #d5d5d5;- white-space: nowrap;- padding: 0;-}--ul.links li a {- padding: 0.2em 0.5em;-}--.hide { display: none; }-.show { display: inherit; }-.clear { clear: both; }--.collapser {- background-image: url(minus.gif);- background-repeat: no-repeat;-}-.expander {- background-image: url(plus.gif);- background-repeat: no-repeat;-}-.collapser, .expander {- padding-left: 14px;- margin-left: -14px;- cursor: pointer;-}-p.caption.collapser,-p.caption.expander {- background-position: 0 0.4em;-}--.instance.collapser, .instance.expander {- margin-left: 0px;- background-position: left center;- min-width: 9px;- min-height: 9px;-}---pre {- padding: 0.25em;- margin: 0.8em 0;- background: rgb(229,237,244);- overflow: auto;- border-bottom: 0.25em solid white;- /* white border adds some space below the box to compensate- for visual extra space that paragraphs have between baseline- and the bounding box */-}--.src {- background: #f0f0f0;- padding: 0.2em 0.5em;-}--.keyword { font-weight: normal; }-.def { font-weight: bold; }--@media print {- #footer { display: none; }-}--/* @end */--/* @group Page Structure */--#content {- margin: 0 auto;- padding: 0 2em 6em;-}--#package-header {- background: rgb(41,56,69);- border-top: 5px solid rgb(78,98,114);- color: #ddd;- padding: 0.2em;- position: relative;- text-align: left;-}--#package-header .caption {- background: url(hslogo-16.png) no-repeat 0em;- color: white;- margin: 0 2em;- font-weight: normal;- font-style: normal;- padding-left: 2em;-}--#package-header a:link, #package-header a:visited { color: white; }-#package-header a:hover { background: rgb(78,98,114); }--#module-header .caption {- color: rgb(78,98,114);- font-weight: bold;- border-bottom: 1px solid #ddd;-}--table.info {- float: right;- padding: 0.5em 1em;- border: 1px solid #ddd;- color: rgb(78,98,114);- background-color: #fff;- max-width: 40%;- border-spacing: 0;- position: relative;- top: -0.5em;- margin: 0 0 0 2em;-}--.info th {- padding: 0 1em 0 0;-}--div#style-menu-holder {- position: relative;- z-index: 2;- display: inline;-}--#style-menu {- position: absolute;- z-index: 1;- overflow: visible;- background: #374c5e;- margin: 0;- text-align: center;- right: 0;- padding: 0;- top: 1.25em;-}--#style-menu li {- display: list-item;- border-style: none;- margin: 0;- padding: 0;- color: #000;- list-style-type: none;-}--#style-menu li + li {- border-top: 1px solid #919191;-}--#style-menu a {- width: 6em;- padding: 3px;- display: block;-}--#footer {- background: #ddd;- border-top: 1px solid #aaa;- padding: 0.5em 0;- color: #666;- text-align: center;- position: absolute;- bottom: 0;- width: 100%;- height: 3em;-}--/* @end */--/* @group Front Matter */--#table-of-contents {- float: right;- clear: right;- background: #faf9dc;- border: 1px solid #d8d7ad;- padding: 0.5em 1em;- max-width: 20em;- margin: 0.5em 0 1em 1em;-}--#table-of-contents .caption {- text-align: center;- margin: 0;-}--#table-of-contents ul {- list-style: none;- margin: 0;-}--#table-of-contents ul ul {- margin-left: 2em;-}--#description .caption {- display: none;-}--#synopsis {- display: none;-}--.no-frame #synopsis {- display: block;- position: fixed;- right: 0;- height: 80%;- top: 10%;- padding: 0;- max-width: 75%;- /* Ensure that synopsis covers everything (including MathJAX markup) */- z-index: 1;-}--#synopsis .caption {- float: left;- width: 29px;- color: rgba(255,255,255,0);- height: 110px;- margin: 0;- font-size: 1px;- padding: 0;-}--#synopsis p.caption.collapser {- background: url(synopsis.png) no-repeat -64px -8px;-}--#synopsis p.caption.expander {- background: url(synopsis.png) no-repeat 0px -8px;-}--#synopsis ul {- height: 100%;- overflow: auto;- padding: 0.5em;- margin: 0;-}--#synopsis ul ul {- overflow: hidden;-}--#synopsis ul,-#synopsis ul li.src {- background-color: #faf9dc;- white-space: nowrap;- list-style: none;- margin-left: 0;-}--/* @end */--/* @group Main Content */--#interface div.top { margin: 2em 0; }-#interface h1 + div.top,-#interface h2 + div.top,-#interface h3 + div.top,-#interface h4 + div.top,-#interface h5 + div.top {- margin-top: 1em;-}-#interface .src .selflink,-#interface .src .link {- float: right;- color: #919191;- background: #f0f0f0;- padding: 0 0.5em 0.2em;- margin: 0 -0.5em 0 0;-}-#interface .src .selflink {- border-left: 1px solid #919191;- margin: 0 -0.5em 0 0.5em;-}--#interface span.fixity {- color: #919191;- border-left: 1px solid #919191;- padding: 0.2em 0.5em 0.2em 0.5em;- margin: 0 -1em 0 1em;-}--#interface span.rightedge {- border-left: 1px solid #919191;- padding: 0.2em 0 0.2em 0;- margin: 0 0 0 1em;-}--#interface table { border-spacing: 2px; }-#interface td {- vertical-align: top;- padding-left: 0.5em;-}-#interface td.src {- white-space: nowrap;-}-#interface td.doc p {- margin: 0;-}-#interface td.doc p + p {- margin-top: 0.8em;-}--.clearfix:after {- clear: both;- content: " ";- display: block;- height: 0;- visibility: hidden;-}--.subs ul {- list-style: none;- display: table;- margin: 0;-}--.subs ul li {- display: table-row;-}--.subs ul li dfn {- display: table-cell;- font-style: normal;- font-weight: bold;- margin: 1px 0;- white-space: nowrap;-}--.subs ul li > .doc {- display: table-cell;- padding-left: 0.5em;- margin-bottom: 0.5em;-}--.subs ul li > .doc p {- margin: 0;-}--/* Render short-style data instances */-.inst ul {- height: 100%;- padding: 0.5em;- margin: 0;-}--.inst, .inst li {- list-style: none;- margin-left: 1em;-}--/* Workaround for bug in Firefox (issue #384) */-.inst-left {- float: left;-}--.top p.src {- border-top: 1px solid #ccc;-}--.subs, .doc {- /* use this selector for one level of indent */- padding-left: 2em;-}--.warning {- color: red;-}--.arguments {- margin-top: -0.4em;-}-.arguments .caption {- display: none;-}--.fields { padding-left: 1em; }--.fields .caption { display: none; }--.fields p { margin: 0 0; }--/* this seems bulky to me-.methods, .constructors {- background: #f8f8f8;- border: 1px solid #eee;-}-*/--/* @end */--/* @group Auxillary Pages */---.extension-list {- list-style-type: none;- margin-left: 0;-}--#mini {- margin: 0 auto;- padding: 0 1em 1em;-}--#mini > * {- font-size: 93%; /* 12pt */-}--#mini #module-list .caption,-#mini #module-header .caption {- font-size: 125%; /* 15pt */-}--#mini #interface h1,-#mini #interface h2,-#mini #interface h3,-#mini #interface h4 {- font-size: 109%; /* 13pt */- margin: 1em 0 0;-}--#mini #interface .top,-#mini #interface .src {- margin: 0;-}--#mini #module-list ul {- list-style: none;- margin: 0;-}--#alphabet ul {- list-style: none;- padding: 0;- margin: 0.5em 0 0;- text-align: center;-}--#alphabet li {- display: inline;- margin: 0 0.25em;-}--#alphabet a {- font-weight: bold;-}--#index .caption,-#module-list .caption { font-size: 131%; /* 17pt */ }--#index table {- margin-left: 2em;-}--#index .src {- font-weight: bold;-}-#index .alt {- font-size: 77%; /* 10pt */- font-style: italic;- padding-left: 2em;-}--#index td + td {- padding-left: 1em;-}--#module-list ul {- list-style: none;- margin: 0 0 0 2em;-}--#module-list li {- clear: right;-}--#module-list span.collapser,-#module-list span.expander {- background-position: 0 0.3em;-}--#module-list .package {- float: right;-}--/* @end */
− resources/html/Ocean.std-theme/plus.gif
binary file changed (59 → absent bytes)
− resources/html/Ocean.std-theme/synopsis.png
binary file changed (11327 → absent bytes)
+ resources/html/Ocean.theme/hslogo-16.png view
binary file changed (absent → 1684 bytes)
+ resources/html/Ocean.theme/minus.gif view
binary file changed (absent → 56 bytes)
+ resources/html/Ocean.theme/ocean.css view
@@ -0,0 +1,647 @@+/* @group Fundamentals */++* { margin: 0; padding: 0 }++/* Is this portable? */+html {+ background-color: white;+ width: 100%;+ height: 100%;+}++body {+ background: white;+ color: black;+ text-align: left;+ min-height: 100%;+ position: relative;+}++p {+ margin: 0.8em 0;+}++ul, ol {+ margin: 0.8em 0 0.8em 2em;+}++dl {+ margin: 0.8em 0;+}++dt {+ font-weight: bold;+}+dd {+ margin-left: 2em;+}++a { text-decoration: none; }+a[href]:link { color: rgb(196,69,29); }+a[href]:visited { color: rgb(171,105,84); }+a[href]:hover { text-decoration:underline; }++a[href].def:link, a[href].def:visited { color: black; }+a[href].def:hover { color: rgb(78, 98, 114); }++/* @end */++/* @group Show and hide with JS */++body.js-enabled .hide-when-js-enabled {+ display: none;+}++/* @end */++/* @group Fonts & Sizes */++/* Basic technique & IE workarounds from YUI 3+ For reasons, see:+ http://yui.yahooapis.com/3.1.1/build/cssfonts/fonts.css+ */++body {+ font:13px/1.4 sans-serif;+ *font-size:small; /* for IE */+ *font:x-small; /* for IE in quirks mode */+}++h1 { font-size: 146.5%; /* 19pt */ }+h2 { font-size: 131%; /* 17pt */ }+h3 { font-size: 116%; /* 15pt */ }+h4 { font-size: 100%; /* 13pt */ }+h5 { font-size: 100%; /* 13pt */ }++select, input, button, textarea {+ font:99% sans-serif;+}++table {+ font-size:inherit;+ font:100%;+}++pre, code, kbd, samp, tt, .src {+ font-family:monospace;+ *font-size:108%;+ line-height: 124%;+}++.links, .link {+ font-size: 85%; /* 11pt */+}++#module-header .caption {+ font-size: 182%; /* 24pt */+}++#module-header .caption sup {+ font-size: 70%;+ font-weight: normal;+}++.info {+ font-size: 85%; /* 11pt */+}++#table-of-contents, #synopsis {+ /* font-size: 85%; /* 11pt */+}+++/* @end */++/* @group Common */++.caption, h1, h2, h3, h4, h5, h6, summary {+ font-weight: bold;+ color: rgb(78,98,114);+ margin: 0.8em 0 0.4em;+}++* + h1, * + h2, * + h3, * + h4, * + h5, * + h6 {+ margin-top: 2em;+}++h1 + h2, h2 + h3, h3 + h4, h4 + h5, h5 + h6 {+ margin-top: inherit;+}++ul.links {+ list-style: none;+ text-align: left;+ float: right;+ display: inline-table;+ margin: 0 0 0 1em;+}++ul.links li {+ display: inline;+ border-left: 1px solid #d5d5d5;+ white-space: nowrap;+ padding: 0;+}++ul.links li a {+ padding: 0.2em 0.5em;+}++.hide { display: none; }+.show { display: inherit; }+.clear { clear: both; }++.collapser {+ background-image: url(minus.gif);+ background-repeat: no-repeat;+}+.expander {+ background-image: url(plus.gif);+ background-repeat: no-repeat;+}+.collapser, .expander {+ padding-left: 14px;+ margin-left: -14px;+ cursor: pointer;+}+p.caption.collapser,+p.caption.expander {+ background-position: 0 0.4em;+}++.instance.collapser, .instance.expander {+ margin-left: 0px;+ background-position: left center;+ min-width: 9px;+ min-height: 9px;+}++summary {+ cursor: pointer;+ outline: none;+ list-style-image: url(plus.gif);+ list-style-position: outside;+}++details[open] > summary {+ list-style-image: url(minus.gif);+}++pre {+ padding: 0.25em;+ margin: 0.8em 0;+ background: rgb(229,237,244);+ overflow: auto;+ border-bottom: 0.25em solid white;+ /* white border adds some space below the box to compensate+ for visual extra space that paragraphs have between baseline+ and the bounding box */+}++.src {+ background: #f0f0f0;+ padding: 0.2em 0.5em;+}++.keyword { font-weight: normal; }+.def { font-weight: bold; }++@media print {+ #footer { display: none; }+}++/* @end */++/* @group Page Structure */++#content {+ margin: 0 auto;+ padding: 0 2em 6em;+}++#package-header {+ background: rgb(41,56,69);+ border-top: 5px solid rgb(78,98,114);+ color: #ddd;+ padding: 0.2em;+ position: relative;+ text-align: left;+}++#package-header .caption {+ background: url(hslogo-16.png) no-repeat 0em;+ color: white;+ margin: 0 2em;+ font-weight: normal;+ font-style: normal;+ padding-left: 2em;+}++#package-header a:link, #package-header a:visited { color: white; }+#package-header a:hover { background: rgb(78,98,114); }++#module-header .caption {+ color: rgb(78,98,114);+ font-weight: bold;+ border-bottom: 1px solid #ddd;+}++table.info {+ float: right;+ padding: 0.5em 1em;+ border: 1px solid #ddd;+ color: rgb(78,98,114);+ background-color: #fff;+ max-width: 40%;+ border-spacing: 0;+ position: relative;+ top: -0.5em;+ margin: 0 0 0 2em;+}++.info th {+ padding: 0 1em 0 0;+}++div#style-menu-holder {+ position: relative;+ z-index: 2;+ display: inline;+}++#style-menu {+ position: absolute;+ z-index: 1;+ overflow: visible;+ background: #374c5e;+ margin: 0;+ text-align: center;+ right: 0;+ padding: 0;+ top: 1.25em;+}++#style-menu li {+ display: list-item;+ border-style: none;+ margin: 0;+ padding: 0;+ color: #000;+ list-style-type: none;+}++#style-menu li + li {+ border-top: 1px solid #919191;+}++#style-menu a {+ width: 6em;+ padding: 3px;+ display: block;+}++#footer {+ background: #ddd;+ border-top: 1px solid #aaa;+ padding: 0.5em 0;+ color: #666;+ text-align: center;+ position: absolute;+ bottom: 0;+ width: 100%;+ height: 3em;+}++/* @end */++/* @group Front Matter */++#table-of-contents {+ float: right;+ clear: right;+ background: #faf9dc;+ border: 1px solid #d8d7ad;+ padding: 0.5em 1em;+ max-width: 20em;+ margin: 0.5em 0 1em 1em;+}++#table-of-contents .caption {+ text-align: center;+ margin: 0;+}++#table-of-contents ul {+ list-style: none;+ margin: 0;+}++#table-of-contents ul ul {+ margin-left: 2em;+}++#description .caption {+ display: none;+}++#synopsis {+ display: block;+ position: fixed;+ right: 0;+ height: 80%;+ top: 10%;+ padding: 0;+ max-width: 75%;+ /* Ensure that synopsis covers everything (including MathJAX markup) */+ z-index: 1;+}++#synopsis summary {+ display: block;+ float: left;+ width: 29px;+ color: rgba(255,255,255,0);+ height: 110px;+ margin: 0;+ font-size: 1px;+ padding: 0;+ background: url(synopsis.png) no-repeat 0px -8px;+}++#synopsis details[open] > summary {+ background: url(synopsis.png) no-repeat -64px -8px;+}++#synopsis ul {+ height: 100%;+ overflow: auto;+ padding: 0.5em;+ margin: 0;+}++#synopsis ul ul {+ overflow: hidden;+}++#synopsis ul,+#synopsis ul li.src {+ background-color: #faf9dc;+ white-space: nowrap;+ list-style: none;+ margin-left: 0;+}++/* @end */++/* @group Main Content */++#interface div.top { margin: 2em 0; }+#interface h1 + div.top,+#interface h2 + div.top,+#interface h3 + div.top,+#interface h4 + div.top,+#interface h5 + div.top {+ margin-top: 1em;+}+#interface .src .selflink,+#interface .src .link {+ float: right;+ color: #919191;+ background: #f0f0f0;+ padding: 0 0.5em 0.2em;+ margin: 0 -0.5em 0 0;+ -moz-user-select: none;+}+#interface .src .selflink {+ border-left: 1px solid #919191;+ margin: 0 -0.5em 0 0.5em;+}++#interface span.fixity {+ color: #919191;+ border-left: 1px solid #919191;+ padding: 0.2em 0.5em 0.2em 0.5em;+ margin: 0 -1em 0 1em;+}++#interface span.rightedge {+ border-left: 1px solid #919191;+ padding: 0.2em 0 0.2em 0;+ margin: 0 0 0 1em;+}++#interface table { border-spacing: 2px; }+#interface td {+ vertical-align: top;+ padding-left: 0.5em;+}++#interface td.doc p {+ margin: 0;+}+#interface td.doc p + p {+ margin-top: 0.8em;+}++.doc table {+ border-collapse: collapse;+ border-spacing: 0px;+}++.doc th,+.doc td {+ padding: 5px;+ border: 1px solid #ddd;+}++.doc th {+ background-color: #f0f0f0;+}++.clearfix:after {+ clear: both;+ content: " ";+ display: block;+ height: 0;+ visibility: hidden;+}++.subs.fields ul {+ list-style: none;+ display: table;+ margin: 0;+}++.subs.fields ul li {+ display: table-row;+}++.subs ul li dfn {+ display: table-cell;+ font-style: normal;+ font-weight: bold;+ margin: 1px 0;+ white-space: nowrap;+}++.subs ul li > .doc {+ display: table-cell;+ padding-left: 0.5em;+ margin-bottom: 0.5em;+}++.subs ul li > .doc p {+ margin: 0;+}++/* Render short-style data instances */+.inst ul {+ height: 100%;+ padding: 0.5em;+ margin: 0;+}++.inst, .inst li {+ list-style: none;+ margin-left: 1em;+}++/* Workaround for bug in Firefox (issue #384) */+.inst-left {+ float: left;+}++.top p.src {+ border-top: 1px solid #ccc;+}++.subs, .doc {+ /* use this selector for one level of indent */+ padding-left: 2em;+}++.warning {+ color: red;+}++.arguments {+ margin-top: -0.4em;+}+.arguments .caption {+ display: none;+}++.fields { padding-left: 1em; }++.fields .caption { display: none; }++.fields p { margin: 0 0; }++/* this seems bulky to me+.methods, .constructors {+ background: #f8f8f8;+ border: 1px solid #eee;+}+*/++/* @end */++/* @group Auxillary Pages */+++.extension-list {+ list-style-type: none;+ margin-left: 0;+}++#mini {+ margin: 0 auto;+ padding: 0 1em 1em;+}++#mini > * {+ font-size: 93%; /* 12pt */+}++#mini #module-list .caption,+#mini #module-header .caption {+ font-size: 125%; /* 15pt */+}++#mini #interface h1,+#mini #interface h2,+#mini #interface h3,+#mini #interface h4 {+ font-size: 109%; /* 13pt */+ margin: 1em 0 0;+}++#mini #interface .top,+#mini #interface .src {+ margin: 0;+}++#mini #module-list ul {+ list-style: none;+ margin: 0;+}++#alphabet ul {+ list-style: none;+ padding: 0;+ margin: 0.5em 0 0;+ text-align: center;+}++#alphabet li {+ display: inline;+ margin: 0 0.25em;+}++#alphabet a {+ font-weight: bold;+}++#index .caption,+#module-list .caption { font-size: 131%; /* 17pt */ }++#index table {+ margin-left: 2em;+}++#index .src {+ font-weight: bold;+}+#index .alt {+ font-size: 77%; /* 10pt */+ font-style: italic;+ padding-left: 2em;+}++#index td + td {+ padding-left: 1em;+}++#module-list ul {+ list-style: none;+ margin: 0 0 0 2em;+}++#module-list li {+ clear: right;+}++#module-list span.collapser,+#module-list span.expander {+ background-position: 0 0.3em;+}++#module-list .package {+ float: right;+}++:target {+ background-color: #ffff00;+}++/* @end */
+ resources/html/Ocean.theme/plus.gif view
binary file changed (absent → 59 bytes)
+ resources/html/Ocean.theme/synopsis.png view
binary file changed (absent → 11327 bytes)
+ resources/html/haddock-bundle.min.js view
@@ -0,0 +1,2 @@+!function i(s,a,l){function c(t,e){if(!a[t]){if(!s[t]){var n="function"==typeof require&&require;if(!e&&n)return n(t,!0);if(u)return u(t,!0);var o=new Error("Cannot find module '"+t+"'");throw o.code="MODULE_NOT_FOUND",o}var r=a[t]={exports:{}};s[t][0].call(r.exports,function(e){return c(s[t][1][e]||e)},r,r.exports,i,s,a,l)}return a[t].exports}for(var u="function"==typeof require&&require,e=0;e<l.length;e++)c(l[e]);return c}({1:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.setCookie=function(e,t){document.cookie=e+"="+encodeURIComponent(t)+";path=/;"},n.clearCookie=function(e){document.cookie=e+"=;path=/;expires=Thu, 01-Jan-1970 00:00:01 GMT;"},n.getCookie=function(e){for(var t=e+"=",n=document.cookie.split(";"),o=0;o<n.length;o++){for(var r=n[o];" "==r.charAt(0);)r=r.substring(1,r.length);if(0==r.indexOf(t))return decodeURIComponent(r.substring(t.length,r.length))}return null}},{}],2:[function(e,t,n){"use strict";var o,r=this&&this.__extends||(o=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])},function(e,t){function n(){this.constructor=e}o(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)});Object.defineProperty(n,"__esModule",{value:!0});var i,s,a=e("preact"),l=a.h,c=a.Component;(s=i||(i={}))[s.Closed=0]="Closed",s[s.Open=1]="Open";var u={defaultInstanceState:i.Open,rememberToggles:!0},d=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return r(t,e),t.prototype.render=function(t){return l("li",null,l("a",{href:"#",onClick:function(e){e.preventDefault(),t.onClick()}},t.title))},t}(c);function h(e){var t=document.querySelector("#page-menu"),n=document.createElement("li");t.insertBefore(n,t.firstChild),a.render(l(d,{onClick:e,title:"Instances"}),t,n)}var p=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return r(t,e),t.prototype.componentWillMount=function(){var t=this;document.addEventListener("mousedown",this.hide.bind(this)),document.addEventListener("keydown",function(e){t.state.isVisible&&"Escape"===e.key&&t.hide()})},t.prototype.hide=function(){this.setState({isVisible:!1})},t.prototype.show=function(){this.state.isVisible||this.setState({isVisible:!0})},t.prototype.toggleVisibility=function(){this.state.isVisible?this.hide():this.show()},t.prototype.componentDidMount=function(){this.props.showHideTrigger(this.toggleVisibility.bind(this))},t.prototype.render=function(e,t){return l("div",{id:"preferences",class:t.isVisible?"":"hidden"},l("div",{id:"preferences-menu",class:"dropdown-menu",onMouseDown:function(e){e.stopPropagation()}},l(b,null)))},t}(c);function f(){var e=JSON.stringify(u);try{localStorage.setItem("global",e)}catch(e){}}var v=!1;function g(){if(!v){v=!0;var e=localStorage.getItem("global");if(e)try{var t=JSON.parse(e);u.defaultInstanceState=t.defaultInstanceState,u.rememberToggles=t.rememberToggles}catch(e){if(!(e instanceof SyntaxError||e instanceof TypeError))throw e;localStorage.removeItem("global")}}}function m(t){return function(e){u.defaultInstanceState=t,A(),f(),E(),O()}}function y(e){var t=e.target.checked;u.rememberToggles=t,f(),E(),O()}function _(e){var t=document.getElementById("default-collapse-instances");null!==t&&(t.checked?m(i.Closed)(e):m(i.Open)(e))}function b(){return g(),l("div",null,l("div",null,l("button",{type:"button",onClick:j},"Expand All Instances"),l("button",{type:"button",onClick:P},"Collapse All Instances")),l("div",null,l("input",{type:"checkbox",id:"default-collapse-instances",name:"default-instance-state",checked:u.defaultInstanceState===i.Closed,onClick:_}),l("span",null,"Collapse All Instances By Default")),l("div",null,l("input",{type:"checkbox",id:"remember-toggles",name:"remember-toggles",checked:u.rememberToggles,onClick:y}),l("label",{for:"remember-toggles"},"Remember Manually Collapsed/Expanded Instances")))}var k={};function S(e){var t=k[e];if(null==t)throw new Error("could not find <details> element with id '"+e+"'");return t}function x(){return u.defaultInstanceState==i.Open}function w(e){for(var t=S(e.target.id),n=t.element.open,o=0,r=t.toggles;o<r.length;o++){var i=r[o];i.classList.contains("details-toggle-control")&&(i.classList.add(n?"collapser":"expander"),i.classList.remove(n?"expander":"collapser"))}}function C(e){var t=e.getAttribute("data-details-id");if(!t)throw new Error("element with class "+e+" has no 'data-details-id' attribute!");return t}function L(e){var t=S(C(e)).element;t.open=!t.open}var M="local-details-config:";function I(){return M+document.location.pathname}function E(){for(var e=[],t=0;t<localStorage.length;++t){var n=localStorage.key(t);null!==n&&n.startsWith(M)&&e.push(n)}e.forEach(function(e){localStorage.removeItem(e)})}function O(){if(u.rememberToggles){var e=Array.prototype.slice.call(document.getElementsByClassName("instances details-toggle details-toggle-control")),n=[];e.forEach(function(e){var t=C(e);document.getElementById(t).open!=x()&&n.push(t)});var t=JSON.stringify(n);try{localStorage.setItem(I(),t)}catch(e){}}}function A(){switch(u.defaultInstanceState){case i.Closed:N(!0);break;case i.Open:N(!1)}}function T(e){L(e.currentTarget),O()}function N(o){var e=document.getElementsByClassName("subs instances");[].forEach.call(e,function(e){var t=o?"collapser":"expander",n=e.getElementsByClassName("instances "+t)[0];n&&L(n)})}function P(){N(!0),O()}function j(){N(!1),O()}n.init=function(e){!function(){for(var e=0,t=Array.prototype.slice.call(document.getElementsByTagName("details"));e<t.length;e++){var n=t[e];"string"==typeof n.id&&0<n.id.length&&(k[n.id]={element:n,toggles:[]},n.addEventListener("toggle",w))}}(),Array.prototype.slice.call(document.getElementsByClassName("details-toggle")).forEach(function(e){var t=S(C(e));t.toggles.push(e),e.addEventListener("click",T),e.classList.contains("details-toggle-control")&&e.classList.add(t.element.open?"collapser":"expander")}),function(){if(g(),A(),u.rememberToggles){var e=localStorage.getItem(I());if(e)try{JSON.parse(e).forEach(function(e){S(e).element.open=!x()})}catch(e){if(!(e instanceof SyntaxError||e instanceof TypeError))throw e;localStorage.removeItem(I())}}}(),a.render(l(p,{showHideTrigger:e||h}),document.body)}},{preact:7}],3:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var o,r=e("./style-menu"),i=e("./details-helper"),s=e("./quick-jump");o=function(){document.body.classList.add("js-enabled"),r.init(),i.init();var e=document.getElementById("head"),t=".";null!==e&&(t=e.getAttribute("data-base-url")||"."),s.init(t)},"interactive"===document.readyState?o():document.addEventListener("readystatechange",function(){"interactive"===document.readyState&&o()})},{"./details-helper":2,"./quick-jump":4,"./style-menu":5}],4:[function(e,t,n){"use strict";var o,r=this&&this.__extends||(o=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])},function(e,t){function n(){this.constructor=e}o(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)});Object.defineProperty(n,"__esModule",{value:!0});var i=e("fuse.js"),s=e("preact"),a=s.h,l=s.Component;var c=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return r(t,e),t.prototype.render=function(t){return a("li",null,a("a",{href:"#",onClick:function(e){e.preventDefault(),t.onClick()}},t.title))},t}(l);function u(e,t){return t.length<=e?t:t.slice(0,e)}var d=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.linkIndex=0,e.focusPlease=!1,e.navigatedByKeyboard=!1,e}return r(e,t),e.prototype.componentWillMount=function(){var e,t,n,o,r=this;this.setState({searchString:"",isVisible:!1,expanded:{},activeLinkIndex:-1,moduleResults:[]}),e=this.props.baseUrl+"/doc-index.json",t=function(e){r.setState({fuse:new i(e,{threshold:.25,caseSensitive:!0,includeScore:!0,tokenize:!0,keys:[{name:"name",weight:.7},{name:"module",weight:.3}]}),moduleResults:[]})},n=function(e){console&&console.error("could not load 'doc-index.json' for searching",e),r.setState({failedLoading:!0})},(o=new XMLHttpRequest).onreadystatechange=function(){if(o.readyState===XMLHttpRequest.DONE)if(200===o.status){if(t)try{t(JSON.parse(o.responseText))}catch(e){n(o)}}else n&&n(o)},o.open("GET",e,!0),o.send(),document.addEventListener("mousedown",this.hide.bind(this)),document.addEventListener("keydown",function(e){r.state.isVisible&&("Escape"===e.key?r.hide():"ArrowUp"===e.key||"k"===e.key&&e.ctrlKey?(e.preventDefault(),r.navigateLinks(-1)):"ArrowDown"===e.key||"j"===e.key&&e.ctrlKey?(e.preventDefault(),r.navigateLinks(1)):"Enter"===e.key&&0<=r.state.activeLinkIndex&&r.followActiveLink()),"s"===e.key&&"input"!==e.target.tagName.toLowerCase()&&(e.preventDefault(),r.show())})},e.prototype.hide=function(){this.setState({isVisible:!1,searchString:""})},e.prototype.show=function(){this.state.isVisible||(this.focusPlease=!0,this.setState({isVisible:!0,activeLinkIndex:-1}))},e.prototype.toggleVisibility=function(){this.state.isVisible?this.hide():this.show()},e.prototype.navigateLinks=function(e){var t=Math.max(-1,Math.min(this.linkIndex-1,this.state.activeLinkIndex+e));this.navigatedByKeyboard=!0,this.setState({activeLinkIndex:t})},e.prototype.followActiveLink=function(){this.activeLinkAction&&this.activeLinkAction()},e.prototype.updateResults=function(){var e=this.input&&this.input.value||"",t=this.state.fuse.search(e),o={};t.forEach(function(e){var t=e.item.module;(o[t]||(o[t]=[])).push(e)});var r=[],n=function(e){var t=o[e],n=0;t.forEach(function(e){n+=1/e.score}),r.push({module:e,totalScore:1/n,items:t})};for(var i in o)n(i);r.sort(function(e,t){return e.totalScore-t.totalScore}),this.setState({searchString:e,isVisible:!0,moduleResults:r})},e.prototype.componentDidUpdate=function(){if(this.searchResults&&this.activeLink&&this.navigatedByKeyboard){var e=this.activeLink.getClientRects()[0],t=this.searchResults.getClientRects()[0].top;e.bottom>window.innerHeight?this.searchResults.scrollTop+=e.bottom-window.innerHeight+80:e.top<t&&(this.searchResults.scrollTop-=t-e.top+80)}this.focusPlease&&this.input&&this.input.focus(),this.navigatedByKeyboard=!1,this.focusPlease=!1},e.prototype.componentDidMount=function(){this.props.showHideTrigger(this.toggleVisibility.bind(this))},e.prototype.render=function(e,t){var r=this;if(t.failedLoading){var n="file:"==window.location.protocol;return a("div",{id:"search",class:t.isVisible?"":"hidden"},a("div",{id:"search-results"},a("p",{class:"error"},"Failed to load file 'doc-index.json' containing definitions in this package."),n?a("p",{class:"error"},"To use quick jump, load this page with HTTP (from a local static file web server) instead of using the ",a("code",null,"file://")," protocol. (For security reasons, it is not possible to fetch auxiliary files using JS in a HTML page opened with ",a("code",null,"file://"),".)"):[]))}this.linkIndex=0;var o=function(e){e.stopPropagation()},i=u(10,t.moduleResults).map(function(e){return r.renderResultsInModule(e)});return a("div",{id:"search",class:t.isVisible?"":"hidden"},a("div",{id:"search-form",onMouseDown:o},a("input",{placeholder:"Search in package by name",ref:function(e){r.input=e},onFocus:this.show.bind(this),onClick:this.show.bind(this),onInput:this.updateResults.bind(this)})),a("div",{id:"search-results",ref:function(e){r.searchResults=e},onMouseDown:o,onMouseOver:function(e){for(var t=e.target;t&&"function"==typeof t.getAttribute;){var n=t.getAttribute("data-link-index");if("string"==typeof n){var o=parseInt(n,10);r.setState({activeLinkIndex:o});break}t=t.parentNode}}},""===t.searchString?[a(f,null),a(p,null)]:0==i.length?a(v,{searchString:t.searchString}):a("ul",null,i)))},e.prototype.renderResultsInModule=function(e){var n=this,t=e.items,o=e.module,r=this.state.expanded[o]||t.length<=10,i=r?t:u(8,t);return a("li",{class:"search-module"},a("h4",null,o),a("ul",null,i.map(function(e){return t=e.item,a("li",{class:"search-result"},n.navigationLink(n.props.baseUrl+"/"+t.link,{},a(h,{html:t.display_html})));var t}),r?[]:a("li",{class:"more-results"},this.actionLink(function(){var e=Object.assign({},n.state.expanded);e[o]=!0,n.setState({expanded:e})},{},"show "+(t.length-i.length)+" more results from this module"))))},e.prototype.navigationLink=function(e,t){for(var n=this,o=[],r=2;r<arguments.length;r++)o[r-2]=arguments[r];var i=Object.assign({href:e,onClick:this.hide.bind(this)},t);return this.menuLink.apply(this,[i,function(){window.location.href=e,n.hide()}].concat(o))},e.prototype.actionLink=function(t,e){for(var n=[],o=2;o<arguments.length;o++)n[o-2]=arguments[o];var r=Object.assign({href:"#",onClick:function(e){e.preventDefault(),t()}},e);return this.menuLink.apply(this,[r,t].concat(n))},e.prototype.menuLink=function(e,t){for(var n=this,o=[],r=2;r<arguments.length;r++)o[r-2]=arguments[r];var i=this.linkIndex;i===this.state.activeLinkIndex&&(e.class=(e.class?e.class+" ":"")+"active-link",e.ref=function(e){e&&(n.activeLink=e)},this.activeLinkAction=t);var s=Object.assign({"data-link-index":i},e);return this.linkIndex+=1,a.apply(void 0,["a",s].concat(o))},e}(l),h=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return r(t,e),t.prototype.shouldComponentUpdate=function(e){return this.props.html!==e.html},t.prototype.render=function(e){return a("div",{dangerouslySetInnerHTML:{__html:e.html}})},t}(l);function p(){return a("table",{class:"keyboard-shortcuts"},a("tr",null,a("th",null,"Key"),a("th",null,"Shortcut")),a("tr",null,a("td",null,a("span",{class:"key"},"s")),a("td",null,"Open this search box")),a("tr",null,a("td",null,a("span",{class:"key"},"esc")),a("td",null,"Close this search box")),a("tr",null,a("td",null,a("span",{class:"key"},"↓"),",",a("span",{class:"key"},"ctrl")," + ",a("span",{class:"key"},"j")),a("td",null,"Move down in search results")),a("tr",null,a("td",null,a("span",{class:"key"},"↑"),",",a("span",{class:"key"},"ctrl")," + ",a("span",{class:"key"},"k")),a("td",null,"Move up in search results")),a("tr",null,a("td",null,a("span",{class:"key"},"↵")),a("td",null,"Go to active search result")))}function f(){return a("p",null,"You can find any exported type, constructor, class, function or pattern defined in this package by (approximate) name.")}function v(e){var t=[a("p",null,"Your search for '",e.searchString,"' produced the following list of results: ",a("code",null,"[]"),"."),a("p",null,a("code",null,"Nothing")," matches your query for '",e.searchString,"'."),a("p",null,a("code",null,"Left \"no matches for '",e.searchString,"'\" :: Either String (NonEmpty SearchResult)"))];return t[(e.searchString||"a").charCodeAt(0)%t.length]}function g(e,t){var n,o=document.getElementById("quick-jump-button");o&&s.render(a(d,{baseUrl:e||".",showHideTrigger:t||(n=o,function(e){var t=document.querySelector("#page-menu");s.render(a(c,{onClick:e,title:"Quick Jump"}),t,n)})}),document.body)}n.init=g,window.quickNav={init:g}},{"fuse.js":6,preact:7}],5:[function(e,t,n){"use strict";var o,r=this&&this.__extends||(o=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])},function(e,t){function n(){this.constructor=e}o(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)});Object.defineProperty(n,"__esModule",{value:!0});var i=e("./cookies"),s=e("preact"),a=s.h,l=s.Component;function c(){return Array.prototype.slice.call(document.getElementsByTagName("link")).filter(function(e){return-1!=e.rel.indexOf("style")&&e.title})}function u(e){for(var t=c(),n=null,o=0;o<t.length;o++){var r=t[o];r.disabled=!0,r.title==e&&(n=r)}n?(n.disabled=!1,i.setCookie("haddock-style",e)):(t[0].disabled=!1,i.clearCookie("haddock-style"))}var d=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return r(t,e),t.prototype.render=function(t){return a("li",null,a("a",{href:"#",onClick:function(e){e.preventDefault(),t.onClick()}},t.title))},t}(l);var h=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return r(t,e),t.prototype.componentWillMount=function(){var t=this;document.addEventListener("mousedown",this.hide.bind(this)),document.addEventListener("keydown",function(e){t.state.isVisible&&"Escape"===e.key&&t.hide()})},t.prototype.hide=function(){this.setState({isVisible:!1})},t.prototype.show=function(){this.state.isVisible||this.setState({isVisible:!0})},t.prototype.toggleVisibility=function(){this.state.isVisible?this.hide():this.show()},t.prototype.componentDidMount=function(){this.props.showHideTrigger(this.toggleVisibility.bind(this))},t.prototype.render=function(e,t){var n=this;return a("div",{id:"style",class:t.isVisible?"":"hidden"},a("div",{id:"style-menu",class:"dropdown-menu",onMouseDown:function(e){e.stopPropagation()}},e.styles.map(function(t){return a("button",{type:"button",onClick:function(e){n.hide(),u(t)}},t)})))},t}(l);n.init=function(e){var t,n=c().map(function(e){return e.title});(t=i.getCookie("haddock-style"))&&u(t),s.render(a(h,{showHideTrigger:e||function(e){return function(e,t){if(1<e.length){var n=document.querySelector("#page-menu"),o=document.createElement("li");n.appendChild(o),s.render(a(d,{onClick:t,title:"Styles"}),n,o)}}(n,e)},styles:n}),document.body)}},{"./cookies":1,preact:7}],6:[function(e,t,n){var o,r;o=this,r=function(){return function(n){var o={};function r(e){if(o[e])return o[e].exports;var t=o[e]={i:e,l:!1,exports:{}};return n[e].call(t.exports,t,t.exports,r),t.l=!0,t.exports}return r.m=n,r.c=o,r.i=function(e){return e},r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:n})},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=8)}([function(e,t,n){"use strict";e.exports=function(e){return Array.isArray?Array.isArray(e):"[object Array]"===Object.prototype.toString.call(e)}},function(e,t,n){"use strict";var o=function(){function o(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(e,t,n){return t&&o(e.prototype,t),n&&o(e,n),e}}();var u=n(5),d=n(7),_=n(4),r=function(){function y(e,t){var n=t.location,o=void 0===n?0:n,r=t.distance,i=void 0===r?100:r,s=t.threshold,a=void 0===s?.6:s,l=t.maxPatternLength,c=void 0===l?32:l,u=t.isCaseSensitive,d=void 0!==u&&u,h=t.tokenSeparator,p=void 0===h?/ +/g:h,f=t.findAllMatches,v=void 0!==f&&f,g=t.minMatchCharLength,m=void 0===g?1:g;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,y),this.options={location:o,distance:i,threshold:a,maxPatternLength:c,isCaseSensitive:d,tokenSeparator:p,findAllMatches:v,minMatchCharLength:m},this.pattern=this.options.isCaseSensitive?e:e.toLowerCase(),this.pattern.length<=c&&(this.patternAlphabet=_(this.pattern))}return o(y,[{key:"search",value:function(e){if(this.options.isCaseSensitive||(e=e.toLowerCase()),this.pattern===e)return{isMatch:!0,score:0,matchedIndices:[[0,e.length-1]]};var t=this.options,n=t.maxPatternLength,o=t.tokenSeparator;if(this.pattern.length>n)return u(e,this.pattern,o);var r=this.options,i=r.location,s=r.distance,a=r.threshold,l=r.findAllMatches,c=r.minMatchCharLength;return d(e,this.pattern,this.patternAlphabet,{location:i,distance:s,threshold:a,findAllMatches:l,minMatchCharLength:c})}}]),y}();e.exports=r},function(e,t,n){"use strict";var u=n(0);e.exports=function(e,t){return function e(t,n,o){if(n){var r=n.indexOf("."),i=n,s=null;-1!==r&&(i=n.slice(0,r),s=n.slice(r+1));var a=t[i];if(null!=a)if(s||"string"!=typeof a&&"number"!=typeof a)if(u(a))for(var l=0,c=a.length;l<c;l+=1)e(a[l],s,o);else s&&e(a,s,o);else o.push(a.toString())}else o.push(t);return o}(e,t,[])}},function(e,t,n){"use strict";e.exports=function(){for(var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:[],t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:1,n=[],o=-1,r=-1,i=0,s=e.length;i<s;i+=1){var a=e[i];a&&-1===o?o=i:a||-1===o||(t<=(r=i-1)-o+1&&n.push([o,r]),o=-1)}return e[i-1]&&t<=i-o&&n.push([o,i-1]),n}},function(e,t,n){"use strict";e.exports=function(e){for(var t={},n=e.length,o=0;o<n;o+=1)t[e.charAt(o)]=0;for(var r=0;r<n;r+=1)t[e.charAt(r)]|=1<<n-r-1;return t}},function(e,t,n){"use strict";var u=/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g;e.exports=function(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:/ +/g,o=new RegExp(t.replace(u,"\\$&").replace(n,"|")),r=e.match(o),i=!!r,s=[];if(i)for(var a=0,l=r.length;a<l;a+=1){var c=r[a];s.push([e.indexOf(c),c.length-1])}return{score:i?.5:1,isMatch:i,matchedIndices:s}}},function(e,t,n){"use strict";e.exports=function(e,t){var n=t.errors,o=void 0===n?0:n,r=t.currentLocation,i=void 0===r?0:r,s=t.expectedLocation,a=void 0===s?0:s,l=t.distance,c=void 0===l?100:l,u=o/e.length,d=Math.abs(a-i);return c?u+d/c:d?1:u}},function(e,t,n){"use strict";var V=n(6),D=n(3);e.exports=function(e,t,n,o){for(var r=o.location,i=void 0===r?0:r,s=o.distance,a=void 0===s?100:s,l=o.threshold,c=void 0===l?.6:l,u=o.findAllMatches,d=void 0!==u&&u,h=o.minMatchCharLength,p=void 0===h?1:h,f=i,v=e.length,g=c,m=e.indexOf(t,f),y=t.length,_=[],b=0;b<v;b+=1)_[b]=0;if(-1!==m){var k=V(t,{errors:0,currentLocation:m,expectedLocation:f,distance:a});if(g=Math.min(k,g),-1!==(m=e.lastIndexOf(t,f+y))){var S=V(t,{errors:0,currentLocation:m,expectedLocation:f,distance:a});g=Math.min(S,g)}}m=-1;for(var x=[],w=1,C=y+v,L=1<<y-1,M=0;M<y;M+=1){for(var I=0,E=C;I<E;){V(t,{errors:M,currentLocation:f+E,expectedLocation:f,distance:a})<=g?I=E:C=E,E=Math.floor((C-I)/2+I)}C=E;var O=Math.max(1,f-E+1),A=d?v:Math.min(f+E,v)+y,T=Array(A+2);T[A+1]=(1<<M)-1;for(var N=A;O<=N;N-=1){var P=N-1,j=n[e.charAt(P)];if(j&&(_[P]=1),T[N]=(T[N+1]<<1|1)&j,0!==M&&(T[N]|=(x[N+1]|x[N])<<1|1|x[N+1]),T[N]&L&&(w=V(t,{errors:M,currentLocation:P,expectedLocation:f,distance:a}))<=g){if(g=w,(m=P)<=f)break;O=Math.max(1,2*f-m)}}if(g<V(t,{errors:M+1,currentLocation:f,expectedLocation:f,distance:a}))break;x=T}return{isMatch:0<=m,score:0===w?.001:w,matchedIndices:D(_,p)}}},function(e,t,n){"use strict";var o=function(){function o(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(e,t,n){return t&&o(e.prototype,t),n&&o(e,n),e}}();var i=n(1),R=n(2),V=n(0),r=function(){function U(e,t){var n=t.location,o=void 0===n?0:n,r=t.distance,i=void 0===r?100:r,s=t.threshold,a=void 0===s?.6:s,l=t.maxPatternLength,c=void 0===l?32:l,u=t.caseSensitive,d=void 0!==u&&u,h=t.tokenSeparator,p=void 0===h?/ +/g:h,f=t.findAllMatches,v=void 0!==f&&f,g=t.minMatchCharLength,m=void 0===g?1:g,y=t.id,_=void 0===y?null:y,b=t.keys,k=void 0===b?[]:b,S=t.shouldSort,x=void 0===S||S,w=t.getFn,C=void 0===w?R:w,L=t.sortFn,M=void 0===L?function(e,t){return e.score-t.score}:L,I=t.tokenize,E=void 0!==I&&I,O=t.matchAllTokens,A=void 0!==O&&O,T=t.includeMatches,N=void 0!==T&&T,P=t.includeScore,j=void 0!==P&&P,V=t.verbose,D=void 0!==V&&V;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,U),this.options={location:o,distance:i,threshold:a,maxPatternLength:c,isCaseSensitive:d,tokenSeparator:p,findAllMatches:v,minMatchCharLength:m,id:_,keys:k,includeMatches:N,includeScore:j,shouldSort:x,getFn:C,sortFn:M,verbose:D,tokenize:E,matchAllTokens:A},this.setCollection(e)}return o(U,[{key:"setCollection",value:function(e){return this.list=e}},{key:"search",value:function(e){this._log('---------\nSearch pattern: "'+e+'"');var t=this._prepareSearchers(e),n=t.tokenSearchers,o=t.fullSearcher,r=this._search(n,o),i=r.weights,s=r.results;return this._computeScore(i,s),this.options.shouldSort&&this._sort(s),this._format(s)}},{key:"_prepareSearchers",value:function(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:"",t=[];if(this.options.tokenize)for(var n=e.split(this.options.tokenSeparator),o=0,r=n.length;o<r;o+=1)t.push(new i(n[o],this.options));return{tokenSearchers:t,fullSearcher:new i(e,this.options)}}},{key:"_search",value:function(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:[],t=arguments[1],n=this.list,o={},r=[];if("string"==typeof n[0]){for(var i=0,s=n.length;i<s;i+=1)this._analyze({key:"",value:n[i],record:i,index:i},{resultMap:o,results:r,tokenSearchers:e,fullSearcher:t});return{weights:null,results:r}}for(var a={},l=0,c=n.length;l<c;l+=1)for(var u=n[l],d=0,h=this.options.keys.length;d<h;d+=1){var p=this.options.keys[d];if("string"!=typeof p){if(a[p.name]={weight:1-p.weight||1},p.weight<=0||1<p.weight)throw new Error("Key weight has to be > 0 and <= 1");p=p.name}else a[p]={weight:1};this._analyze({key:p,value:this.options.getFn(u,p),record:u,index:l},{resultMap:o,results:r,tokenSearchers:e,fullSearcher:t})}return{weights:a,results:r}}},{key:"_analyze",value:function(e,t){var n=e.key,o=e.arrayIndex,r=void 0===o?-1:o,i=e.value,s=e.record,a=e.index,l=t.tokenSearchers,c=void 0===l?[]:l,u=t.fullSearcher,d=void 0===u?[]:u,h=t.resultMap,p=void 0===h?{}:h,f=t.results,v=void 0===f?[]:f;if(null!=i){var g=!1,m=-1,y=0;if("string"==typeof i){this._log("\nKey: "+(""===n?"-":n));var _=d.search(i);if(this._log('Full text: "'+i+'", score: '+_.score),this.options.tokenize){for(var b=i.split(this.options.tokenSeparator),k=[],S=0;S<c.length;S+=1){var x=c[S];this._log('\nPattern: "'+x.pattern+'"');for(var w=!1,C=0;C<b.length;C+=1){var L=b[C],M=x.search(L),I={};M.isMatch?(I[L]=M.score,w=g=!0,k.push(M.score)):(I[L]=1,this.options.matchAllTokens||k.push(1)),this._log('Token: "'+L+'", score: '+I[L])}w&&(y+=1)}m=k[0];for(var E=k.length,O=1;O<E;O+=1)m+=k[O];m/=E,this._log("Token score average:",m)}var A=_.score;-1<m&&(A=(A+m)/2),this._log("Score average:",A);var T=!this.options.tokenize||!this.options.matchAllTokens||y>=c.length;if(this._log("\nCheck Matches: "+T),(g||_.isMatch)&&T){var N=p[a];N?N.output.push({key:n,arrayIndex:r,value:i,score:A,matchedIndices:_.matchedIndices}):(p[a]={item:s,output:[{key:n,arrayIndex:r,value:i,score:A,matchedIndices:_.matchedIndices}]},v.push(p[a]))}}else if(V(i))for(var P=0,j=i.length;P<j;P+=1)this._analyze({key:n,arrayIndex:P,value:i[P],record:s,index:a},{resultMap:p,results:v,tokenSearchers:c,fullSearcher:d})}}},{key:"_computeScore",value:function(e,t){this._log("\n\nComputing score:\n");for(var n=0,o=t.length;n<o;n+=1){for(var r=t[n].output,i=r.length,s=1,a=1,l=0;l<i;l+=1){var c=e?e[r[l].key].weight:1,u=(1===c?r[l].score:r[l].score||.001)*c;1!==c?a=Math.min(a,u):s*=r[l].nScore=u}t[n].score=1===a?s:a,this._log(t[n])}}},{key:"_sort",value:function(e){this._log("\n\nSorting...."),e.sort(this.options.sortFn)}},{key:"_format",value:function(e){var t=[];this.options.verbose&&this._log("\n\nOutput:\n\n",JSON.stringify(e));var n=[];this.options.includeMatches&&n.push(function(e,t){var n=e.output;t.matches=[];for(var o=0,r=n.length;o<r;o+=1){var i=n[o];if(0!==i.matchedIndices.length){var s={indices:i.matchedIndices,value:i.value};i.key&&(s.key=i.key),i.hasOwnProperty("arrayIndex")&&-1<i.arrayIndex&&(s.arrayIndex=i.arrayIndex),t.matches.push(s)}}}),this.options.includeScore&&n.push(function(e,t){t.score=e.score});for(var o=0,r=e.length;o<r;o+=1){var i=e[o];if(this.options.id&&(i.item=this.options.getFn(i.item,this.options.id)[0]),n.length){for(var s={item:i.item},a=0,l=n.length;a<l;a+=1)n[a](i,s);t.push(s)}else t.push(i.item)}return t}},{key:"_log",value:function(){var e;this.options.verbose&&(e=console).log.apply(e,arguments)}}]),U}();e.exports=r}])},"object"==typeof n&&"object"==typeof t?t.exports=r():"function"==typeof define&&define.amd?define("Fuse",[],r):"object"==typeof n?n.Fuse=r():o.Fuse=r()},{}],7:[function(e,y,t){!function(){"use strict";function n(e,t){var n,o,r,i,s=d;for(i=arguments.length;2<i--;)u.push(arguments[i]);for(t&&null!=t.children&&(u.length||u.push(t.children),delete t.children);u.length;)if((o=u.pop())&&void 0!==o.pop)for(i=o.length;i--;)u.push(o[i]);else"boolean"==typeof o&&(o=null),(r="function"!=typeof e)&&(null==o?o="":"number"==typeof o?o=String(o):"string"!=typeof o&&(r=!1)),r&&n?s[s.length-1]+=o:s===d?s=[o]:s.push(o),n=r;var a=new c;return a.nodeName=e,a.children=s,a.attributes=null==t?void 0:t,a.key=null==t?void 0:t.key,void 0!==D.vnode&&D.vnode(a),a}function L(e,t){for(var n in t)e[n]=t[n];return e}function i(e){!e.__d&&(e.__d=!0)&&1==p.push(e)&&(D.debounceRendering||r)(t)}function t(){var e,t=p;for(p=[];e=t.pop();)e.__d&&j(e)}function C(e,t){return e.__n===t||e.nodeName.toLowerCase()===t.toLowerCase()}function M(e){var t=L({},e.attributes);t.children=e.children;var n=e.nodeName.defaultProps;if(void 0!==n)for(var o in n)void 0===t[o]&&(t[o]=n[o]);return t}function I(e){var t=e.parentNode;t&&t.removeChild(e)}function v(e,t,n,o,r){if("className"===t&&(t="class"),"key"===t);else if("ref"===t)n&&n(null),o&&o(e);else if("class"!==t||r)if("style"===t){if(o&&"string"!=typeof o&&"string"!=typeof n||(e.style.cssText=o||""),o&&"object"==typeof o){if("string"!=typeof n)for(var i in n)i in o||(e.style[i]="");for(var i in o)e.style[i]="number"==typeof o[i]&&!1===h.test(i)?o[i]+"px":o[i]}}else if("dangerouslySetInnerHTML"===t)o&&(e.innerHTML=o.__html||"");else if("o"==t[0]&&"n"==t[1]){var s=t!==(t=t.replace(/Capture$/,""));t=t.toLowerCase().substring(2),o?n||e.addEventListener(t,l,s):e.removeEventListener(t,l,s),(e.__l||(e.__l={}))[t]=o}else if("list"!==t&&"type"!==t&&!r&&t in e){try{e[t]=null==o?"":o}catch(e){}null!=o&&!1!==o||"spellcheck"==t||e.removeAttribute(t)}else{var a=r&&t!==(t=t.replace(/^xlink:?/,""));null==o||!1===o?a?e.removeAttributeNS("http://www.w3.org/1999/xlink",t.toLowerCase()):e.removeAttribute(t):"function"!=typeof o&&(a?e.setAttributeNS("http://www.w3.org/1999/xlink",t.toLowerCase(),o):e.setAttribute(t,o))}else e.className=o||""}function l(e){return this.__l[e.type](D.event&&D.event(e)||e)}function E(){for(var e;e=U.pop();)D.afterMount&&D.afterMount(e),e.componentDidMount&&e.componentDidMount()}function O(e,t,n,o,r,i){R++||(g=null!=r&&void 0!==r.ownerSVGElement,m=null!=e&&!("__preactattr_"in e));var s=A(e,t,n,o,i);return r&&s.parentNode!==r&&r.appendChild(s),--R||(m=!1,i||E()),s}function A(e,t,n,o,r){var i=e,s=g;if(null!=t&&"boolean"!=typeof t||(t=""),"string"==typeof t||"number"==typeof t)return e&&void 0!==e.splitText&&e.parentNode&&(!e._component||r)?e.nodeValue!=t&&(e.nodeValue=t):(i=document.createTextNode(t),e&&(e.parentNode&&e.parentNode.replaceChild(i,e),T(e,!0))),i.__preactattr_=!0,i;var a,l,c=t.nodeName;if("function"==typeof c)return function(e,t,n,o){var r=e&&e._component,i=r,s=e,a=r&&e._componentConstructor===t.nodeName,l=a,c=M(t);for(;r&&!l&&(r=r.__u);)l=r.constructor===t.nodeName;r&&l&&(!o||r._component)?(P(r,c,3,n,o),e=r.base):(i&&!a&&(V(i),e=s=null),r=N(t.nodeName,c,n),e&&!r.__b&&(r.__b=e,s=null),P(r,c,1,n,o),e=r.base,s&&e!==s&&(s._component=null,T(s,!1)));return e}(e,t,n,o);if(g="svg"===c||"foreignObject"!==c&&g,c=String(c),(!e||!C(e,c))&&(a=c,(l=g?document.createElementNS("http://www.w3.org/2000/svg",a):document.createElement(a)).__n=a,i=l,e)){for(;e.firstChild;)i.appendChild(e.firstChild);e.parentNode&&e.parentNode.replaceChild(i,e),T(e,!0)}var u=i.firstChild,d=i.__preactattr_,h=t.children;if(null==d){d=i.__preactattr_={};for(var p=i.attributes,f=p.length;f--;)d[p[f].name]=p[f].value}return!m&&h&&1===h.length&&"string"==typeof h[0]&&null!=u&&void 0!==u.splitText&&null==u.nextSibling?u.nodeValue!=h[0]&&(u.nodeValue=h[0]):(h&&h.length||null!=u)&&function(e,t,n,o,r){var i,s,a,l,c,u=e.childNodes,d=[],h={},p=0,f=0,v=u.length,g=0,m=t?t.length:0;if(0!==v)for(var y=0;y<v;y++){var _=u[y],b=_.__preactattr_,k=m&&b?_._component?_._component.__k:b.key:null;null!=k?(p++,h[k]=_):(b||(void 0!==_.splitText?!r||_.nodeValue.trim():r))&&(d[g++]=_)}if(0!==m)for(var y=0;y<m;y++){l=t[y],c=null;var k=l.key;if(null!=k)p&&void 0!==h[k]&&(c=h[k],h[k]=void 0,p--);else if(f<g)for(i=f;i<g;i++)if(void 0!==d[i]&&(S=s=d[i],w=r,"string"==typeof(x=l)||"number"==typeof x?void 0!==S.splitText:"string"==typeof x.nodeName?!S._componentConstructor&&C(S,x.nodeName):w||S._componentConstructor===x.nodeName)){c=s,d[i]=void 0,i===g-1&&g--,i===f&&f++;break}c=A(c,l,n,o),a=u[y],c&&c!==e&&c!==a&&(null==a?e.appendChild(c):c===a.nextSibling?I(a):e.insertBefore(c,a))}var S,x,w;if(p)for(var y in h)void 0!==h[y]&&T(h[y],!1);for(;f<=g;)void 0!==(c=d[g--])&&T(c,!1)}(i,h,n,o,m||null!=d.dangerouslySetInnerHTML),function(e,t,n){var o;for(o in n)t&&null!=t[o]||null==n[o]||v(e,o,n[o],n[o]=void 0,g);for(o in t)"children"===o||"innerHTML"===o||o in n&&t[o]===("value"===o||"checked"===o?e[o]:n[o])||v(e,o,n[o],n[o]=t[o],g)}(i,t.attributes,d),g=s,i}function T(e,t){var n=e._component;n?V(n):(null!=e.__preactattr_&&e.__preactattr_.ref&&e.__preactattr_.ref(null),!1!==t&&null!=e.__preactattr_||I(e),o(e))}function o(e){for(e=e.lastChild;e;){var t=e.previousSibling;T(e,!0),e=t}}function N(e,t,n){var o,r=f.length;for(e.prototype&&e.prototype.render?(o=new e(t,n),a.call(o,t,n)):((o=new a(t,n)).constructor=e,o.render=s);r--;)if(f[r].constructor===e)return o.__b=f[r].__b,f.splice(r,1),o;return o}function s(e,t,n){return this.constructor(e,n)}function P(e,t,n,o,r){e.__x||(e.__x=!0,e.__r=t.ref,e.__k=t.key,delete t.ref,delete t.key,void 0===e.constructor.getDerivedStateFromProps&&(!e.base||r?e.componentWillMount&&e.componentWillMount():e.componentWillReceiveProps&&e.componentWillReceiveProps(t,o)),o&&o!==e.context&&(e.__c||(e.__c=e.context),e.context=o),e.__p||(e.__p=e.props),e.props=t,e.__x=!1,0!==n&&(1!==n&&!1===D.syncComponentUpdates&&e.base?i(e):j(e,1,r)),e.__r&&e.__r(e))}function j(e,t,n,o){if(!e.__x){var r,i,s,a=e.props,l=e.state,c=e.context,u=e.__p||a,d=e.__s||l,h=e.__c||c,p=e.base,f=e.__b,v=p||f,g=e._component,m=!1,y=h;if(e.constructor.getDerivedStateFromProps&&(l=L(L({},l),e.constructor.getDerivedStateFromProps(a,l)),e.state=l),p&&(e.props=u,e.state=d,e.context=h,2!==t&&e.shouldComponentUpdate&&!1===e.shouldComponentUpdate(a,l,c)?m=!0:e.componentWillUpdate&&e.componentWillUpdate(a,l,c),e.props=a,e.state=l,e.context=c),e.__p=e.__s=e.__c=e.__b=null,e.__d=!1,!m){r=e.render(a,l,c),e.getChildContext&&(c=L(L({},c),e.getChildContext())),p&&e.getSnapshotBeforeUpdate&&(y=e.getSnapshotBeforeUpdate(u,d));var _,b,k=r&&r.nodeName;if("function"==typeof k){var S=M(r);(i=g)&&i.constructor===k&&S.key==i.__k?P(i,S,1,c,!1):(_=i,e._component=i=N(k,S,c),i.__b=i.__b||f,i.__u=e,P(i,S,0,c,!1),j(i,1,n,!0)),b=i.base}else s=v,(_=g)&&(s=e._component=null),(v||1===t)&&(s&&(s._component=null),b=O(s,r,c,n||!p,v&&v.parentNode,!0));if(v&&b!==v&&i!==g){var x=v.parentNode;x&&b!==x&&(x.replaceChild(b,v),_||(v._component=null,T(v,!1)))}if(_&&V(_),(e.base=b)&&!o){for(var w=e,C=e;C=C.__u;)(w=C).base=b;b._component=w,b._componentConstructor=w.constructor}}for(!p||n?U.unshift(e):m||(e.componentDidUpdate&&e.componentDidUpdate(u,d,y),D.afterUpdate&&D.afterUpdate(e));e.__h.length;)e.__h.pop().call(e);R||o||E()}}function V(e){D.beforeUnmount&&D.beforeUnmount(e);var t=e.base;e.__x=!0,e.componentWillUnmount&&e.componentWillUnmount(),e.base=null;var n=e._component;n?V(n):t&&(t.__preactattr_&&t.__preactattr_.ref&&t.__preactattr_.ref(null),I(e.__b=t),f.push(e),o(t)),e.__r&&e.__r(null)}function a(e,t){this.__d=!0,this.context=t,this.props=e,this.state=this.state||{},this.__h=[]}var c=function(){},D={},u=[],d=[],r="function"==typeof Promise?Promise.resolve().then.bind(Promise.resolve()):setTimeout,h=/acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i,p=[],U=[],R=0,g=!1,m=!1,f=[];L(a.prototype,{setState:function(e,t){this.__s||(this.__s=this.state),this.state=L(L({},this.state),"function"==typeof e?e(this.state,this.props):e),t&&this.__h.push(t),i(this)},forceUpdate:function(e){e&&this.__h.push(e),j(this,2)},render:function(){}});var e={h:n,createElement:n,cloneElement:function(e,t){return n(e.nodeName,L(L({},e.attributes),t),2<arguments.length?[].slice.call(arguments,2):e.children)},Component:a,render:function(e,t,n){return O(n,e,{},!1,t,!1)},rerender:t,options:D};void 0!==y?y.exports=e:self.preact=e}()},{}]},{},[3]);+//# sourceMappingURL=haddock-bundle.min.js.map
− resources/html/haddock-util.js
@@ -1,316 +0,0 @@-// Haddock JavaScript utilities--var rspace = /\s\s+/g,- rtrim = /^\s+|\s+$/g;--function spaced(s) { return (" " + s + " ").replace(rspace, " "); }-function trim(s) { return s.replace(rtrim, ""); }--function hasClass(elem, value) {- var className = spaced(elem.className || "");- return className.indexOf( " " + value + " " ) >= 0;-}--function addClass(elem, value) {- var className = spaced(elem.className || "");- if ( className.indexOf( " " + value + " " ) < 0 ) {- elem.className = trim(className + " " + value);- }-}--function removeClass(elem, value) {- var className = spaced(elem.className || "");- className = className.replace(" " + value + " ", " ");- elem.className = trim(className);-}--function toggleClass(elem, valueOn, valueOff, bool) {- if (bool == null) { bool = ! hasClass(elem, valueOn); }- if (bool) {- removeClass(elem, valueOff);- addClass(elem, valueOn);- }- else {- removeClass(elem, valueOn);- addClass(elem, valueOff);- }- return bool;-}---function makeClassToggle(valueOn, valueOff)-{- return function(elem, bool) {- return toggleClass(elem, valueOn, valueOff, bool);- }-}--toggleShow = makeClassToggle("show", "hide");-toggleCollapser = makeClassToggle("collapser", "expander");--function toggleSection(id)-{- var b = toggleShow(document.getElementById("section." + id));- toggleCollapser(document.getElementById("control." + id), b);- rememberCollapsed(id, b);- return b;-}--var collapsed = {};-function rememberCollapsed(id, b)-{- if(b)- delete collapsed[id]- else- collapsed[id] = null;-- var sections = [];- for(var i in collapsed)- {- if(collapsed.hasOwnProperty(i))- sections.push(i);- }- // cookie specific to this page; don't use setCookie which sets path=/- document.cookie = "collapsed=" + escape(sections.join('+'));-}--function restoreCollapsed()-{- var cookie = getCookie("collapsed");- if(!cookie)- return;-- var ids = cookie.split('+');- for(var i in ids)- {- if(document.getElementById("section." + ids[i]))- toggleSection(ids[i]);- }-}--function setCookie(name, value) {- document.cookie = name + "=" + escape(value) + ";path=/;";-}--function clearCookie(name) {- document.cookie = name + "=;path=/;expires=Thu, 01-Jan-1970 00:00:01 GMT;";-}--function getCookie(name) {- var nameEQ = name + "=";- var ca = document.cookie.split(';');- for(var i=0;i < ca.length;i++) {- var c = ca[i];- while (c.charAt(0)==' ') c = c.substring(1,c.length);- if (c.indexOf(nameEQ) == 0) {- return unescape(c.substring(nameEQ.length,c.length));- }- }- return null;-}----var max_results = 75; // 50 is not enough to search for map in the base libraries-var shown_range = null;-var last_search = null;--function quick_search()-{- perform_search(false);-}--function full_search()-{- perform_search(true);-}---function perform_search(full)-{- var text = document.getElementById("searchbox").value.toLowerCase();- if (text == last_search && !full) return;- last_search = text;-- var table = document.getElementById("indexlist");- var status = document.getElementById("searchmsg");- var children = table.firstChild.childNodes;-- // first figure out the first node with the prefix- var first = bisect(-1);- var last = (first == -1 ? -1 : bisect(1));-- if (first == -1)- {- table.className = "";- status.innerHTML = "No results found, displaying all";- }- else if (first == 0 && last == children.length - 1)- {- table.className = "";- status.innerHTML = "";- }- else if (last - first >= max_results && !full)- {- table.className = "";- status.innerHTML = "More than " + max_results + ", press Search to display";- }- else- {- // decide what you need to clear/show- if (shown_range)- setclass(shown_range[0], shown_range[1], "indexrow");- setclass(first, last, "indexshow");- shown_range = [first, last];- table.className = "indexsearch";- status.innerHTML = "";- }--- function setclass(first, last, status)- {- for (var i = first; i <= last; i++)- {- children[i].className = status;- }- }--- // do a binary search, treating 0 as ...- // return either -1 (no 0's found) or location of most far match- function bisect(dir)- {- var first = 0, finish = children.length - 1;- var mid, success = false;-- while (finish - first > 3)- {- mid = Math.floor((finish + first) / 2);-- var i = checkitem(mid);- if (i == 0) i = dir;- if (i == -1)- finish = mid;- else- first = mid;- }- var a = (dir == 1 ? first : finish);- var b = (dir == 1 ? finish : first);- for (var i = b; i != a - dir; i -= dir)- {- if (checkitem(i) == 0) return i;- }- return -1;- }--- // from an index, decide what the result is- // 0 = match, -1 is lower, 1 is higher- function checkitem(i)- {- var s = getitem(i).toLowerCase().substr(0, text.length);- if (s == text) return 0;- else return (s > text ? -1 : 1);- }--- // from an index, get its string- // this abstracts over alternates- function getitem(i)- {- for ( ; i >= 0; i--)- {- var s = children[i].firstChild.firstChild.data;- if (s.indexOf(' ') == -1)- return s;- }- return ""; // should never be reached- }-}--function setSynopsis(filename) {- if (parent.window.synopsis && parent.window.synopsis.location) {- if (parent.window.synopsis.location.replace) {- // In Firefox this avoids adding the change to the history.- parent.window.synopsis.location.replace(filename);- } else {- parent.window.synopsis.location = filename;- }- }-}--function addMenuItem(html) {- var menu = document.getElementById("page-menu");- if (menu) {- var btn = menu.firstChild.cloneNode(false);- btn.innerHTML = html;- menu.appendChild(btn);- }-}--function styles() {- var i, a, es = document.getElementsByTagName("link"), rs = [];- for (i = 0; a = es[i]; i++) {- if(a.rel.indexOf("style") != -1 && a.title) {- rs.push(a);- }- }- return rs;-}--function addStyleMenu() {- var as = styles();- var i, a, btns = "";- for(i=0; a = as[i]; i++) {- btns += "<li><a href='#' onclick=\"setActiveStyleSheet('"- + a.title + "'); return false;\">"- + a.title + "</a></li>"- }- if (as.length > 1) {- var h = "<div id='style-menu-holder'>"- + "<a href='#' onclick='styleMenu(); return false;'>Style ▾</a>"- + "<ul id='style-menu' class='hide'>" + btns + "</ul>"- + "</div>";- addMenuItem(h);- }-}--function setActiveStyleSheet(title) {- var as = styles();- var i, a, found;- for(i=0; a = as[i]; i++) {- a.disabled = true;- // need to do this always, some browsers are edge triggered- if(a.title == title) {- found = a;- }- }- if (found) {- found.disabled = false;- setCookie("haddock-style", title);- }- else {- as[0].disabled = false;- clearCookie("haddock-style");- }- styleMenu(false);-}--function resetStyle() {- var s = getCookie("haddock-style");- if (s) setActiveStyleSheet(s);-}---function styleMenu(show) {- var m = document.getElementById('style-menu');- if (m) toggleShow(m, show);-}---function pageLoad() {- addStyleMenu();- resetStyle();- restoreCollapsed();-}-
+ resources/html/quick-jump.css view
@@ -0,0 +1,221 @@+/* @group Fundamentals */++.hidden {+ display: none;+}++/* @end */++/* @group Search box layout */++#search {+ position: fixed;+ top: 3.2em;+ bottom: 0;+ left: calc(50% - 22em);+ width: 44em;+ z-index: 1000;+ overflow-y: auto;+}++@media only screen and (max-width: 999px) {+ #search {+ top: 5.7em;+ }+}++#search-form, #search-results {+ box-shadow: 2px 2px 6px rgb(199, 204, 208);+ pointer-events: all;+}++#search-form input {+ font-size: 1.25em; line-height: 2.3em; height: 2.4em;+ display: block;+ box-sizing: border-box;+ width: 100%;+ margin: 0;+ padding: 0 0.75em;+ border: 0.05em solid rgb(151, 179, 202);+}++#search input:focus {+ outline: none;+}++#search p.error {+ color: rgb(107, 24, 24);+ font-weight: bold;+}++#search-results {+ box-sizing: border-box;+ border: 0.05em solid #b2d5fb;+ background: #e8f3ff;+ max-height: 80%;+ overflow: scroll;+}++#search-form input + #search-results {+ border-top: none;+ top: 3em;+ max-height: calc(100% - 3em);+}++/* @end */++/* @group search results */++#search-results > ul {+ margin: 0;+ list-style: none;+}++#search-results > ul > li,+#search-results > p,+#search-results > table {+ padding: 0.5em 1em;+ margin: 0;+}++#search-results > ul > li {+ border-bottom: 1px solid #b2d5fb;+}++#search-results > ul > li > ul {+ list-style: none;+}++.search-module h4 {+ margin: 0;+}++.search-module > ul {+ margin: 0.5em 0 0.5em 2em;+}++.search-module > ul > li > a[href] {+ display: block;+ color: inherit;+ padding: 0.25em 0.5em;+}++.search-module > ul > li > a[href].active-link {+ background: #faf9dc;+}++.search-module a[href]:hover {+ text-decoration: none;+}++.search-result a a {+ pointer-events: none;+}++.search-result ul.subs {+ display: inline-block;+ margin: 0; padding: 0;+}++.search-result ul.subs li {+ display: none;+}++.search-result ul.subs::after {+ display: inline-block;+ content: "...";+ color: rgb(78,98,114);+ margin: 0 0.25em;+}++.more-results {+ color: rgb(99, 141, 173);+ position: relative;+}++.more-results::before {+ content: "+";+ display: inline-block;+ color: #b2d5fb;+ font-weight: bold;+ font-size: 1.25em; line-height: inherit;+ position: absolute;+ left: -1em;+}++/* @end */++/* @group Keyboard shortcuts table */++.keyboard-shortcuts {+ line-height: 1.6em;+}++.keyboard-shortcuts th {+ color: rgb(78,98,114);+}++.keyboard-shortcuts td:first-child,+.keyboard-shortcuts th:first-child {+ text-align: right;+ padding-right: 0.6em;+}++.key {+ display: inline-block;+ font-size: 0.9em;+ min-width: 0.8em; line-height: 1.2em;+ text-align: center;+ background: #b2d5fb;+ border: 1px solid #74a3d6;+ padding: 0 0.2em;+ margin: 0 0.1em;+}++/* @end */++/* @group Dropdown menus */++/* Based on #search styling above. */++.dropdown-menu {+ position: fixed;+ /* Not robust to window size changes. */+ top: 3.2em;+ right: 0;+ /* To display on top of synopsis menu on right side. */+ z-index: 1000;+ border: 0.05em solid #b2d5fb;+ background: #e8f3ff;+}++@media only screen and (max-width: 999px) {+ .dropdown-menu {+ top: 5.7em;+ }+}++.dropdown-menu * {+ margin: 0.1em;+}++.dropdown-menu button {+ border: 1px #5E5184 solid;+ border-radius: 3px;+ background: #5E5184;+ padding: 3px;+ color: #f4f4f4;+ min-width: 6em;+}++.dropdown-menu button:hover {+ color: #5E5184;+ background: #f4f4f4;+}++.dropdown-menu button:active {+ color: #f4f4f4;+ background: #5E5184;+}++/* @end */
+ resources/html/quick-jump.min.js view
@@ -0,0 +1,2 @@+!function i(s,a,l){function c(t,e){if(!a[t]){if(!s[t]){var n="function"==typeof require&&require;if(!e&&n)return n(t,!0);if(u)return u(t,!0);var o=new Error("Cannot find module '"+t+"'");throw o.code="MODULE_NOT_FOUND",o}var r=a[t]={exports:{}};s[t][0].call(r.exports,function(e){return c(s[t][1][e]||e)},r,r.exports,i,s,a,l)}return a[t].exports}for(var u="function"==typeof require&&require,e=0;e<l.length;e++)c(l[e]);return c}({1:[function(e,t,n){"use strict";var o,r=this&&this.__extends||(o=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])},function(e,t){function n(){this.constructor=e}o(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)});Object.defineProperty(n,"__esModule",{value:!0});var i=e("fuse.js"),s=e("preact"),a=s.h,l=s.Component;var c=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return r(t,e),t.prototype.render=function(t){return a("li",null,a("a",{href:"#",onClick:function(e){e.preventDefault(),t.onClick()}},t.title))},t}(l);function u(e,t){return t.length<=e?t:t.slice(0,e)}var h=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.linkIndex=0,e.focusPlease=!1,e.navigatedByKeyboard=!1,e}return r(e,t),e.prototype.componentWillMount=function(){var e,t,n,o,r=this;this.setState({searchString:"",isVisible:!1,expanded:{},activeLinkIndex:-1,moduleResults:[]}),e=this.props.baseUrl+"/doc-index.json",t=function(e){r.setState({fuse:new i(e,{threshold:.25,caseSensitive:!0,includeScore:!0,tokenize:!0,keys:[{name:"name",weight:.7},{name:"module",weight:.3}]}),moduleResults:[]})},n=function(e){console&&console.error("could not load 'doc-index.json' for searching",e),r.setState({failedLoading:!0})},(o=new XMLHttpRequest).onreadystatechange=function(){if(o.readyState===XMLHttpRequest.DONE)if(200===o.status){if(t)try{t(JSON.parse(o.responseText))}catch(e){n(o)}}else n&&n(o)},o.open("GET",e,!0),o.send(),document.addEventListener("mousedown",this.hide.bind(this)),document.addEventListener("keydown",function(e){r.state.isVisible&&("Escape"===e.key?r.hide():"ArrowUp"===e.key||"k"===e.key&&e.ctrlKey?(e.preventDefault(),r.navigateLinks(-1)):"ArrowDown"===e.key||"j"===e.key&&e.ctrlKey?(e.preventDefault(),r.navigateLinks(1)):"Enter"===e.key&&0<=r.state.activeLinkIndex&&r.followActiveLink()),"s"===e.key&&"input"!==e.target.tagName.toLowerCase()&&(e.preventDefault(),r.show())})},e.prototype.hide=function(){this.setState({isVisible:!1,searchString:""})},e.prototype.show=function(){this.state.isVisible||(this.focusPlease=!0,this.setState({isVisible:!0,activeLinkIndex:-1}))},e.prototype.toggleVisibility=function(){this.state.isVisible?this.hide():this.show()},e.prototype.navigateLinks=function(e){var t=Math.max(-1,Math.min(this.linkIndex-1,this.state.activeLinkIndex+e));this.navigatedByKeyboard=!0,this.setState({activeLinkIndex:t})},e.prototype.followActiveLink=function(){this.activeLinkAction&&this.activeLinkAction()},e.prototype.updateResults=function(){var e=this.input&&this.input.value||"",t=this.state.fuse.search(e),o={};t.forEach(function(e){var t=e.item.module;(o[t]||(o[t]=[])).push(e)});var r=[],n=function(e){var t=o[e],n=0;t.forEach(function(e){n+=1/e.score}),r.push({module:e,totalScore:1/n,items:t})};for(var i in o)n(i);r.sort(function(e,t){return e.totalScore-t.totalScore}),this.setState({searchString:e,isVisible:!0,moduleResults:r})},e.prototype.componentDidUpdate=function(){if(this.searchResults&&this.activeLink&&this.navigatedByKeyboard){var e=this.activeLink.getClientRects()[0],t=this.searchResults.getClientRects()[0].top;e.bottom>window.innerHeight?this.searchResults.scrollTop+=e.bottom-window.innerHeight+80:e.top<t&&(this.searchResults.scrollTop-=t-e.top+80)}this.focusPlease&&this.input&&this.input.focus(),this.navigatedByKeyboard=!1,this.focusPlease=!1},e.prototype.componentDidMount=function(){this.props.showHideTrigger(this.toggleVisibility.bind(this))},e.prototype.render=function(e,t){var r=this;if(t.failedLoading){var n="file:"==window.location.protocol;return a("div",{id:"search",class:t.isVisible?"":"hidden"},a("div",{id:"search-results"},a("p",{class:"error"},"Failed to load file 'doc-index.json' containing definitions in this package."),n?a("p",{class:"error"},"To use quick jump, load this page with HTTP (from a local static file web server) instead of using the ",a("code",null,"file://")," protocol. (For security reasons, it is not possible to fetch auxiliary files using JS in a HTML page opened with ",a("code",null,"file://"),".)"):[]))}this.linkIndex=0;var o=function(e){e.stopPropagation()},i=u(10,t.moduleResults).map(function(e){return r.renderResultsInModule(e)});return a("div",{id:"search",class:t.isVisible?"":"hidden"},a("div",{id:"search-form",onMouseDown:o},a("input",{placeholder:"Search in package by name",ref:function(e){r.input=e},onFocus:this.show.bind(this),onClick:this.show.bind(this),onInput:this.updateResults.bind(this)})),a("div",{id:"search-results",ref:function(e){r.searchResults=e},onMouseDown:o,onMouseOver:function(e){for(var t=e.target;t&&"function"==typeof t.getAttribute;){var n=t.getAttribute("data-link-index");if("string"==typeof n){var o=parseInt(n,10);r.setState({activeLinkIndex:o});break}t=t.parentNode}}},""===t.searchString?[a(f,null),a(d,null)]:0==i.length?a(v,{searchString:t.searchString}):a("ul",null,i)))},e.prototype.renderResultsInModule=function(e){var n=this,t=e.items,o=e.module,r=this.state.expanded[o]||t.length<=10,i=r?t:u(8,t);return a("li",{class:"search-module"},a("h4",null,o),a("ul",null,i.map(function(e){return t=e.item,a("li",{class:"search-result"},n.navigationLink(n.props.baseUrl+"/"+t.link,{},a(p,{html:t.display_html})));var t}),r?[]:a("li",{class:"more-results"},this.actionLink(function(){var e=Object.assign({},n.state.expanded);e[o]=!0,n.setState({expanded:e})},{},"show "+(t.length-i.length)+" more results from this module"))))},e.prototype.navigationLink=function(e,t){for(var n=this,o=[],r=2;r<arguments.length;r++)o[r-2]=arguments[r];var i=Object.assign({href:e,onClick:this.hide.bind(this)},t);return this.menuLink.apply(this,[i,function(){window.location.href=e,n.hide()}].concat(o))},e.prototype.actionLink=function(t,e){for(var n=[],o=2;o<arguments.length;o++)n[o-2]=arguments[o];var r=Object.assign({href:"#",onClick:function(e){e.preventDefault(),t()}},e);return this.menuLink.apply(this,[r,t].concat(n))},e.prototype.menuLink=function(e,t){for(var n=this,o=[],r=2;r<arguments.length;r++)o[r-2]=arguments[r];var i=this.linkIndex;i===this.state.activeLinkIndex&&(e.class=(e.class?e.class+" ":"")+"active-link",e.ref=function(e){e&&(n.activeLink=e)},this.activeLinkAction=t);var s=Object.assign({"data-link-index":i},e);return this.linkIndex+=1,a.apply(void 0,["a",s].concat(o))},e}(l),p=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return r(t,e),t.prototype.shouldComponentUpdate=function(e){return this.props.html!==e.html},t.prototype.render=function(e){return a("div",{dangerouslySetInnerHTML:{__html:e.html}})},t}(l);function d(){return a("table",{class:"keyboard-shortcuts"},a("tr",null,a("th",null,"Key"),a("th",null,"Shortcut")),a("tr",null,a("td",null,a("span",{class:"key"},"s")),a("td",null,"Open this search box")),a("tr",null,a("td",null,a("span",{class:"key"},"esc")),a("td",null,"Close this search box")),a("tr",null,a("td",null,a("span",{class:"key"},"↓"),",",a("span",{class:"key"},"ctrl")," + ",a("span",{class:"key"},"j")),a("td",null,"Move down in search results")),a("tr",null,a("td",null,a("span",{class:"key"},"↑"),",",a("span",{class:"key"},"ctrl")," + ",a("span",{class:"key"},"k")),a("td",null,"Move up in search results")),a("tr",null,a("td",null,a("span",{class:"key"},"↵")),a("td",null,"Go to active search result")))}function f(){return a("p",null,"You can find any exported type, constructor, class, function or pattern defined in this package by (approximate) name.")}function v(e){var t=[a("p",null,"Your search for '",e.searchString,"' produced the following list of results: ",a("code",null,"[]"),"."),a("p",null,a("code",null,"Nothing")," matches your query for '",e.searchString,"'."),a("p",null,a("code",null,"Left \"no matches for '",e.searchString,"'\" :: Either String (NonEmpty SearchResult)"))];return t[(e.searchString||"a").charCodeAt(0)%t.length]}function g(e,t){var n,o=document.getElementById("quick-jump-button");o&&s.render(a(h,{baseUrl:e||".",showHideTrigger:t||(n=o,function(e){var t=document.querySelector("#page-menu");s.render(a(c,{onClick:e,title:"Quick Jump"}),t,n)})}),document.body)}n.init=g,window.quickNav={init:g}},{"fuse.js":2,preact:3}],2:[function(e,t,n){var o,r;o=this,r=function(){return function(n){var o={};function r(e){if(o[e])return o[e].exports;var t=o[e]={i:e,l:!1,exports:{}};return n[e].call(t.exports,t,t.exports,r),t.l=!0,t.exports}return r.m=n,r.c=o,r.i=function(e){return e},r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:n})},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=8)}([function(e,t,n){"use strict";e.exports=function(e){return Array.isArray?Array.isArray(e):"[object Array]"===Object.prototype.toString.call(e)}},function(e,t,n){"use strict";var o=function(){function o(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(e,t,n){return t&&o(e.prototype,t),n&&o(e,n),e}}();var u=n(5),h=n(7),y=n(4),r=function(){function m(e,t){var n=t.location,o=void 0===n?0:n,r=t.distance,i=void 0===r?100:r,s=t.threshold,a=void 0===s?.6:s,l=t.maxPatternLength,c=void 0===l?32:l,u=t.isCaseSensitive,h=void 0!==u&&u,p=t.tokenSeparator,d=void 0===p?/ +/g:p,f=t.findAllMatches,v=void 0!==f&&f,g=t.minMatchCharLength,_=void 0===g?1:g;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,m),this.options={location:o,distance:i,threshold:a,maxPatternLength:c,isCaseSensitive:h,tokenSeparator:d,findAllMatches:v,minMatchCharLength:_},this.pattern=this.options.isCaseSensitive?e:e.toLowerCase(),this.pattern.length<=c&&(this.patternAlphabet=y(this.pattern))}return o(m,[{key:"search",value:function(e){if(this.options.isCaseSensitive||(e=e.toLowerCase()),this.pattern===e)return{isMatch:!0,score:0,matchedIndices:[[0,e.length-1]]};var t=this.options,n=t.maxPatternLength,o=t.tokenSeparator;if(this.pattern.length>n)return u(e,this.pattern,o);var r=this.options,i=r.location,s=r.distance,a=r.threshold,l=r.findAllMatches,c=r.minMatchCharLength;return h(e,this.pattern,this.patternAlphabet,{location:i,distance:s,threshold:a,findAllMatches:l,minMatchCharLength:c})}}]),m}();e.exports=r},function(e,t,n){"use strict";var u=n(0);e.exports=function(e,t){return function e(t,n,o){if(n){var r=n.indexOf("."),i=n,s=null;-1!==r&&(i=n.slice(0,r),s=n.slice(r+1));var a=t[i];if(null!=a)if(s||"string"!=typeof a&&"number"!=typeof a)if(u(a))for(var l=0,c=a.length;l<c;l+=1)e(a[l],s,o);else s&&e(a,s,o);else o.push(a.toString())}else o.push(t);return o}(e,t,[])}},function(e,t,n){"use strict";e.exports=function(){for(var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:[],t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:1,n=[],o=-1,r=-1,i=0,s=e.length;i<s;i+=1){var a=e[i];a&&-1===o?o=i:a||-1===o||(t<=(r=i-1)-o+1&&n.push([o,r]),o=-1)}return e[i-1]&&t<=i-o&&n.push([o,i-1]),n}},function(e,t,n){"use strict";e.exports=function(e){for(var t={},n=e.length,o=0;o<n;o+=1)t[e.charAt(o)]=0;for(var r=0;r<n;r+=1)t[e.charAt(r)]|=1<<n-r-1;return t}},function(e,t,n){"use strict";var u=/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g;e.exports=function(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:/ +/g,o=new RegExp(t.replace(u,"\\$&").replace(n,"|")),r=e.match(o),i=!!r,s=[];if(i)for(var a=0,l=r.length;a<l;a+=1){var c=r[a];s.push([e.indexOf(c),c.length-1])}return{score:i?.5:1,isMatch:i,matchedIndices:s}}},function(e,t,n){"use strict";e.exports=function(e,t){var n=t.errors,o=void 0===n?0:n,r=t.currentLocation,i=void 0===r?0:r,s=t.expectedLocation,a=void 0===s?0:s,l=t.distance,c=void 0===l?100:l,u=o/e.length,h=Math.abs(a-i);return c?u+h/c:h?1:u}},function(e,t,n){"use strict";var U=n(6),R=n(3);e.exports=function(e,t,n,o){for(var r=o.location,i=void 0===r?0:r,s=o.distance,a=void 0===s?100:s,l=o.threshold,c=void 0===l?.6:l,u=o.findAllMatches,h=void 0!==u&&u,p=o.minMatchCharLength,d=void 0===p?1:p,f=i,v=e.length,g=c,_=e.indexOf(t,f),m=t.length,y=[],k=0;k<v;k+=1)y[k]=0;if(-1!==_){var b=U(t,{errors:0,currentLocation:_,expectedLocation:f,distance:a});if(g=Math.min(b,g),-1!==(_=e.lastIndexOf(t,f+m))){var x=U(t,{errors:0,currentLocation:_,expectedLocation:f,distance:a});g=Math.min(x,g)}}_=-1;for(var S=[],w=1,L=m+v,C=1<<m-1,M=0;M<m;M+=1){for(var A=0,I=L;A<I;){U(t,{errors:M,currentLocation:f+I,expectedLocation:f,distance:a})<=g?A=I:L=I,I=Math.floor((L-A)/2+A)}L=I;var N=Math.max(1,f-I+1),T=h?v:Math.min(f+I,v)+m,O=Array(T+2);O[T+1]=(1<<M)-1;for(var P=T;N<=P;P-=1){var j=P-1,E=n[e.charAt(j)];if(E&&(y[j]=1),O[P]=(O[P+1]<<1|1)&E,0!==M&&(O[P]|=(S[P+1]|S[P])<<1|1|S[P+1]),O[P]&C&&(w=U(t,{errors:M,currentLocation:j,expectedLocation:f,distance:a}))<=g){if(g=w,(_=j)<=f)break;N=Math.max(1,2*f-_)}}if(g<U(t,{errors:M+1,currentLocation:f,expectedLocation:f,distance:a}))break;S=O}return{isMatch:0<=_,score:0===w?.001:w,matchedIndices:R(y,d)}}},function(e,t,n){"use strict";var o=function(){function o(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(e,t,n){return t&&o(e.prototype,t),n&&o(e,n),e}}();var i=n(1),F=n(2),U=n(0),r=function(){function D(e,t){var n=t.location,o=void 0===n?0:n,r=t.distance,i=void 0===r?100:r,s=t.threshold,a=void 0===s?.6:s,l=t.maxPatternLength,c=void 0===l?32:l,u=t.caseSensitive,h=void 0!==u&&u,p=t.tokenSeparator,d=void 0===p?/ +/g:p,f=t.findAllMatches,v=void 0!==f&&f,g=t.minMatchCharLength,_=void 0===g?1:g,m=t.id,y=void 0===m?null:m,k=t.keys,b=void 0===k?[]:k,x=t.shouldSort,S=void 0===x||x,w=t.getFn,L=void 0===w?F:w,C=t.sortFn,M=void 0===C?function(e,t){return e.score-t.score}:C,A=t.tokenize,I=void 0!==A&&A,N=t.matchAllTokens,T=void 0!==N&&N,O=t.includeMatches,P=void 0!==O&&O,j=t.includeScore,E=void 0!==j&&j,U=t.verbose,R=void 0!==U&&U;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,D),this.options={location:o,distance:i,threshold:a,maxPatternLength:c,isCaseSensitive:h,tokenSeparator:d,findAllMatches:v,minMatchCharLength:_,id:y,keys:b,includeMatches:P,includeScore:E,shouldSort:S,getFn:L,sortFn:M,verbose:R,tokenize:I,matchAllTokens:T},this.setCollection(e)}return o(D,[{key:"setCollection",value:function(e){return this.list=e}},{key:"search",value:function(e){this._log('---------\nSearch pattern: "'+e+'"');var t=this._prepareSearchers(e),n=t.tokenSearchers,o=t.fullSearcher,r=this._search(n,o),i=r.weights,s=r.results;return this._computeScore(i,s),this.options.shouldSort&&this._sort(s),this._format(s)}},{key:"_prepareSearchers",value:function(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:"",t=[];if(this.options.tokenize)for(var n=e.split(this.options.tokenSeparator),o=0,r=n.length;o<r;o+=1)t.push(new i(n[o],this.options));return{tokenSearchers:t,fullSearcher:new i(e,this.options)}}},{key:"_search",value:function(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:[],t=arguments[1],n=this.list,o={},r=[];if("string"==typeof n[0]){for(var i=0,s=n.length;i<s;i+=1)this._analyze({key:"",value:n[i],record:i,index:i},{resultMap:o,results:r,tokenSearchers:e,fullSearcher:t});return{weights:null,results:r}}for(var a={},l=0,c=n.length;l<c;l+=1)for(var u=n[l],h=0,p=this.options.keys.length;h<p;h+=1){var d=this.options.keys[h];if("string"!=typeof d){if(a[d.name]={weight:1-d.weight||1},d.weight<=0||1<d.weight)throw new Error("Key weight has to be > 0 and <= 1");d=d.name}else a[d]={weight:1};this._analyze({key:d,value:this.options.getFn(u,d),record:u,index:l},{resultMap:o,results:r,tokenSearchers:e,fullSearcher:t})}return{weights:a,results:r}}},{key:"_analyze",value:function(e,t){var n=e.key,o=e.arrayIndex,r=void 0===o?-1:o,i=e.value,s=e.record,a=e.index,l=t.tokenSearchers,c=void 0===l?[]:l,u=t.fullSearcher,h=void 0===u?[]:u,p=t.resultMap,d=void 0===p?{}:p,f=t.results,v=void 0===f?[]:f;if(null!=i){var g=!1,_=-1,m=0;if("string"==typeof i){this._log("\nKey: "+(""===n?"-":n));var y=h.search(i);if(this._log('Full text: "'+i+'", score: '+y.score),this.options.tokenize){for(var k=i.split(this.options.tokenSeparator),b=[],x=0;x<c.length;x+=1){var S=c[x];this._log('\nPattern: "'+S.pattern+'"');for(var w=!1,L=0;L<k.length;L+=1){var C=k[L],M=S.search(C),A={};M.isMatch?(A[C]=M.score,w=g=!0,b.push(M.score)):(A[C]=1,this.options.matchAllTokens||b.push(1)),this._log('Token: "'+C+'", score: '+A[C])}w&&(m+=1)}_=b[0];for(var I=b.length,N=1;N<I;N+=1)_+=b[N];_/=I,this._log("Token score average:",_)}var T=y.score;-1<_&&(T=(T+_)/2),this._log("Score average:",T);var O=!this.options.tokenize||!this.options.matchAllTokens||m>=c.length;if(this._log("\nCheck Matches: "+O),(g||y.isMatch)&&O){var P=d[a];P?P.output.push({key:n,arrayIndex:r,value:i,score:T,matchedIndices:y.matchedIndices}):(d[a]={item:s,output:[{key:n,arrayIndex:r,value:i,score:T,matchedIndices:y.matchedIndices}]},v.push(d[a]))}}else if(U(i))for(var j=0,E=i.length;j<E;j+=1)this._analyze({key:n,arrayIndex:j,value:i[j],record:s,index:a},{resultMap:d,results:v,tokenSearchers:c,fullSearcher:h})}}},{key:"_computeScore",value:function(e,t){this._log("\n\nComputing score:\n");for(var n=0,o=t.length;n<o;n+=1){for(var r=t[n].output,i=r.length,s=1,a=1,l=0;l<i;l+=1){var c=e?e[r[l].key].weight:1,u=(1===c?r[l].score:r[l].score||.001)*c;1!==c?a=Math.min(a,u):s*=r[l].nScore=u}t[n].score=1===a?s:a,this._log(t[n])}}},{key:"_sort",value:function(e){this._log("\n\nSorting...."),e.sort(this.options.sortFn)}},{key:"_format",value:function(e){var t=[];this.options.verbose&&this._log("\n\nOutput:\n\n",JSON.stringify(e));var n=[];this.options.includeMatches&&n.push(function(e,t){var n=e.output;t.matches=[];for(var o=0,r=n.length;o<r;o+=1){var i=n[o];if(0!==i.matchedIndices.length){var s={indices:i.matchedIndices,value:i.value};i.key&&(s.key=i.key),i.hasOwnProperty("arrayIndex")&&-1<i.arrayIndex&&(s.arrayIndex=i.arrayIndex),t.matches.push(s)}}}),this.options.includeScore&&n.push(function(e,t){t.score=e.score});for(var o=0,r=e.length;o<r;o+=1){var i=e[o];if(this.options.id&&(i.item=this.options.getFn(i.item,this.options.id)[0]),n.length){for(var s={item:i.item},a=0,l=n.length;a<l;a+=1)n[a](i,s);t.push(s)}else t.push(i.item)}return t}},{key:"_log",value:function(){var e;this.options.verbose&&(e=console).log.apply(e,arguments)}}]),D}();e.exports=r}])},"object"==typeof n&&"object"==typeof t?t.exports=r():"function"==typeof define&&define.amd?define("Fuse",[],r):"object"==typeof n?n.Fuse=r():o.Fuse=r()},{}],3:[function(e,m,t){!function(){"use strict";function n(e,t){var n,o,r,i,s=h;for(i=arguments.length;2<i--;)u.push(arguments[i]);for(t&&null!=t.children&&(u.length||u.push(t.children),delete t.children);u.length;)if((o=u.pop())&&void 0!==o.pop)for(i=o.length;i--;)u.push(o[i]);else"boolean"==typeof o&&(o=null),(r="function"!=typeof e)&&(null==o?o="":"number"==typeof o?o=String(o):"string"!=typeof o&&(r=!1)),r&&n?s[s.length-1]+=o:s===h?s=[o]:s.push(o),n=r;var a=new c;return a.nodeName=e,a.children=s,a.attributes=null==t?void 0:t,a.key=null==t?void 0:t.key,void 0!==R.vnode&&R.vnode(a),a}function C(e,t){for(var n in t)e[n]=t[n];return e}function i(e){!e.__d&&(e.__d=!0)&&1==d.push(e)&&(R.debounceRendering||r)(t)}function t(){var e,t=d;for(d=[];e=t.pop();)e.__d&&E(e)}function L(e,t){return e.__n===t||e.nodeName.toLowerCase()===t.toLowerCase()}function M(e){var t=C({},e.attributes);t.children=e.children;var n=e.nodeName.defaultProps;if(void 0!==n)for(var o in n)void 0===t[o]&&(t[o]=n[o]);return t}function A(e){var t=e.parentNode;t&&t.removeChild(e)}function v(e,t,n,o,r){if("className"===t&&(t="class"),"key"===t);else if("ref"===t)n&&n(null),o&&o(e);else if("class"!==t||r)if("style"===t){if(o&&"string"!=typeof o&&"string"!=typeof n||(e.style.cssText=o||""),o&&"object"==typeof o){if("string"!=typeof n)for(var i in n)i in o||(e.style[i]="");for(var i in o)e.style[i]="number"==typeof o[i]&&!1===p.test(i)?o[i]+"px":o[i]}}else if("dangerouslySetInnerHTML"===t)o&&(e.innerHTML=o.__html||"");else if("o"==t[0]&&"n"==t[1]){var s=t!==(t=t.replace(/Capture$/,""));t=t.toLowerCase().substring(2),o?n||e.addEventListener(t,l,s):e.removeEventListener(t,l,s),(e.__l||(e.__l={}))[t]=o}else if("list"!==t&&"type"!==t&&!r&&t in e){try{e[t]=null==o?"":o}catch(e){}null!=o&&!1!==o||"spellcheck"==t||e.removeAttribute(t)}else{var a=r&&t!==(t=t.replace(/^xlink:?/,""));null==o||!1===o?a?e.removeAttributeNS("http://www.w3.org/1999/xlink",t.toLowerCase()):e.removeAttribute(t):"function"!=typeof o&&(a?e.setAttributeNS("http://www.w3.org/1999/xlink",t.toLowerCase(),o):e.setAttribute(t,o))}else e.className=o||""}function l(e){return this.__l[e.type](R.event&&R.event(e)||e)}function I(){for(var e;e=D.pop();)R.afterMount&&R.afterMount(e),e.componentDidMount&&e.componentDidMount()}function N(e,t,n,o,r,i){F++||(g=null!=r&&void 0!==r.ownerSVGElement,_=null!=e&&!("__preactattr_"in e));var s=T(e,t,n,o,i);return r&&s.parentNode!==r&&r.appendChild(s),--F||(_=!1,i||I()),s}function T(e,t,n,o,r){var i=e,s=g;if(null!=t&&"boolean"!=typeof t||(t=""),"string"==typeof t||"number"==typeof t)return e&&void 0!==e.splitText&&e.parentNode&&(!e._component||r)?e.nodeValue!=t&&(e.nodeValue=t):(i=document.createTextNode(t),e&&(e.parentNode&&e.parentNode.replaceChild(i,e),O(e,!0))),i.__preactattr_=!0,i;var a,l,c=t.nodeName;if("function"==typeof c)return function(e,t,n,o){var r=e&&e._component,i=r,s=e,a=r&&e._componentConstructor===t.nodeName,l=a,c=M(t);for(;r&&!l&&(r=r.__u);)l=r.constructor===t.nodeName;r&&l&&(!o||r._component)?(j(r,c,3,n,o),e=r.base):(i&&!a&&(U(i),e=s=null),r=P(t.nodeName,c,n),e&&!r.__b&&(r.__b=e,s=null),j(r,c,1,n,o),e=r.base,s&&e!==s&&(s._component=null,O(s,!1)));return e}(e,t,n,o);if(g="svg"===c||"foreignObject"!==c&&g,c=String(c),(!e||!L(e,c))&&(a=c,(l=g?document.createElementNS("http://www.w3.org/2000/svg",a):document.createElement(a)).__n=a,i=l,e)){for(;e.firstChild;)i.appendChild(e.firstChild);e.parentNode&&e.parentNode.replaceChild(i,e),O(e,!0)}var u=i.firstChild,h=i.__preactattr_,p=t.children;if(null==h){h=i.__preactattr_={};for(var d=i.attributes,f=d.length;f--;)h[d[f].name]=d[f].value}return!_&&p&&1===p.length&&"string"==typeof p[0]&&null!=u&&void 0!==u.splitText&&null==u.nextSibling?u.nodeValue!=p[0]&&(u.nodeValue=p[0]):(p&&p.length||null!=u)&&function(e,t,n,o,r){var i,s,a,l,c,u=e.childNodes,h=[],p={},d=0,f=0,v=u.length,g=0,_=t?t.length:0;if(0!==v)for(var m=0;m<v;m++){var y=u[m],k=y.__preactattr_,b=_&&k?y._component?y._component.__k:k.key:null;null!=b?(d++,p[b]=y):(k||(void 0!==y.splitText?!r||y.nodeValue.trim():r))&&(h[g++]=y)}if(0!==_)for(var m=0;m<_;m++){l=t[m],c=null;var b=l.key;if(null!=b)d&&void 0!==p[b]&&(c=p[b],p[b]=void 0,d--);else if(f<g)for(i=f;i<g;i++)if(void 0!==h[i]&&(x=s=h[i],w=r,"string"==typeof(S=l)||"number"==typeof S?void 0!==x.splitText:"string"==typeof S.nodeName?!x._componentConstructor&&L(x,S.nodeName):w||x._componentConstructor===S.nodeName)){c=s,h[i]=void 0,i===g-1&&g--,i===f&&f++;break}c=T(c,l,n,o),a=u[m],c&&c!==e&&c!==a&&(null==a?e.appendChild(c):c===a.nextSibling?A(a):e.insertBefore(c,a))}var x,S,w;if(d)for(var m in p)void 0!==p[m]&&O(p[m],!1);for(;f<=g;)void 0!==(c=h[g--])&&O(c,!1)}(i,p,n,o,_||null!=h.dangerouslySetInnerHTML),function(e,t,n){var o;for(o in n)t&&null!=t[o]||null==n[o]||v(e,o,n[o],n[o]=void 0,g);for(o in t)"children"===o||"innerHTML"===o||o in n&&t[o]===("value"===o||"checked"===o?e[o]:n[o])||v(e,o,n[o],n[o]=t[o],g)}(i,t.attributes,h),g=s,i}function O(e,t){var n=e._component;n?U(n):(null!=e.__preactattr_&&e.__preactattr_.ref&&e.__preactattr_.ref(null),!1!==t&&null!=e.__preactattr_||A(e),o(e))}function o(e){for(e=e.lastChild;e;){var t=e.previousSibling;O(e,!0),e=t}}function P(e,t,n){var o,r=f.length;for(e.prototype&&e.prototype.render?(o=new e(t,n),a.call(o,t,n)):((o=new a(t,n)).constructor=e,o.render=s);r--;)if(f[r].constructor===e)return o.__b=f[r].__b,f.splice(r,1),o;return o}function s(e,t,n){return this.constructor(e,n)}function j(e,t,n,o,r){e.__x||(e.__x=!0,e.__r=t.ref,e.__k=t.key,delete t.ref,delete t.key,void 0===e.constructor.getDerivedStateFromProps&&(!e.base||r?e.componentWillMount&&e.componentWillMount():e.componentWillReceiveProps&&e.componentWillReceiveProps(t,o)),o&&o!==e.context&&(e.__c||(e.__c=e.context),e.context=o),e.__p||(e.__p=e.props),e.props=t,e.__x=!1,0!==n&&(1!==n&&!1===R.syncComponentUpdates&&e.base?i(e):E(e,1,r)),e.__r&&e.__r(e))}function E(e,t,n,o){if(!e.__x){var r,i,s,a=e.props,l=e.state,c=e.context,u=e.__p||a,h=e.__s||l,p=e.__c||c,d=e.base,f=e.__b,v=d||f,g=e._component,_=!1,m=p;if(e.constructor.getDerivedStateFromProps&&(l=C(C({},l),e.constructor.getDerivedStateFromProps(a,l)),e.state=l),d&&(e.props=u,e.state=h,e.context=p,2!==t&&e.shouldComponentUpdate&&!1===e.shouldComponentUpdate(a,l,c)?_=!0:e.componentWillUpdate&&e.componentWillUpdate(a,l,c),e.props=a,e.state=l,e.context=c),e.__p=e.__s=e.__c=e.__b=null,e.__d=!1,!_){r=e.render(a,l,c),e.getChildContext&&(c=C(C({},c),e.getChildContext())),d&&e.getSnapshotBeforeUpdate&&(m=e.getSnapshotBeforeUpdate(u,h));var y,k,b=r&&r.nodeName;if("function"==typeof b){var x=M(r);(i=g)&&i.constructor===b&&x.key==i.__k?j(i,x,1,c,!1):(y=i,e._component=i=P(b,x,c),i.__b=i.__b||f,i.__u=e,j(i,x,0,c,!1),E(i,1,n,!0)),k=i.base}else s=v,(y=g)&&(s=e._component=null),(v||1===t)&&(s&&(s._component=null),k=N(s,r,c,n||!d,v&&v.parentNode,!0));if(v&&k!==v&&i!==g){var S=v.parentNode;S&&k!==S&&(S.replaceChild(k,v),y||(v._component=null,O(v,!1)))}if(y&&U(y),(e.base=k)&&!o){for(var w=e,L=e;L=L.__u;)(w=L).base=k;k._component=w,k._componentConstructor=w.constructor}}for(!d||n?D.unshift(e):_||(e.componentDidUpdate&&e.componentDidUpdate(u,h,m),R.afterUpdate&&R.afterUpdate(e));e.__h.length;)e.__h.pop().call(e);F||o||I()}}function U(e){R.beforeUnmount&&R.beforeUnmount(e);var t=e.base;e.__x=!0,e.componentWillUnmount&&e.componentWillUnmount(),e.base=null;var n=e._component;n?U(n):t&&(t.__preactattr_&&t.__preactattr_.ref&&t.__preactattr_.ref(null),A(e.__b=t),f.push(e),o(t)),e.__r&&e.__r(null)}function a(e,t){this.__d=!0,this.context=t,this.props=e,this.state=this.state||{},this.__h=[]}var c=function(){},R={},u=[],h=[],r="function"==typeof Promise?Promise.resolve().then.bind(Promise.resolve()):setTimeout,p=/acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i,d=[],D=[],F=0,g=!1,_=!1,f=[];C(a.prototype,{setState:function(e,t){this.__s||(this.__s=this.state),this.state=C(C({},this.state),"function"==typeof e?e(this.state,this.props):e),t&&this.__h.push(t),i(this)},forceUpdate:function(e){e&&this.__h.push(e),E(this,2)},render:function(){}});var e={h:n,createElement:n,cloneElement:function(e,t){return n(e.nodeName,C(C({},e.attributes),t),2<arguments.length?[].slice.call(arguments,2):e.children)},Component:a,render:function(e,t,n){return N(n,e,{},!1,t,!1)},rerender:t,options:R};void 0!==m?m.exports=e:self.preact=e}()},{}]},{},[1]);+//# sourceMappingURL=quick-jump.min.js.map
resources/html/solarized.css view
@@ -53,3 +53,45 @@ a:hover, a.hover-highlight { background-color: #eee8d5; }++span.annot{+ position:relative;+ color:#000;+ text-decoration:none+ }++span.annot:hover{z-index:25; background-color:#ff0}++span.annot span.annottext{+ display: none;+ border-radius: 5px 5px;++ -moz-border-radius: 5px;+ -webkit-border-radius: 5px;++ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.1);+ -webkit-box-shadow: 5px 5px rgba(0, 0, 0, 0.1);+ -moz-box-shadow: 5px 5px rgba(0, 0, 0, 0.1);++ position: absolute;+ left: 1em; top: 2em;+ z-index: 99;+ margin-left: 5;+ background: #FFFFAA;+ border: 2px solid #FFAD33;+ padding: 0.8em 1em;+}++span.annot:hover span.annottext{+ display:block;+}++/* This bridges the gap so you can mouse into the tooltip without it disappearing */+span.annot span.annottext:before{+ content: "";+ position: absolute;+ left: -1em; top: -1em;+ background: #FFFFFF00;+ z-index:-1;+ padding: 2em 2em;+}
src/Documentation/Haddock.hs view
@@ -8,7 +8,7 @@ -- Stability : experimental -- Portability : portable ----- The Haddock API: A rudimentory, highly experimental API exposing some of+-- 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 (@@ -39,7 +39,8 @@ DocH(..), Example(..), Hyperlink(..),- DocMarkup(..),+ DocMarkup,+ DocMarkupH(..), Documentation(..), ArgMap, AliasMap,@@ -51,9 +52,7 @@ -- * Interface files InterfaceFile(..), readInterfaceFile,- nameCacheFromGhc, freshNameCache,- NameCacheAccessor, -- * Flags and options Flag(..),@@ -69,12 +68,11 @@ withGhc ) where -+import Documentation.Haddock.Markup (markup) import Haddock.InterfaceFile import Haddock.Interface import Haddock.Types import Haddock.Options-import Haddock.Utils import Haddock
src/Haddock.hs view
@@ -1,6 +1,12 @@-{-# OPTIONS_GHC -Wwarn #-}-{-# LANGUAGE CPP, ScopedTypeVariables, Rank2Types #-}-{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# OPTIONS_GHC -Wwarn #-} ----------------------------------------------------------------------------- -- | -- Module : Haddock@@ -25,54 +31,59 @@ withGhc ) where -import Data.Version import Haddock.Backends.Xhtml+import Haddock.Backends.Xhtml.Meta import Haddock.Backends.Xhtml.Themes (getThemes) import Haddock.Backends.LaTeX import Haddock.Backends.Hoogle import Haddock.Backends.Hyperlinker import Haddock.Interface+import Haddock.Interface.Json import Haddock.Parser import Haddock.Types import Haddock.Version import Haddock.InterfaceFile import Haddock.Options import Haddock.Utils+import Haddock.GhcUtils (modifySessionDynFlags, setOutputDir) +import Control.DeepSeq (force) import Control.Monad hiding (forM_)-import Control.Applicative-import Data.Foldable (forM_)-import Data.List (isPrefixOf)+import Control.Monad.IO.Class (MonadIO(..))+import Data.Bifunctor (second)+import Data.Foldable (forM_, foldl')+import Data.Traversable (for)+import Data.List (find, isPrefixOf, nub) import Control.Exception import Data.Maybe import Data.IORef-import Data.Map (Map)-import qualified Data.Map as Map+import Data.Map.Strict (Map)+import Data.Version (makeVersion)+import qualified Data.Map.Strict as Map import System.IO import System.Exit--#if defined(mingw32_HOST_OS)-import Foreign-import Foreign.C-import Data.Int-#endif+import System.FilePath #ifdef IN_GHC_TREE-import System.FilePath+import System.Environment (getExecutablePath) #else import qualified GHC.Paths as GhcPaths import Paths_haddock_api (getDataDir)-import System.Directory (doesDirectoryExist) #endif+import System.Directory (doesDirectoryExist, getTemporaryDirectory) +import Text.ParserCombinators.ReadP (readP_to_S) import GHC hiding (verbosity)-import Config-import DynFlags hiding (projectVersion, verbosity)-import StaticFlags (discardStaticFlags)-import Packages-import Panic (handleGhcException)-import Module-import FastString+import GHC.Settings.Config+import GHC.Driver.Config.Logger (initLogFlags)+import GHC.Driver.Env+import GHC.Driver.Session hiding (projectVersion, verbosity)+import GHC.Utils.Error+import GHC.Utils.Logger+import GHC.Types.Name.Cache+import GHC.Unit+import GHC.Utils.Panic (handleGhcException)+import GHC.Data.FastString -------------------------------------------------------------------------------- -- * Exception handling@@ -147,101 +158,181 @@ -- or which exits with an error or help message. (flags, files) <- parseHaddockOpts args shortcutFlags flags- qual <- case qualification flags of {Left msg -> throwE msg; Right q -> return q}+ qual <- rightOrThrowE (qualification flags)+ sinceQual <- rightOrThrowE (sinceQualification flags) - -- inject dynamic-too into flags before we proceed- flags' <- ghc flags $ do+ -- Inject dynamic-too into ghc options if the ghc we are using was built with+ -- dynamic linking+ flags'' <- ghc flags $ do df <- getDynFlags case lookup "GHC Dynamic" (compilerInfo df) of Just "YES" -> return $ Flag_OptGhc "-dynamic-too" : flags _ -> return flags + -- Inject `-j` into ghc options, if given to Haddock+ flags' <- pure $ case optParCount flags'' of+ Nothing -> flags''+ Just Nothing -> Flag_OptGhc "-j" : flags''+ Just (Just n) -> Flag_OptGhc ("-j" ++ show n) : flags''++ -- Whether or not to bypass the interface version check+ let noChecks = Flag_BypassInterfaceVersonCheck `elem` flags++ -- Create a temporary directory and redirect GHC output there (unless user+ -- requested otherwise).+ --+ -- Output dir needs to be set before calling 'depanal' since 'depanal' uses it+ -- to compute output file names that are stored in the 'DynFlags' of the+ -- resulting 'ModSummary's.+ let withDir | Flag_NoTmpCompDir `elem` flags = id+ | otherwise = withTempOutputDir++ -- Output warnings about potential misuse of some flags unless (Flag_NoWarnings `elem` flags) $ do hypSrcWarnings flags- forM_ (warnings args) $ \warning -> do- hPutStrLn stderr warning-- ghc flags' $ do+ mapM_ (hPutStrLn stderr) (optGhcWarnings args)+ when noChecks $+ hPutStrLn stderr noCheckWarning + ghc flags' $ withDir $ do dflags <- getDynFlags+ logger <- getLogger+ !unit_state <- hsc_units <$> getSession + -- If any --show-interface was used, show the given interfaces+ forM_ (optShowInterfaceFile flags) $ \path -> liftIO $ do+ name_cache <- freshNameCache+ mIfaceFile <- readInterfaceFiles name_cache [(("", Nothing), Visible, path)] noChecks+ forM_ mIfaceFile $ \(_,_,_, ifaceFile) -> do+ putMsg logger $ renderJson (jsonInterfaceFile ifaceFile)++ -- If we were given source files to generate documentation from, do it if not (null files) then do (packages, ifaces, homeLinks) <- readPackagesAndProcessModules flags files+ let packageInfo = PackageInfo { piPackageName =+ fromMaybe (PackageName mempty) (optPackageName flags)+ , piPackageVersion =+ fromMaybe (makeVersion []) (optPackageVersion flags)+ } -- Dump an "interface file" (.haddock file), if requested. forM_ (optDumpInterfaceFile flags) $ \path -> liftIO $ do writeInterfaceFile path InterfaceFile { ifInstalledIfaces = map toInstalledIface ifaces+ , ifPackageInfo = packageInfo , ifLinkEnv = homeLinks } -- Render the interfaces.- liftIO $ renderStep dflags flags qual packages ifaces+ liftIO $ renderStep logger dflags unit_state flags sinceQual qual packages ifaces + -- If we were not given any input files, error if documentation was+ -- requested else do when (any (`elem` [Flag_Html, Flag_Hoogle, Flag_LaTeX]) flags) $ throwE "No input file(s)." -- Get packages supplied with --read-interface.- packages <- liftIO $ readInterfaceFiles freshNameCache (readIfaceArgs flags)+ name_cache <- liftIO $ freshNameCache+ packages <- liftIO $ readInterfaceFiles name_cache (readIfaceArgs flags) noChecks -- Render even though there are no input files (usually contents/index).- liftIO $ renderStep dflags flags qual packages []+ liftIO $ renderStep logger dflags unit_state flags sinceQual qual packages [] +-- | Run the GHC action using a temporary output directory+withTempOutputDir :: Ghc a -> Ghc a+withTempOutputDir action = do+ tmp <- liftIO getTemporaryDirectory+ x <- liftIO getProcessID+ let dir = tmp </> ".haddock-" ++ show x+ modifySessionDynFlags (setOutputDir dir)+ withTempDir dir action+ -- | Create warnings about potential misuse of -optghc-warnings :: [String] -> [String]-warnings = map format . filter (isPrefixOf "-optghc")+optGhcWarnings :: [String] -> [String]+optGhcWarnings = map format . filter (isPrefixOf "-optghc") where format arg = concat ["Warning: `", arg, "' means `-o ", drop 2 arg, "', did you mean `-", arg, "'?"] +-- | Create a warning about bypassing the interface version check+noCheckWarning :: String+noCheckWarning = "Warning: `--bypass-interface-version-check' can cause " +++ "Haddock to crash when reading Haddock interface files." withGhc :: [Flag] -> Ghc a -> IO a withGhc flags action = do- libDir <- fmap snd (getGhcDirs flags)+ libDir <- fmap (fromMaybe (error "No GhcDir found") . snd) (getGhcDirs flags) -- Catches all GHC source errors, then prints and re-throws them. let handleSrcErrors action' = flip handleSourceError action' $ \err -> do printException err liftIO exitFailure+ needHieFiles = Flag_HyperlinkedSource `elem` flags - withGhc' libDir (ghcFlags flags) (\_ -> handleSrcErrors action)+ withGhc' libDir needHieFiles (ghcFlags flags) (\_ -> handleSrcErrors action) readPackagesAndProcessModules :: [Flag] -> [String]- -> Ghc ([(DocPaths, InterfaceFile)], [Interface], LinkEnv)+ -> Ghc ([(DocPaths, Visibility, FilePath, InterfaceFile)], [Interface], LinkEnv) readPackagesAndProcessModules flags files = do- -- Get packages supplied with --read-interface.- packages <- readInterfaceFiles nameCacheFromGhc (readIfaceArgs flags)+ -- Whether or not we bypass the interface file version check+ let noChecks = Flag_BypassInterfaceVersonCheck `elem` flags - -- Create the interfaces -- this is the core part of Haddock.- let ifaceFiles = map snd packages+ -- Read package dependency interface files supplied with --read-interface+ name_cache <- hsc_NC <$> getSession+ packages <- liftIO $ readInterfaceFiles name_cache (readIfaceArgs flags) noChecks++ -- Create the interfaces for the given modules -- this is the core part of Haddock+ let ifaceFiles = map (\(_, _, _, ifaceFile) -> ifaceFile) packages (ifaces, homeLinks) <- processModules (verbosity flags) files flags ifaceFiles return (packages, ifaces, homeLinks) -renderStep :: DynFlags -> [Flag] -> QualOption -> [(DocPaths, InterfaceFile)] -> [Interface] -> IO ()-renderStep dflags flags qual pkgs interfaces = do- updateHTMLXRefs pkgs+renderStep :: Logger -> DynFlags -> UnitState -> [Flag] -> SinceQual -> QualOption+ -> [(DocPaths, Visibility, FilePath, InterfaceFile)] -> [Interface] -> IO ()+renderStep logger dflags unit_state flags sinceQual nameQual pkgs interfaces = do+ updateHTMLXRefs (map (\(docPath, _ifaceFilePath, _showModules, ifaceFile) ->+ ( case baseUrl flags of+ Nothing -> fst docPath+ Just url -> url </> packageName (ifUnitId ifaceFile)+ , ifaceFile)) pkgs) let- ifaceFiles = map snd pkgs- installedIfaces = concatMap ifInstalledIfaces ifaceFiles+ installedIfaces =+ map+ (\(_, showModules, ifaceFilePath, ifaceFile)+ -> (ifaceFilePath, mkPackageInterfaces showModules ifaceFile))+ pkgs extSrcMap = Map.fromList $ do- ((_, Just path), ifile) <- pkgs+ ((_, Just path), _, _, ifile) <- pkgs iface <- ifInstalledIfaces ifile return (instMod iface, path)- render dflags flags qual interfaces installedIfaces extSrcMap-+ render logger dflags unit_state flags sinceQual nameQual interfaces installedIfaces extSrcMap+ where+ -- get package name from unit-id+ packageName :: Unit -> String+ packageName unit =+ case lookupUnit unit_state unit of+ Nothing -> show unit+ Just pkg -> unitPackageNameString pkg -- | Render the interfaces with whatever backend is specified in the flags.-render :: DynFlags -> [Flag] -> QualOption -> [Interface] -> [InstalledInterface] -> Map Module FilePath -> IO ()-render dflags flags qual ifaces installedIfaces extSrcMap = do+render :: Logger -> DynFlags -> UnitState -> [Flag] -> SinceQual -> QualOption -> [Interface]+ -> [(FilePath, PackageInterfaces)] -> Map Module FilePath -> IO ()+render log' dflags unit_state flags sinceQual qual ifaces packages extSrcMap = do let+ packageInfo = PackageInfo { piPackageName = fromMaybe (PackageName mempty)+ $ optPackageName flags+ , piPackageVersion = fromMaybe (makeVersion [])+ $ optPackageVersion flags+ }+ title = fromMaybe "" (optTitle flags) unicode = Flag_UseUnicode `elem` flags pretty = Flag_PrettyHtml `elem` flags opt_wiki_urls = wikiUrls flags+ opt_base_url = baseUrl flags opt_contents_url = optContentsUrl flags opt_index_url = optIndexUrl flags odir = outputDir flags@@ -251,113 +342,190 @@ dflags' | unicode = gopt_set dflags Opt_PrintUnicodeSyntax | otherwise = dflags+ logger = setLogFlags log' (initLogFlags dflags') visibleIfaces = [ i | i <- ifaces, OptHide `notElem` ifaceOptions i ] - -- /All/ visible interfaces including external package modules.- allIfaces = map toInstalledIface ifaces ++ installedIfaces- allVisibleIfaces = [ i | i <- allIfaces, OptHide `notElem` instOptions i ]+ -- /All/ interfaces including external package modules, grouped by+ -- interface file (package).+ allPackages :: [PackageInterfaces]+ allPackages = [PackageInterfaces+ { piPackageInfo = packageInfo+ , piVisibility = Visible+ , piInstalledInterfaces = map toInstalledIface ifaces+ }]+ ++ map snd packages - pkgMod = ifaceMod (head ifaces)- pkgKey = moduleUnitId pkgMod- pkgStr = Just (unitIdString pkgKey)- pkgNameVer = modulePackageInfo dflags flags pkgMod+ -- /All/ visible interfaces including external package modules, grouped by+ -- interface file (package).+ allVisiblePackages :: [PackageInterfaces]+ allVisiblePackages = [ pinfo { piInstalledInterfaces =+ filter (\i -> OptHide `notElem` instOptions i)+ piInstalledInterfaces+ }+ | pinfo@PackageInterfaces+ { piVisibility = Visible+ , piInstalledInterfaces+ } <- allPackages+ ] + -- /All/ installed interfaces.+ allInstalledIfaces :: [InstalledInterface]+ allInstalledIfaces = concatMap (piInstalledInterfaces . snd) packages++ pkgMod = fmap ifaceMod (listToMaybe ifaces)+ pkgKey = fmap moduleUnit pkgMod+ pkgStr = fmap unitString pkgKey+ pkgNameVer = modulePackageInfo unit_state flags pkgMod+ pkgName = fmap (unpackFS . (\(PackageName n) -> n)) (fst pkgNameVer)+ sincePkg = case sinceQual of+ External -> pkgName+ Always -> Nothing+ (srcBase, srcModule, srcEntity, srcLEntity) = sourceUrls flags srcModule' | Flag_HyperlinkedSource `elem` flags = Just hypSrcModuleUrlFormat | otherwise = srcModule - srcMap = mkSrcMap $ Map.union+ srcMap = Map.union (Map.map SrcExternal extSrcMap) (Map.fromList [ (ifaceMod iface, SrcLocal) | iface <- ifaces ]) - pkgSrcMap = Map.mapKeys moduleUnitId extSrcMap+ pkgSrcMap = Map.mapKeys moduleUnit extSrcMap pkgSrcMap'- | Flag_HyperlinkedSource `elem` flags =- Map.insert pkgKey hypSrcModuleNameUrlFormat pkgSrcMap- | Just srcNameUrl <- srcEntity = Map.insert pkgKey srcNameUrl pkgSrcMap+ | Flag_HyperlinkedSource `elem` flags+ , Just k <- pkgKey+ = Map.insert k hypSrcModuleNameUrlFormat pkgSrcMap+ | Just srcNameUrl <- srcEntity+ , Just k <- pkgKey+ = Map.insert k srcNameUrl pkgSrcMap | otherwise = pkgSrcMap -- TODO: Get these from the interface files as with srcMap pkgSrcLMap'- | Flag_HyperlinkedSource `elem` flags =- Map.singleton pkgKey hypSrcModuleLineUrlFormat- | Just path <- srcLEntity = Map.singleton pkgKey path+ | Flag_HyperlinkedSource `elem` flags+ , Just k <- pkgKey+ = Map.singleton k hypSrcModuleLineUrlFormat+ | Just path <- srcLEntity+ , Just k <- pkgKey+ = Map.singleton k path | otherwise = Map.empty sourceUrls' = (srcBase, srcModule', pkgSrcMap', pkgSrcLMap') + installedMap :: Map Module InstalledInterface+ installedMap = Map.fromList [ (unwire (instMod iface), iface) | iface <- allInstalledIfaces ]++ -- The user gives use base-4.9.0.0, but the InstalledInterface+ -- records the *wired in* identity base. So untranslate it+ -- so that we can service the request.+ unwire :: Module -> Module+ unwire m = m { moduleUnit = unwireUnit unit_state (moduleUnit m) }++ reexportedIfaces <- concat `fmap` (for (reexportFlags flags) $ \mod_str -> do+ let warn' = hPutStrLn stderr . ("Warning: " ++)+ case readP_to_S parseHoleyModule mod_str of+ [(m, "")]+ | Just iface <- Map.lookup m installedMap+ -> return [iface]+ | otherwise+ -> warn' ("Cannot find reexported module '" ++ mod_str ++ "'") >> return []+ _ -> warn' ("Cannot parse reexported module flag '" ++ mod_str ++ "'") >> return [])+ libDir <- getHaddockLibDir flags- prologue <- getPrologue dflags' flags+ !prologue <- force <$> getPrologue dflags' flags themes <- getThemes libDir flags >>= either bye return + let withQuickjump = Flag_QuickJumpIndex `elem` flags+ withBaseURL = isJust+ . find (\flag -> case flag of+ Flag_BaseURL base_url ->+ base_url /= "." && base_url /= "./"+ _ -> False+ )+ $ flags+ when (Flag_GenIndex `elem` flags) $ do- ppHtmlIndex odir title pkgStr- themes opt_mathjax opt_contents_url sourceUrls' opt_wiki_urls- allVisibleIfaces pretty- copyHtmlBits odir libDir themes+ withTiming logger "ppHtmlIndex" (const ()) $ do+ _ <- {-# SCC ppHtmlIndex #-}+ ppHtmlIndex odir title pkgStr+ themes opt_mathjax opt_contents_url sourceUrls' opt_wiki_urls+ withQuickjump+ (concatMap piInstalledInterfaces allVisiblePackages) pretty+ return () + unless withBaseURL $+ copyHtmlBits odir libDir themes withQuickjump+ when (Flag_GenContents `elem` flags) $ do- ppHtmlContents dflags' odir title pkgStr- themes opt_mathjax opt_index_url sourceUrls' opt_wiki_urls- allVisibleIfaces True prologue pretty- (makeContentsQual qual)- copyHtmlBits odir libDir themes+ withTiming logger "ppHtmlContents" (const ()) $ do+ _ <- {-# SCC ppHtmlContents #-}+ ppHtmlContents unit_state odir title pkgStr+ themes opt_mathjax opt_index_url sourceUrls' opt_wiki_urls+ withQuickjump+ allVisiblePackages True prologue pretty+ sincePkg (makeContentsQual qual)+ return ()+ copyHtmlBits odir libDir themes withQuickjump + when withQuickjump $ void $+ ppJsonIndex odir sourceUrls' opt_wiki_urls+ unicode Nothing qual+ ifaces+ ( nub+ . map fst+ . filter ((== Visible) . piVisibility . snd)+ $ packages)+ when (Flag_Html `elem` flags) $ do- ppHtml dflags' title pkgStr visibleIfaces odir- prologue- themes opt_mathjax sourceUrls' opt_wiki_urls- opt_contents_url opt_index_url unicode qual- pretty- copyHtmlBits odir libDir themes+ withTiming logger "ppHtml" (const ()) $ do+ _ <- {-# SCC ppHtml #-}+ ppHtml unit_state title pkgStr visibleIfaces reexportedIfaces odir+ prologue+ themes opt_mathjax sourceUrls' opt_wiki_urls opt_base_url+ opt_contents_url opt_index_url unicode sincePkg packageInfo+ qual pretty withQuickjump+ return ()+ unless withBaseURL $ do+ copyHtmlBits odir libDir themes withQuickjump+ writeHaddockMeta odir withQuickjump -- TODO: we throw away Meta for both Hoogle and LaTeX right now, -- might want to fix that if/when these two get some work on them when (Flag_Hoogle `elem` flags) $ do case pkgNameVer of- Nothing -> putStrLn . unlines $+ (Just (PackageName pkgNameFS), mpkgVer) ->+ let+ pkgNameStr | unpackFS pkgNameFS == "main" && title /= [] = title+ | otherwise = unpackFS pkgNameFS++ pkgVer =+ fromMaybe (makeVersion []) mpkgVer+ in ppHoogle dflags' pkgNameStr pkgVer title (fmap _doc prologue)+ visibleIfaces odir+ _ -> putStrLn . unlines $ [ "haddock: Unable to find a package providing module "- ++ moduleNameString (moduleName pkgMod) ++ ", skipping Hoogle."+ ++ maybe "<no-mod>" (moduleNameString . moduleName) pkgMod+ ++ ", skipping Hoogle." , "" , " Perhaps try specifying the desired package explicitly" ++ " using the --package-name" , " and --package-version arguments." ]- Just (PackageName pkgNameFS, pkgVer) ->- let pkgNameStr | unpackFS pkgNameFS == "main" && title /= [] = title- | otherwise = unpackFS pkgNameFS- in ppHoogle dflags' pkgNameStr pkgVer title (fmap _doc prologue)- visibleIfaces odir when (Flag_LaTeX `elem` flags) $ do- ppLaTeX title pkgStr visibleIfaces odir (fmap _doc prologue) opt_latex_style- libDir+ withTiming logger "ppLatex" (const ()) $ do+ _ <- {-# SCC ppLatex #-}+ ppLaTeX title pkgStr visibleIfaces odir (fmap _doc prologue) opt_latex_style+ libDir+ return () when (Flag_HyperlinkedSource `elem` flags && not (null ifaces)) $ do- ppHyperlinkedSource odir libDir opt_source_css pretty srcMap ifaces---- | From GHC 7.10, this function has a potential to crash with a--- nasty message such as @expectJust getPackageDetails@ 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 and it is--- returned here if present: if it is not present, the error will--- occur. Nasty but that's how it is for now. Potential TODO.-modulePackageInfo :: DynFlags- -> [Flag] -- ^ Haddock flags are checked as they may- -- contain the package name or version- -- provided by the user which we- -- prioritise- -> Module -> Maybe (PackageName, Data.Version.Version)-modulePackageInfo dflags flags modu =- cmdline <|> pkgDb- where- cmdline = (,) <$> optPackageName flags <*> optPackageVersion flags- pkgDb = (\pkg -> (packageName pkg, packageVersion pkg)) <$> lookupPackage dflags (moduleUnitId modu)+ withTiming logger "ppHyperlinkedSource" (const ()) $ do+ _ <- {-# SCC ppHyperlinkedSource #-}+ ppHyperlinkedSource (verbosity flags) odir libDir opt_source_css pretty srcMap ifaces+ return () -------------------------------------------------------------------------------@@ -365,22 +533,22 @@ ------------------------------------------------------------------------------- -readInterfaceFiles :: MonadIO m- => NameCacheAccessor m- -> [(DocPaths, FilePath)]- -> m [(DocPaths, InterfaceFile)]-readInterfaceFiles name_cache_accessor pairs = do- catMaybes `liftM` mapM tryReadIface pairs+readInterfaceFiles :: NameCache+ -> [(DocPaths, Visibility, FilePath)]+ -> Bool+ -> IO [(DocPaths, Visibility, FilePath, InterfaceFile)]+readInterfaceFiles name_cache_accessor pairs bypass_version_check = do+ catMaybes `liftM` mapM ({-# SCC readInterfaceFile #-} tryReadIface) pairs where -- try to read an interface, warn if we can't- tryReadIface (paths, file) =- readInterfaceFile name_cache_accessor file >>= \case- Left err -> liftIO $ do+ tryReadIface (paths, vis, file) =+ readInterfaceFile name_cache_accessor file bypass_version_check >>= \case+ Left err -> do putStrLn ("Warning: Cannot read " ++ file ++ ":") putStrLn (" " ++ err) putStrLn "Skipping this interface." return Nothing- Right f -> return $ Just (paths, f)+ Right f -> return (Just (paths, vis, file, f)) -------------------------------------------------------------------------------@@ -390,84 +558,147 @@ -- | Start a GHC session with the -haddock flag set. Also turn off -- compilation and linking. Then run the given 'Ghc' action.-withGhc' :: String -> [String] -> (DynFlags -> Ghc a) -> IO a-withGhc' libDir flags ghcActs = runGhc (Just libDir) $ do- dynflags <- getSessionDynFlags- dynflags' <- parseGhcFlags (gopt_set dynflags Opt_Haddock) {- hscTarget = HscNothing,- ghcMode = CompManager,- ghcLink = NoLink- }- let dynflags'' = gopt_unset dynflags' Opt_SplitObjs- defaultCleanupHandler dynflags'' $ do- -- ignore the following return-value, which is a list of packages- -- that may need to be re-linked: Haddock doesn't do any- -- dynamic or static linking at all!- _ <- setSessionDynFlags dynflags''- ghcActs dynflags''+withGhc' :: String -> Bool -> [String] -> (DynFlags -> Ghc a) -> IO a+withGhc' libDir needHieFiles flags ghcActs = runGhc (Just libDir) $ do+ logger <- getLogger+ dynflags' <- parseGhcFlags logger =<< getSessionDynFlags++ -- We disable pattern match warnings because than can be very+ -- expensive to check+ let dynflags'' = unsetPatternMatchWarnings $ updOptLevel 0 dynflags'++ -- ignore the following return-value, which is a list of packages+ -- that may need to be re-linked: Haddock doesn't do any+ -- dynamic or static linking at all!+ _ <- setSessionDynFlags dynflags''+ ghcActs dynflags'' where- parseGhcFlags :: MonadIO m => DynFlags -> m DynFlags- parseGhcFlags dynflags = do+ -- ignore sublists of flags that start with "+RTS" and end in "-RTS"+ --+ -- See https://github.com/haskell/haddock/issues/666+ filterRtsFlags :: [String] -> [String]+ filterRtsFlags flgs = foldr go (const []) flgs True+ where go "-RTS" func _ = func True+ go "+RTS" func _ = func False+ go _ func False = func False+ go arg func True = arg : func True++ parseGhcFlags :: MonadIO m => Logger -> DynFlags -> m DynFlags+ parseGhcFlags logger dynflags = do -- TODO: handle warnings? - -- NOTA BENE: We _MUST_ discard any static flags here, because we cannot- -- rely on Haddock to parse them, as it only parses the DynFlags. Yet if- -- we pass any, Haddock will fail. Since StaticFlags are global to the- -- GHC invocation, there's also no way to reparse/save them to set them- -- again properly.- --- -- This is a bit of a hack until we get rid of the rest of the remaining- -- StaticFlags. See GHC issue #8276.- let flags' = discardStaticFlags flags- (dynflags', rest, _) <- parseDynamicFlags dynflags (map noLoc flags')+ let extra_opts | needHieFiles = [Opt_WriteHie, Opt_Haddock]+ | otherwise = [Opt_Haddock]+ dynflags' = (foldl' gopt_set dynflags extra_opts)+ { backend = noBackend+ , ghcMode = CompManager+ , ghcLink = NoLink+ }+ flags' = filterRtsFlags flags++ (dynflags'', rest, _) <- parseDynamicFlags logger dynflags' (map noLoc flags') if not (null rest) then throwE ("Couldn't parse GHC options: " ++ unwords flags')- else return dynflags'+ else return dynflags'' +unsetPatternMatchWarnings :: DynFlags -> DynFlags+unsetPatternMatchWarnings dflags =+ foldl' wopt_unset dflags pattern_match_warnings+ where+ pattern_match_warnings =+ [ Opt_WarnIncompletePatterns+ , Opt_WarnIncompleteUniPatterns+ , Opt_WarnIncompletePatternsRecUpd+ , Opt_WarnOverlappingPatterns+ ]+ ------------------------------------------------------------------------------- -- * Misc ------------------------------------------------------------------------------- -getHaddockLibDir :: [Flag] -> IO String+getHaddockLibDir :: [Flag] -> IO FilePath getHaddockLibDir flags = case [str | Flag_Lib str <- flags] of [] -> do #ifdef IN_GHC_TREE- getInTreeDir++ -- When in the GHC tree, we should be able to locate the "lib" folder+ -- based on the location of the current executable.+ base_dir <- getBaseDir -- Provided by GHC+ let res_dirs = [ d | Just d <- [base_dir] ] +++ #else- d <- getDataDir -- provided by Cabal- doesDirectoryExist d >>= \exists -> case exists of- True -> return d- False -> do- -- If directory does not exist then we are probably invoking from- -- ./dist/build/haddock/haddock so we use ./resources as a fallback.- doesDirectoryExist "resources" >>= \exists_ -> case exists_ of- True -> return "resources"- False -> die ("Haddock's resource directory (" ++ d ++ ") does not exist!\n")++ -- When Haddock was installed by @cabal@, the resources (which are listed+ -- under @data-files@ in the Cabal file) will have been copied to a+ -- special directory.+ data_dir <- getDataDir -- Provided by Cabal+ let res_dirs = [ data_dir ] +++ #endif- fs -> return (last fs) + -- When Haddock is built locally (eg. regular @cabal new-build@), the data+ -- directory does not exist and we are probably invoking from either+ -- @./haddock-api@ or @./@+ [ "resources"+ , "haddock-api/resources"+ ] -getGhcDirs :: [Flag] -> IO (String, String)+ res_dir <- check res_dirs+ case res_dir of+ Just p -> return p+ _ -> die "Haddock's resource directory does not exist!\n"++ fs -> return (last fs)+ where+ -- Pick the first path that corresponds to a directory that exists+ check :: [FilePath] -> IO (Maybe FilePath)+ check [] = pure Nothing+ check (path : other_paths) = do+ exists <- doesDirectoryExist path+ if exists then pure (Just path) else check other_paths++-- | Find the @lib@ directory for GHC and the path to @ghc@+getGhcDirs :: [Flag] -> IO (Maybe FilePath, Maybe FilePath) getGhcDirs flags = do- case [ dir | Flag_GhcLibDir dir <- flags ] of- [] -> do+ #ifdef IN_GHC_TREE- libDir <- getInTreeDir- return (ghcPath, libDir)+ base_dir <- getBaseDir+ let ghc_path = Nothing #else- return (ghcPath, GhcPaths.libdir)+ let base_dir = Just GhcPaths.libdir+ ghc_path = Just GhcPaths.ghc #endif- xs -> return (ghcPath, last xs)- where++ -- If the user explicitly specifies a lib dir, use that+ let ghc_dir = case [ dir | Flag_GhcLibDir dir <- flags ] of+ [] -> base_dir+ xs -> Just (last xs)++ pure (ghc_path, ghc_dir)++ #ifdef IN_GHC_TREE- ghcPath = "not available"-#else- ghcPath = GhcPaths.ghc-#endif +-- | See 'getBaseDir' in "SysTools.BaseDir"+getBaseDir :: IO (Maybe FilePath)+getBaseDir = do + -- Getting executable path can fail. Turn that into 'Nothing'+ exec_path_opt <- catch (Just <$> getExecutablePath)+ (\(_ :: SomeException) -> pure Nothing)++ -- Check that the path we are about to return actually exists+ case exec_path_opt of+ Nothing -> pure Nothing+ Just exec_path -> do+ let base_dir = takeDirectory (takeDirectory exec_path) </> "lib"+ exists <- doesDirectoryExist base_dir+ pure (if exists then Just base_dir else Nothing)++#endif+ shortcutFlags :: [Flag] -> IO () shortcutFlags flags = do usage <- getUsage@@ -480,19 +711,19 @@ when (Flag_GhcVersion `elem` flags) (bye (cProjectVersion ++ "\n")) when (Flag_PrintGhcPath `elem` flags) $ do- dir <- fmap fst (getGhcDirs flags)- bye $ dir ++ "\n"+ path <- fmap fst (getGhcDirs flags)+ bye $ fromMaybe "not available" path ++ "\n" when (Flag_PrintGhcLibDir `elem` flags) $ do dir <- fmap snd (getGhcDirs flags)- bye $ dir ++ "\n"+ bye $ fromMaybe "not available" dir ++ "\n" when (Flag_UseUnicode `elem` flags && Flag_Html `notElem` flags) $ throwE "Unicode can only be enabled for HTML output." when ((Flag_GenIndex `elem` flags || Flag_GenContents `elem` flags) && Flag_Html `elem` flags) $- throwE "-h cannot be used with --gen-index or --gen-contents"+ throwE "-h/--html cannot be used with --gen-index or --gen-contents" when ((Flag_GenIndex `elem` flags || Flag_GenContents `elem` flags) && Flag_Hoogle `elem` flags) $@@ -510,38 +741,42 @@ -- | Generate some warnings about potential misuse of @--hyperlinked-source@. hypSrcWarnings :: [Flag] -> IO () hypSrcWarnings flags = do- when (hypSrc && any isSourceUrlFlag flags) $ hPutStrLn stderr $ concat [ "Warning: " , "--source-* options are ignored when " , "--hyperlinked-source is enabled." ]- when (not hypSrc && any isSourceCssFlag flags) $ hPutStrLn stderr $ concat [ "Warning: " , "source CSS file is specified but " , "--hyperlinked-source is disabled." ]- where+ hypSrc :: Bool hypSrc = Flag_HyperlinkedSource `elem` flags++ isSourceUrlFlag :: Flag -> Bool isSourceUrlFlag (Flag_SourceBaseURL _) = True isSourceUrlFlag (Flag_SourceModuleURL _) = True isSourceUrlFlag (Flag_SourceEntityURL _) = True isSourceUrlFlag (Flag_SourceLEntityURL _) = True isSourceUrlFlag _ = False++ isSourceCssFlag :: Flag -> Bool isSourceCssFlag (Flag_SourceCss _) = True isSourceCssFlag _ = False -updateHTMLXRefs :: [(DocPaths, InterfaceFile)] -> IO ()+updateHTMLXRefs :: [(FilePath, InterfaceFile)] -> IO () updateHTMLXRefs packages = do- writeIORef html_xrefs_ref (Map.fromList mapping)- writeIORef html_xrefs_ref' (Map.fromList mapping')+ let !modMap = force $ Map.fromList mapping+ !modNameMap = force $ Map.fromList mapping'+ writeIORef html_xrefs_ref modMap+ writeIORef html_xrefs_ref' modNameMap where- mapping = [ (instMod iface, html) | ((html, _), ifaces) <- packages+ mapping = [ (instMod iface, html) | (html, ifaces) <- packages , iface <- ifInstalledIfaces ifaces ] mapping' = [ (moduleName m, html) | (m, html) <- mapping ] @@ -550,36 +785,15 @@ getPrologue dflags flags = case [filename | Flag_Prologue filename <- flags ] of [] -> return Nothing- [filename] -> withFile filename ReadMode $ \h -> do+ [filename] -> do+ h <- openFile filename ReadMode hSetEncoding h utf8- str <- hGetContents h- return . Just $! parseParas dflags str+ str <- hGetContents h -- semi-closes the handle+ return . Just $! second (fmap rdrName) $ parseParas dflags Nothing str _ -> throwE "multiple -p/--prologue options" -#ifdef IN_GHC_TREE--getInTreeDir :: IO String-getInTreeDir = getExecDir >>= \case- Nothing -> error "No GhcDir found"- Just d -> return (d </> ".." </> "lib")---getExecDir :: IO (Maybe String)-#if defined(mingw32_HOST_OS)-getExecDir = try_size 2048 -- plenty, PATH_MAX is 512 under Win32.- where- try_size size = allocaArray (fromIntegral size) $ \buf -> do- ret <- c_GetModuleFileName nullPtr buf size- case ret of- 0 -> return Nothing- _ | ret < size -> fmap (Just . dropFileName) $ peekCWString buf- | otherwise -> try_size (size * 2)--foreign import stdcall unsafe "windows.h GetModuleFileNameW"- c_GetModuleFileName :: Ptr () -> CWString -> Word32 -> IO Word32-#else-getExecDir = return Nothing-#endif+rightOrThrowE :: Either String b -> IO b+rightOrThrowE (Left msg) = throwE msg+rightOrThrowE (Right x) = pure x -#endif
src/Haddock/Backends/HaddockDB.hs view
@@ -104,16 +104,21 @@ hsep (map ppHsAType b)) context) ppHsType :: HsType -> Doc-ppHsType (HsForAllType Nothing context htype) =+ppHsType (HsForAllType _ Nothing context htype) = hsep [ ppHsContext context, text "=>", ppHsType htype]-ppHsType (HsForAllType (Just tvs) [] htype) =- hsep (text "forall" : map ppHsName tvs ++ text "." : [ppHsType htype])-ppHsType (HsForAllType (Just tvs) context htype) =- hsep (text "forall" : map ppHsName tvs ++ text "." :+ppHsType (HsForAllType fvf (Just tvs) [] htype) =+ hsep (text "forall" : map ppHsName tvs ++ pprHsForAllSeparator fvf :+ [ppHsType htype])+ppHsType (HsForAllType fvf (Just tvs) context htype) =+ hsep (text "forall" : map ppHsName tvs ++ pprHsForAllSeparator fvf : ppHsContext context : text "=>" : [ppHsType htype]) ppHsType (HsTyFun a b) = fsep [ppHsBType a, text "->", ppHsType b] ppHsType (HsTyIP n t) = fsep [(char '?' <> ppHsName n), text "::", ppHsType t] ppHsType t = ppHsBType t++ppHsForAllSeparator :: ForallVisFlag -> Doc+ppHsForAllSeparator ForallVis = text "->"+ppHsForAllSeparator ForallInvis = text "." ppHsBType (HsTyApp (HsTyCon (Qual (Module "Prelude") (HsTyClsName (HsSpecial "[]")))) b ) = brackets $ ppHsType b
src/Haddock/Backends/Hoogle.hs view
@@ -1,3 +1,6 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}+ ----------------------------------------------------------------------------- -- | -- Module : Haddock.Backends.Hoogle@@ -12,27 +15,34 @@ -- http://www.haskell.org/hoogle/ ----------------------------------------------------------------------------- module Haddock.Backends.Hoogle (+ -- * Main entry point to Hoogle output generation ppHoogle++ -- * Utilities for generating Hoogle output during interface creation+ , ppExportD+ , outWith ) where -import BasicTypes (OverlapFlag(..), OverlapMode(..))-import InstEnv (ClsInst(..))+import Documentation.Haddock.Markup import Haddock.GhcUtils import Haddock.Types hiding (Version) import Haddock.Utils hiding (out) import GHC-import Outputable-import NameSet+import GHC.Driver.Ppr+import GHC.Plugins (TopLevelFlag(..))+import GHC.Utils.Outputable as Outputable+import GHC.Utils.Panic+import GHC.Unit.State import Data.Char-import Data.List+import Data.Foldable (toList)+import Data.List (intercalate, isPrefixOf) import Data.Maybe import Data.Version import System.Directory import System.FilePath-import System.IO prefix :: [String] prefix = ["-- Hoogle documentation, generated by Haddock"@@ -42,57 +52,59 @@ ppHoogle :: DynFlags -> String -> Version -> String -> Maybe (Doc RdrName) -> [Interface] -> FilePath -> IO () ppHoogle dflags package version synopsis prologue ifaces odir = do- let filename = package ++ ".txt"+ 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 +++ docWith dflags' (drop 2 $ dropWhile (/= ':') synopsis) prologue ++ ["@package " ++ package] ++ ["@version " ++ showVersion version- | not (null (versionBranch version)) ] ++- concat [ppModule dflags i | i <- ifaces, OptHide `notElem` ifaceOptions i]+ | not (null (versionBranch version))+ ] +++ concat [ppModule dflags' i | i <- ifaces, OptHide `notElem` ifaceOptions i] createDirectoryIfMissing True odir- h <- openFile (odir </> filename) WriteMode- hSetEncoding h utf8- hPutStr h (unlines contents)- hClose h+ writeUtf8File (odir </> filename) (unlines contents) ppModule :: DynFlags -> Interface -> [String] ppModule dflags iface = "" : ppDocumentation dflags (ifaceDoc iface) ++ ["module " ++ moduleString (ifaceMod iface)] ++- concatMap (ppExport dflags) (ifaceExportItems iface) ++- concatMap (ppInstance dflags) (ifaceInstances iface)+ concatMap ppExportItem (ifaceRnExportItems $ iface) +++ map (fromMaybe "" . haddockClsInstPprHoogle) (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 _ = [] --------------------------------------------------------------------- -- Utility functions -dropHsDocTy :: HsType a -> HsType a-dropHsDocTy = f+dropHsDocTy :: HsSigType GhcRn -> HsSigType GhcRn+dropHsDocTy = drop_sig_ty where- g (L src x) = L src (f x)- f (HsForAllTy a e) = HsForAllTy a (g e)- f (HsQualTy a e) = HsQualTy a (g e)- f (HsBangTy a b) = HsBangTy a (g b)- f (HsAppTy a b) = HsAppTy (g a) (g b)- f (HsFunTy a b) = HsFunTy (g a) (g b)- f (HsListTy a) = HsListTy (g a)- f (HsPArrTy a) = HsPArrTy (g a)- f (HsTupleTy a b) = HsTupleTy a (map g b)- f (HsOpTy a b c) = HsOpTy (g a) b (g c)- f (HsParTy a) = HsParTy (g a)- f (HsKindSig a b) = HsKindSig (g a) b- f (HsDocTy a _) = f $ unL a- f x = x--outHsType :: OutputableBndr a => DynFlags -> HsType a -> String-outHsType dflags = out dflags . dropHsDocTy+ 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) -dropComment :: String -> String-dropComment (' ':'-':'-':' ':_) = []-dropComment (x:xs) = x : dropComment xs-dropComment [] = []+ 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 outWith :: Outputable a => (SDoc -> String) -> a -> [Char] outWith p = f . unwords . map (dropWhile isSpace) . lines . p . ppr@@ -102,60 +114,73 @@ f [] = [] out :: Outputable a => DynFlags -> a -> String-out dflags = outWith $ showSDocUnqual dflags+out dflags = outWith $ showSDoc dflags operator :: String -> String operator (x:xs) | not (isAlphaNum x) && x `notElem` "_' ([{" = '(' : x:xs ++ ")" operator x = x commaSeparate :: Outputable a => DynFlags -> [a] -> String-commaSeparate dflags = showSDocUnqual dflags . interpp'SP+commaSeparate dflags = showSDoc dflags . interpp'SP --------------------------------------------------------------------- -- How to print each export -ppExport :: DynFlags -> ExportItem Name -> [String]-ppExport dflags ExportDecl { expItemDecl = L _ decl- , expItemMbDoc = (dc, _)- , expItemSubDocs = subdocs- , expItemFixities = fixities- } = ppDocumentation dflags dc ++ f decl- where- f (TyClD d@DataDecl{}) = ppData dflags d subdocs- f (TyClD d@SynDecl{}) = ppSynonym dflags d- f (TyClD d@ClassDecl{}) = ppClass dflags d subdocs- f (ForD (ForeignImport name typ _ _)) = [pp_sig dflags [name] (hsSigType typ)]- f (ForD (ForeignExport name typ _ _)) = [pp_sig dflags [name] (hsSigType typ)]- f (SigD sig) = ppSig dflags sig ++ ppFixities- f _ = []+ppExportD :: DynFlags -> ExportD GhcRn -> [String]+ppExportD dflags+ ExportD+ { expDDecl = L _ decl+ , expDPats = bundledPats+ , expDMbDoc = mbDoc+ , expDSubDocs = subdocs+ , expDFixities = fixities+ }+ = let+ -- Since Hoogle is line based, we want to avoid breaking long lines.+ dflags' = dflags{ pprCols = maxBound }+ in+ concat+ [ ppDocumentation dflags' dc ++ f d+ | (d, (dc, _)) <- (decl, mbDoc) : bundledPats+ ] ++ ppFixities+ where+ 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 = concatMap (ppFixity dflags) fixities-ppExport _ _ = []+ ppFixities :: [String]+ ppFixities = concatMap (ppFixity dflags) fixities -ppSigWithDoc :: DynFlags -> Sig Name -> [(Name, DocForDecl Name)] -> [String]-ppSigWithDoc dflags (TypeSig names sig) subdocs- = concatMap mkDocSig names- where- mkDocSig n = concatMap (ppDocumentation dflags) (getDoc n)- ++ [pp_sig dflags names (hsSigWcType sig)] - getDoc :: Located Name -> [Documentation Name]- getDoc n = maybe [] (return . fst) (lookup (unL n) subdocs)--ppSigWithDoc _ _ _ = []+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+ _ -> []+ where+ mkDocSig leader typ n = mkSubdocN dflags n subdocs+ [leader ++ pp_sig dflags [n] typ] -ppSig :: DynFlags -> Sig Name -> [String]+ppSig :: DynFlags -> Sig GhcRn -> [String] ppSig dflags x = ppSigWithDoc dflags x [] -pp_sig :: DynFlags -> [Located Name] -> LHsType Name -> String+pp_sig :: DynFlags -> [LocatedN Name] -> LHsSigType GhcRn -> String pp_sig dflags names (L _ typ) =- operator prettyNames ++ " :: " ++ outHsType dflags 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 Name -> [(Name, DocForDecl Name)] -> [String]-ppClass dflags decl subdocs = (out dflags decl{tcdSigs=[]} ++ ppTyFams) : ppMethods+ppClass :: DynFlags -> TyClDecl GhcRn -> [(Name, DocForDecl Name)] -> [String]+ppClass dflags decl@(ClassDecl {}) subdocs =+ (out dflags decl{tcdSigs=[], tcdATs=[], tcdATDefs=[], tcdMeths=emptyLHsBinds}+ ++ ppTyFams) : ppMethods where ppMethods = concat . map (ppSig' . unLoc . add_ctxt) $ tcdSigs decl@@ -165,97 +190,97 @@ ppTyFams | null $ tcdATs decl = ""- | otherwise = (" " ++) . showSDocUnqual dflags . whereWrapper $ concat- [ map ppr (tcdATs decl)- , map (ppr . tyFamEqnToSyn . unLoc) (tcdATDefs 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 (ppFam dflags at)+ whereWrapper elems = vcat' [ text "where" <+> lbrace- , nest 4 . vcat . map (<> semi) $ elems+ , nest 4 . vcat . map (Outputable.<> semi) $ elems , rbrace ]-- tyFamEqnToSyn :: TyFamDefltEqn Name -> TyClDecl Name- tyFamEqnToSyn tfe = SynDecl- { tcdLName = tfe_tycon tfe- , tcdTyVars = tfe_pats tfe- , tcdRhs = tfe_rhs tfe- , tcdFVs = emptyNameSet- }---ppInstance :: DynFlags -> ClsInst -> [String]-ppInstance dflags x =- [dropComment $ outWith (showSDocForUser dflags alwaysQualify) cls]+ppClass _ _non_cls_decl _ = []+ppFam :: DynFlags -> FamilyDecl GhcRn -> [String]+ppFam dflags decl@(FamilyDecl { fdInfo = info })+ = [out dflags decl'] where- -- As per #168, we don't want safety information about the class- -- in Hoogle output. The easiest way to achieve this is to set the- -- 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 mempty- , isSafeOverlap = False } }+ 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 -ppSynonym :: DynFlags -> TyClDecl Name -> [String]+ppSynonym :: DynFlags -> TyClDecl GhcRn -> [String] ppSynonym dflags x = [out dflags x] -ppData :: DynFlags -> TyClDecl Name -> [(Name, DocForDecl Name)] -> [String]-ppData dflags decl@(DataDecl { tcdDataDefn = defn }) subdocs- = showData decl{ tcdDataDefn = defn { dd_cons=[],dd_derivs=Nothing }} :- concatMap (ppCtor dflags decl subdocs . unL) (dd_cons defn)+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) where-- -- GHC gives out "data Bar =", we want to delete the equals- -- also writes data : a b, when we want data (:) a b- showData d = unwords $ map f $ if last xs == "=" then init xs else xs- where- xs = words $ out dflags d- nam = out dflags $ tyClDeclLName d- f w = if w == nam then operator nam else w ppData _ _ _ = panic "ppData" -- | for constructors, and named-fields...-lookupCon :: DynFlags -> [(Name, DocForDecl Name)] -> Located Name -> [String]+lookupCon :: DynFlags -> [(Name, DocForDecl Name)] -> LocatedN Name -> [String] lookupCon dflags subdocs (L _ name) = case lookup name subdocs of Just (d, _) -> ppDocumentation dflags d _ -> [] -ppCtor :: DynFlags -> TyClDecl Name -> [(Name, DocForDecl Name)] -> ConDecl Name -> [String]-ppCtor dflags dat subdocs con@ConDeclH98 {}+ppCtor :: DynFlags -> TyClDecl GhcRn -> [(Name, DocForDecl Name)] -> ConDecl GhcRn -> [String]+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 (getConDetails con)+ = concatMap (lookupCon dflags subdocs) [con_name con] ++ f con_args' where- f (PrefixCon args) = [typeSig name $ args ++ [resType]]- f (InfixCon a1 a2) = f $ PrefixCon [a1,a2]- f (RecCon (L _ recs)) = f (PrefixCon $ map cd_fld_type (map unLoc recs)) ++ concat- [(concatMap (lookupCon dflags subdocs . noLoc . selectorFieldOcc . unLoc) (cd_fld_names r)) ++- [out dflags (map (selectorFieldOcc . unLoc) $ cd_fld_names r) `typeSig` [resType, cd_fld_type r]]+ 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 x y)- apps = foldl1 (\x y -> reL $ HsAppTy x y)+ funs = foldr1 (\x y -> reL $ HsFunTy noAnn (HsUnrestrictedArrow noHsUniTok) x y)+ apps = foldl1 (\x y -> reL $ HsAppTy noExtField x y) - typeSig nm flds = operator nm ++ " :: " ++ outHsType dflags (unL $ funs flds)+ 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 . map unL $ getConNames con-- resType = apps $ map (reL . HsTyVar . reL) $- (tcdName dat) : [hsTyVarName v | L _ v@(UserTyVar _) <- hsQTvExplicit $ tyClDeclTyVars dat]+ name = commaSeparate dflags . toList $ unL <$> getConNames con -ppCtor dflags _dat subdocs con@ConDeclGADT {}- = concatMap (lookupCon dflags subdocs) (getConNames con) ++ f- where- f = [typeSig name (hsib_body $ con_type con)]+ tyVarArg (UserTyVar _ _ n) = HsTyVar noAnn NotPromoted n+ tyVarArg (KindedTyVar _ _ n lty) = HsKindSig noAnn (reL (HsTyVar noAnn NotPromoted n)) lty+ tyVarArg _ = panic "ppCtor" - typeSig nm ty = operator nm ++ " :: " ++ outHsType dflags (unL ty)- name = out dflags $ map unL $ getConNames con+ 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+ theta_ty = case mcxt of+ 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+ mkFunTy a b = noLocA (HsFunTy noAnn (HsUnrestrictedArrow noHsUniTok) a b) ppFixity :: DynFlags -> (Name, Fixity) -> [String]-ppFixity dflags (name, fixity) = [out dflags (FixitySig [noLoc name] fixity)]+ppFixity dflags (name, fixity) = [out dflags ((FixitySig noExtField [noLocA name] fixity) :: FixitySig GhcRn)] ---------------------------------------------------------------------@@ -278,7 +303,14 @@ 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 (n2l 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)+ data Tag = TagL Char [Tags] | TagP Tags | TagPre Tags | TagInline String Tags | Str String deriving Show @@ -304,8 +336,8 @@ markupString = str, markupAppend = (++), markupIdentifier = box (TagInline "a") . str . out dflags,- markupIdentifierUnchecked = box (TagInline "a") . str . out dflags . snd,- markupModule = box (TagInline "a") . str,+ 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"),@@ -314,14 +346,15 @@ markupMathInline = const $ str "<math>", markupMathDisplay = const $ str "<math>", markupUnorderedList = box (TagL 'u'),- markupOrderedList = box (TagL 'o'),+ 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") . str) (fromMaybe url mLabel),+ 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+ markupHeader = \(Header l h) -> box (TagInline $ "h" ++ show l) h,+ markupTable = \(Table _ _) -> str "TODO: table" }
src/Haddock/Backends/Hyperlinker.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-} module Haddock.Backends.Hyperlinker ( ppHyperlinkedSource , module Haddock.Backends.Hyperlinker.Types@@ -6,50 +8,98 @@ 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.Types import Haddock.Backends.Hyperlinker.Utils--import Text.XHtml hiding ((</>))+import Haddock.Backends.Xhtml.Utils ( renderToString ) 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 ) + -- | 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 :: FilePath -- ^ Output directory+ppHyperlinkedSource :: Verbosity+ -> FilePath -- ^ Output directory -> FilePath -- ^ Resource directory -> Maybe FilePath -- ^ Custom CSS file path -> Bool -- ^ Flag indicating whether to pretty-print HTML- -> SrcMap -- ^ Paths to sources+ -> M.Map Module SrcPath -- ^ Paths to sources -> [Interface] -- ^ Interfaces for which we create source -> IO ()-ppHyperlinkedSource outdir libdir mstyle pretty srcs ifaces = do+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 srcdir pretty srcs) ifaces+ mapM_ (ppHyperlinkedModuleSource verbosity srcdir pretty srcs) ifaces where srcdir = outdir </> hypSrcDir+ srcs = (srcs', M.mapKeys moduleName srcs') -- | Generate hyperlinked source for particular interface.-ppHyperlinkedModuleSource :: FilePath -> Bool -> SrcMap -> Interface- -> IO ()-ppHyperlinkedModuleSource srcdir pretty srcs iface =- case ifaceTokenizedSrc iface of- Just tokens -> writeFile path . html . render' $ tokens- Nothing -> return ()+ppHyperlinkedModuleSource :: Verbosity -> FilePath -> Bool -> SrcMaps -> Interface -> IO ()+ppHyperlinkedModuleSource verbosity srcdir pretty srcs iface = case ifaceHieFile iface of+ Just hfp -> 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 hfp)++ -- 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) ]++ -- 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+ Nothing -> return () where+ df = ifaceDynFlags iface render' = render (Just srcCssFile) (Just highlightScript) srcs- html = if pretty then renderHtml else showHtml path = srcdir </> hypSrcModuleFile (ifaceMod iface)++ emptyHieAst fileFs = Node+ { nodeSpan = realSrcLocSpan (mkRealSrcLoc fileFs 1 0)+ , nodeChildren = []+ , sourcedNodeInfo = SourcedNodeInfo mempty+ } -- | Name of CSS file in output directory. srcCssFile :: FilePath
− src/Haddock/Backends/Hyperlinker/Ast.hs
@@ -1,185 +0,0 @@-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TypeFamilies #-}---module Haddock.Backends.Hyperlinker.Ast (enrich) where---import Haddock.Syb-import Haddock.Backends.Hyperlinker.Types--import qualified GHC--import Control.Applicative-import Data.Data-import Data.Maybe----- | Add more detailed information to token stream using GHC API.-enrich :: GHC.RenamedSource -> [Token] -> [RichToken]-enrich src =- map $ \token -> RichToken- { rtkToken = token- , rtkDetails = enrichToken token detailsMap- }- where- detailsMap = concatMap ($ src)- [ variables- , types- , decls- , binds- , imports- ]---- | A map containing association between source locations and "details" of--- this location.------ For the time being, it is just a list of pairs. However, looking up things--- in such structure has linear complexity. We cannot use any hashmap-like--- stuff because source locations are not ordered. In the future, this should--- be replaced with interval tree data structure.-type DetailsMap = [(GHC.SrcSpan, TokenDetails)]--lookupBySpan :: Span -> DetailsMap -> Maybe TokenDetails-lookupBySpan tspan = listToMaybe . map snd . filter (matches tspan . fst)--enrichToken :: Token -> DetailsMap -> Maybe TokenDetails-enrichToken (Token typ _ spn) dm- | typ `elem` [TkIdentifier, TkOperator] = lookupBySpan spn dm-enrichToken _ _ = Nothing---- | Obtain details map for variables ("normally" used identifiers).-variables :: GHC.RenamedSource -> DetailsMap-variables =- everything (<|>) (var `combine` rec)- where- var term = case cast term of- (Just (GHC.L sspan (GHC.HsVar name))) ->- pure (sspan, RtkVar (GHC.unLoc name))- (Just (GHC.L _ (GHC.RecordCon (GHC.L sspan name) _ _ _))) ->- pure (sspan, RtkVar name)- _ -> empty- rec term = case cast term of- Just (GHC.HsRecField (GHC.L sspan name) (_ :: GHC.LHsExpr GHC.Name) _) ->- pure (sspan, RtkVar name)- _ -> empty---- | Obtain details map for types.-types :: GHC.RenamedSource -> DetailsMap-types =- everything (<|>) ty- where- ty term = case cast term of- (Just (GHC.L sspan (GHC.HsTyVar name))) ->- pure (sspan, RtkType (GHC.unLoc name))- _ -> empty---- | Obtain details map for identifier bindings.------ That includes both identifiers bound by pattern matching or declared using--- ordinary assignment (in top-level declarations, let-expressions and where--- clauses).-binds :: GHC.RenamedSource -> DetailsMap-binds =- everything (<|>) (fun `combine` pat `combine` tvar)- where- fun term = case cast term of- (Just (GHC.FunBind (GHC.L sspan name) _ _ _ _ :: GHC.HsBind GHC.Name)) ->- pure (sspan, RtkBind name)- _ -> empty- pat term = case cast term of- (Just (GHC.L sspan (GHC.VarPat name))) ->- pure (sspan, RtkBind (GHC.unLoc name))- (Just (GHC.L _ (GHC.ConPatIn (GHC.L sspan name) recs))) ->- [(sspan, RtkVar name)] ++ everything (<|>) rec recs- (Just (GHC.L _ (GHC.AsPat (GHC.L sspan name) _))) ->- pure (sspan, RtkBind name)- _ -> empty- rec term = case cast term of- (Just (GHC.HsRecField (GHC.L sspan name) (_ :: GHC.LPat GHC.Name) _)) ->- pure (sspan, RtkVar name)- _ -> empty- tvar term = case cast term of- (Just (GHC.L sspan (GHC.UserTyVar name))) ->- pure (sspan, RtkBind (GHC.unLoc name))- (Just (GHC.L _ (GHC.KindedTyVar (GHC.L sspan name) _))) ->- pure (sspan, RtkBind name)- _ -> empty---- | Obtain details map for top-level declarations.-decls :: GHC.RenamedSource -> DetailsMap-decls (group, _, _, _) = concatMap ($ group)- [ concat . map typ . concat . map GHC.group_tyclds . GHC.hs_tyclds- , everything (<|>) fun . GHC.hs_valds- , everything (<|>) (con `combine` ins)- ]- where- typ (GHC.L _ t) = case t of- GHC.DataDecl { tcdLName = name } -> pure . decl $ name- GHC.SynDecl name _ _ _ -> pure . decl $ name- GHC.FamDecl fam -> pure . decl $ GHC.fdLName fam- GHC.ClassDecl{..} -> [decl tcdLName] ++ concatMap sig tcdSigs- fun term = case cast term of- (Just (GHC.FunBind (GHC.L sspan name) _ _ _ _ :: GHC.HsBind GHC.Name))- | GHC.isExternalName name -> pure (sspan, RtkDecl name)- _ -> empty- con term = case cast term of- (Just cdcl) ->- map decl (GHC.getConNames cdcl) ++ everything (<|>) fld cdcl- Nothing -> empty- ins term = case cast term of- (Just (GHC.DataFamInstD inst)) -> pure . tyref $ GHC.dfid_tycon inst- (Just (GHC.TyFamInstD (GHC.TyFamInstDecl (GHC.L _ eqn) _))) ->- pure . tyref $ GHC.tfe_tycon eqn- _ -> empty- fld term = case cast term of- Just (field :: GHC.ConDeclField GHC.Name)- -> map (decl . fmap GHC.selectorFieldOcc) $ GHC.cd_fld_names field- Nothing -> empty- sig (GHC.L _ (GHC.TypeSig names _)) = map decl names- sig _ = []- decl (GHC.L sspan name) = (sspan, RtkDecl name)- tyref (GHC.L sspan name) = (sspan, RtkType name)---- | Obtain details map for import declarations.------ This map also includes type and variable details for items in export and--- import lists.-imports :: GHC.RenamedSource -> DetailsMap-imports src@(_, imps, _, _) =- everything (<|>) ie src ++ mapMaybe (imp . GHC.unLoc) imps- where- ie term = case cast term of- (Just (GHC.IEVar v)) -> pure $ var v- (Just (GHC.IEThingAbs t)) -> pure $ typ t- (Just (GHC.IEThingAll t)) -> pure $ typ t- (Just (GHC.IEThingWith t _ vs _fls)) ->- [typ t] ++ map var vs- _ -> empty- typ (GHC.L sspan name) = (sspan, RtkType name)- var (GHC.L sspan name) = (sspan, RtkVar name)- imp idecl | not . GHC.ideclImplicit $ idecl =- let (GHC.L sspan name) = GHC.ideclName idecl- in Just (sspan, RtkModule name)- imp _ = Nothing---- | Check whether token stream span matches GHC source span.------ Currently, it is implemented as checking whether "our" span is contained--- in GHC span. The reason for that is because GHC span are generally wider--- and may spread across couple tokens. For example, @(>>=)@ consists of three--- tokens: @(@, @>>=@, @)@, but GHC source span associated with @>>=@ variable--- contains @(@ and @)@. Similarly, qualified identifiers like @Foo.Bar.quux@--- are tokenized as @Foo@, @.@, @Bar@, @.@, @quux@ but GHC source span--- associated with @quux@ contains all five elements.-matches :: Span -> GHC.SrcSpan -> Bool-matches tspan (GHC.RealSrcSpan aspan)- | saspan <= stspan && etspan <= easpan = True- where- stspan = (posRow . spStart $ tspan, posCol . spStart $ tspan)- etspan = (posRow . spEnd $ tspan, posCol . spEnd $ tspan)- saspan = (GHC.srcSpanStartLine aspan, GHC.srcSpanStartCol aspan)- easpan = (GHC.srcSpanEndLine aspan, GHC.srcSpanEndCol aspan)-matches _ _ = False
src/Haddock/Backends/Hyperlinker/Parser.hs view
@@ -1,214 +1,406 @@+{-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} module Haddock.Backends.Hyperlinker.Parser (parse) where +import Control.Monad.Trans.Maybe+import Control.Monad.Trans.Class+import Control.Applicative ( Alternative(..) )+import Data.List ( isPrefixOf, isSuffixOf ) -import Data.Char-import Data.List-import Data.Maybe+import qualified Data.ByteString as BS -import Haddock.Backends.Hyperlinker.Types+import GHC.Platform+import GHC.Types.SourceText+import GHC.Driver.Session+import GHC.Driver.Config.Diagnostic+import GHC.Utils.Error ( pprLocMsgEnvelopeDefault )+import GHC.Data.FastString ( mkFastString )+import GHC.Parser.Errors.Ppr ()+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.SrcLoc+import GHC.Data.StringBuffer ( StringBuffer, atEnd ) +import Haddock.Backends.Hyperlinker.Types as T+import Haddock.GhcUtils -- | Turn source code string into a stream of more descriptive tokens. ----- Result should retain original file layout (including comments, whitespace,--- etc.), i.e. the following "law" should hold:------ @concat . map 'tkValue' . 'parse' = id@-parse :: String -> [Token]-parse = tokenize . tag . chunk---- | Split raw source string to more meaningful chunks.------ This is the initial stage of tokenization process. Each chunk is either--- a comment (including comment delimiters), a whitespace string, preprocessor--- macro (and all its content until the end of a line) or valid Haskell lexeme.-chunk :: String -> [String]-chunk [] = []-chunk str@(c:_)- | isSpace c =- let (space, mcpp, rest) = spanSpaceOrCpp str- in [space] ++ maybeToList mcpp ++ chunk rest-chunk str- | "--" `isPrefixOf` str = chunk' $ spanToNewline str- | "{-" `isPrefixOf` str = chunk' $ chunkComment 0 str- | otherwise = case lex' str of- (tok:_) -> chunk' tok- [] -> [str]+-- 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+ -> [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 where- chunk' (c, rest) = c:(chunk rest) --- | A bit better lexer then the default, i.e. handles DataKinds quotes-lex' :: ReadS String-lex' ('\'' : '\'' : rest) = [("''", rest)]-lex' str@('\'' : '\\' : _ : '\'' : _) = lex str-lex' str@('\'' : _ : '\'' : _) = lex str-lex' ('\'' : rest) = [("'", rest)]-lex' str = lex str+ 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 --- | Split input to "first line" string and the rest of it.------ Ideally, this should be done simply with @'break' (== '\n')@. However,--- Haskell also allows line-unbreaking (or whatever it is called) so things--- are not as simple and this function deals with that.-spanToNewline :: String -> (String, String)-spanToNewline [] = ([], [])-spanToNewline ('\\':'\n':str) =- let (str', rest) = spanToNewline str- in ('\\':'\n':str', rest)-spanToNewline str@('\n':_) = ("", str)-spanToNewline (c:str) =- let (str', rest) = spanToNewline str- in (c:str', rest)+ 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)+ then do+ mtok <- runMaybeT (parseCppLine <|> parsePlainTok inPrag)+ (newToks, inPrag') <- case mtok of+ Nothing -> unknownLine+ Just a -> pure a+ go inPrag' (newToks ++ toks)+ else+ pure toks --- | Split input to whitespace string, (optional) preprocessor directive and--- the rest of it.------ Again, using something like @'span' 'isSpace'@ would be nice to chunk input--- to whitespace. The problem is with /#/ symbol - if it is placed at the very--- beginning of a line, it should be recognized as preprocessor macro. In any--- other case, it is ordinary Haskell symbol and can be used to declare--- operators. Hence, while dealing with whitespace we also check whether there--- happens to be /#/ symbol just after a newline character - if that is the--- case, we begin treating the whole line as preprocessor macro.-spanSpaceOrCpp :: String -> (String, Maybe String, String)-spanSpaceOrCpp ('\n':'#':str) =- let (str', rest) = spanToNewline str- in ("\n", Just $ '#':str', rest)-spanSpaceOrCpp (c:str')- | isSpace c =- let (space, mcpp, rest) = spanSpaceOrCpp str'- in (c:space, mcpp, rest)-spanSpaceOrCpp str = ("", Nothing, str)+ -- | 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 --- | Split input to comment content (including delimiters) and the rest.------ Again, some more logic than simple 'span' is required because of Haskell--- comment nesting policy.-chunkComment :: Int -> String -> (String, String)-chunkComment _ [] = ("", "")-chunkComment depth ('{':'-':str) =- let (c, rest) = chunkComment (depth + 1) str- in ("{-" ++ c, rest)-chunkComment depth ('-':'}':str)- | depth == 1 = ("-}", str)- | otherwise =- let (c, rest) = chunkComment (depth - 1) str- in ("-}" ++ c, rest)-chunkComment depth (e:str) =- let (c, rest) = chunkComment depth str- in (e:c, rest)+ -- | 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 --- | Assign source location for each chunk in given stream.-tag :: [String] -> [(Span, String)]-tag =- reverse . snd . foldl aux (Position 1 1, [])- where- aux (pos, cs) str =- let pos' = foldl move pos str- in (pos', (Span pos pos', str):cs)- move pos '\n' = pos { posRow = posRow pos + 1, posCol = 1 }- move pos _ = pos { posCol = posCol pos + 1 }+ -- | 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)+ (bEnd, _) <- lift getInput+ case sp of+ UnhelpfulSpan _ -> pure ([], False) -- pretend the token never existed+ RealSrcSpan rsp _ -> do+ let typ = if inPrag then TkPragma else classify tok+ RealSrcLoc lStart _ = srcSpanStart sp -- safe since @sp@ is real+ (spaceBStr, bStart) = spanPosition lInit lStart bInit+ inPragDef = inPragma inPrag tok --- | Turn unrecognised chunk stream to more descriptive token stream.-tokenize :: [(Span, String)] -> [Token]-tokenize =- map aux- where- aux (sp, str) = Token- { tkType = classify str- , tkValue = str- , tkSpan = sp- }+ (bEnd', inPrag') <- case tok of --- | Classify given string as appropriate Haskell token.------ This method is based on Haskell 98 Report lexical structure description:--- https://www.haskell.org/onlinereport/lexemes.html------ However, this is probably far from being perfect and most probably does not--- handle correctly all corner cases.-classify :: String -> TokenType-classify str- | "--" `isPrefixOf` str = TkComment- | "{-#" `isPrefixOf` str = TkPragma- | "{-" `isPrefixOf` str = TkComment-classify "''" = TkSpecial-classify "'" = TkSpecial-classify str@(c:_)- | isSpace c = TkSpace- | isDigit c = TkNumber- | c `elem` special = TkSpecial- | str `elem` glyphs = TkGlyph- | all (`elem` symbols) str = TkOperator- | c == '#' = TkCpp- | c == '"' = TkString- | c == '\'' = TkChar-classify str- | str `elem` keywords = TkKeyword- | isIdentifier str = TkIdentifier- | otherwise = TkUnknown+ -- 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 -keywords :: [String]-keywords =- [ "as"- , "case"- , "class"- , "data"- , "default"- , "deriving"- , "do"- , "else"- , "hiding"- , "if"- , "import"- , "in"- , "infix"- , "infixl"- , "infixr"- , "instance"- , "let"- , "module"- , "newtype"- , "of"- , "qualified"- , "then"- , "type"- , "where"- , "forall"- , "family"- , "mdo"- ]+ let newLoc = mkRealSrcLoc file (fromIntegral line - 1) (srcSpanEndCol spF)+ (bEnd'', _) <- lift getInput+ lift $ setInput (bEnd'', newLoc) -glyphs :: [String]-glyphs =- [ ".."- , ":"- , "::"- , "="- , "\\"- , "|"- , "<-"- , "->"- , "@"- , "~"- , "~#"- , "=>"- , "-"- , "!"- ]+ pure (bEnd'', False) -special :: [Char]-special = "()[]{},;`"+ -- 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 --- TODO: Add support for any Unicode symbol or punctuation.--- source: http://stackoverflow.com/questions/10548170/what-characters-are-permitted-for-haskell-operators-symbols :: [Char]-symbols = "!#$%&*+./<=>?@\\^|-~:"+ let newLoc = mkRealSrcLoc (srcSpanFile spF) (srcSpanEndLine spF) (fromIntegral col)+ (bEnd'', _) <- lift getInput+ lift $ setInput (bEnd'', newLoc) -isIdentifier :: String -> Bool-isIdentifier (s:str)- | (isLower' s || isUpper s) && all isAlphaNum' str = True- where- isLower' c = isLower c || c == '_'- isAlphaNum' c = isAlphaNum c || c == '_' || c == '\''-isIdentifier _ = False+ 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)+ 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' }+ 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)++-- | 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 }) ()++tryP :: P a -> MaybeT P a+tryP (P f) = MaybeT $ P $ \s -> case f s of+ POk s' a -> POk s' (Just a)+ PFailed _ -> POk s Nothing++tryOrElse :: Alternative f => a -> f a -> f a+tryOrElse x p = p <|> pure x++-- | Classify given tokens as appropriate Haskell token type.+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+ 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++-- | 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 _ 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+
src/Haddock/Backends/Hyperlinker/Renderer.hs view
@@ -1,5 +1,7 @@ {-# LANGUAGE RecordWildCards #-}-+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE BangPatterns #-} module Haddock.Backends.Hyperlinker.Renderer (render) where @@ -7,16 +9,21 @@ import Haddock.Backends.Hyperlinker.Types import Haddock.Backends.Hyperlinker.Utils -import qualified GHC-import qualified Name as GHC-import qualified Unique as GHC+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.Types.SrcLoc+import GHC.Types.Unique ( getKey )+import GHC.Utils.Encoding ( utf8DecodeByteString )+ import System.FilePath.Posix ((</>)) -import Data.List-import Data.Maybe-import Data.Monoid 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@@ -24,48 +31,24 @@ type StyleClass = String --render :: Maybe FilePath -> Maybe FilePath -> SrcMap -> [RichToken]- -> Html-render mcss mjs srcs tokens = header mcss mjs <> body srcs tokens---data TokenGroup- = GrpNormal Token- | GrpRich TokenDetails [Token]----- | Group consecutive tokens pointing to the same element.------ We want to render qualified identifiers as one entity. For example,--- @Bar.Baz.foo@ consists of 5 tokens (@Bar@, @.@, @Baz@, @.@, @foo@) but for--- better user experience when highlighting and clicking links, these tokens--- should be regarded as one identifier. Therefore, before rendering we must--- group consecutive elements pointing to the same 'GHC.Name' (note that even--- dot token has it if it is part of qualified name).-groupTokens :: [RichToken] -> [TokenGroup]-groupTokens [] = []-groupTokens ((RichToken tok Nothing):rest) = (GrpNormal tok):(groupTokens rest)-groupTokens ((RichToken tok (Just det)):rest) =- let (grp, rest') = span same rest- in (GrpRich det (tok:(map rtkToken grp))):(groupTokens rest')- where- same (RichToken _ (Just det')) = det == det'- same _ = False-+-- | 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+ -> Html+render mcss mjs srcs ast tokens = header mcss mjs <> body srcs ast tokens -body :: SrcMap -> [RichToken] -> Html-body srcs tokens =- Html.body . Html.pre $ hypsrc+body :: SrcMaps -> HieAST PrintedType -> [Token] -> Html+body srcs ast tokens = Html.body . Html.pre $ hypsrc where- hypsrc = mconcat . map (tokenGroup srcs) . groupTokens $ tokens-+ hypsrc = renderWithAst srcs ast tokens header :: Maybe FilePath -> Maybe FilePath -> Html-header mcss mjs- | isNothing mcss && isNothing mjs = Html.noHtml-header mcss mjs =- Html.header $ css mcss <> js mjs+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 !@@ -80,34 +63,137 @@ ] -tokenGroup :: SrcMap -> TokenGroup -> Html-tokenGroup _ (GrpNormal tok@(Token { .. }))- | tkType == TkSpace = renderSpace (posRow . spStart $ tkSpan) tkValue- | otherwise = tokenSpan tok ! attrs+splitTokens :: HieAST PrintedType -> [Token] -> ([Token],[Token],[Token])+splitTokens ast toks = (before,during,after) where- attrs = [ multiclass . tokenStyle $ tkType ]-tokenGroup srcs (GrpRich det tokens) =- externalAnchor det . internalAnchor det . hyperlink srcs det $ content+ (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++-- | Turn a list of tokens into hyperlinked sources, threading in relevant link+-- 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 where- content = mconcat . map (richToken det) $ tokens+ 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+ where+ (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 +renderToken :: Token -> Html+renderToken Token{..}+ | 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') -richToken :: TokenDetails -> Token -> Html-richToken det tok =- tokenSpan tok ! [ multiclass style ]++-- | 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 where- style = (tokenStyle . tkType) tok ++ richTokenStyle det+ tkValue' = filterCRLF $ utf8DecodeByteString tkValue+ content = tokenSpan ! [ multiclass style ]+ tokenSpan = Html.thespan (Html.toHtml tkValue')+ style = tokenStyle tkType ++ concatMap (richTokenStyle (null (nodeType details))) contexts + contexts = concatMap (Set.elems . identInfo) . Map.elems . nodeIdentifiers $ details -tokenSpan :: Token -> Html-tokenSpan = Html.thespan . Html.toHtml . tkValue+ -- pick an arbitrary non-evidence identifier to hyperlink with+ identDet = Map.lookupMin $ Map.filter notEvidence $ nodeIdentifiers details+ notEvidence = not . any isEvidenceContext . identInfo + -- If we have name information, we can make links+ linked = case identDet of+ Just (n,_) -> hyperlink srcs n+ Nothing -> id -richTokenStyle :: TokenDetails -> [StyleClass]-richTokenStyle (RtkVar _) = ["hs-var"]-richTokenStyle (RtkType _) = ["hs-type"]-richTokenStyle _ = []+-- | Remove CRLFs from source+filterCRLF :: String -> String+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" ]+ where+ annot+ | not (null annotation) =+ 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) ]+ identTyps+ | 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?+ -> [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{} = []+ tokenStyle :: TokenType -> [StyleClass] tokenStyle TkIdentifier = ["hs-identifier"] tokenStyle TkKeyword = ["hs-keyword"]@@ -124,59 +210,78 @@ tokenStyle TkUnknown = [] multiclass :: [StyleClass] -> HtmlAttr-multiclass = Html.theclass . intercalate " "+multiclass = Html.theclass . unwords -externalAnchor :: TokenDetails -> Html -> Html-externalAnchor (RtkDecl name) content =- Html.anchor content ! [ Html.name $ externalAnchorIdent name ]-externalAnchor _ content = content+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 ]+externalAnchor _ _ content = content -internalAnchor :: TokenDetails -> Html -> Html-internalAnchor (RtkBind name) content =- Html.anchor content ! [ Html.name $ internalAnchorIdent name ]-internalAnchor _ content = content+isBinding :: ContextInfo -> Bool+isBinding (ValBind RegularBind _ _) = True+isBinding PatternBind{} = True+isBinding Decl{} = True+isBinding (RecField RecFieldDecl _) = True+isBinding TyVarBind{} = True+isBinding ClassTyDecl{} = True+isBinding _ = False -externalAnchorIdent :: GHC.Name -> String-externalAnchorIdent = hypSrcNameUrl+internalAnchor :: Identifier -> Set.Set ContextInfo -> Html -> Html+internalAnchor (Right name) contexts content+ | isInternalName name+ , any isBinding contexts+ = Html.thespan content ! [ Html.identifier $ internalAnchorIdent name ]+internalAnchor _ _ content = content -internalAnchorIdent :: GHC.Name -> String-internalAnchorIdent = ("local-" ++) . show . GHC.getKey . GHC.nameUnique+externalAnchorIdent :: Name -> String+externalAnchorIdent = hypSrcNameUrl -hyperlink :: SrcMap -> TokenDetails -> Html -> Html-hyperlink srcs details = case rtkName details of- Left name ->- if GHC.isInternalName name- then internalHyperlink name- else externalNameHyperlink srcs name- Right name -> externalModHyperlink srcs name+internalAnchorIdent :: Name -> String+internalAnchorIdent = ("local-" ++) . show . getKey . nameUnique -internalHyperlink :: GHC.Name -> Html -> Html-internalHyperlink name content =- Html.anchor content ! [ Html.href $ "#" ++ internalAnchorIdent name ]+-- | 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 -externalNameHyperlink :: SrcMap -> GHC.Name -> Html -> Html-externalNameHyperlink (srcs, _) name content = case Map.lookup mdl srcs of- Just SrcLocal -> Html.anchor content !- [ Html.href $ hypSrcModuleNameUrl mdl name ]- Just (SrcExternal path) -> Html.anchor content !- [ Html.href $ path </> hypSrcModuleNameUrl mdl name ]- Nothing -> content where- mdl = GHC.nameModule name+ -- In a Nix environment, we have file:// URLs with absolute paths+ makeHyperlinkUrl url | List.isPrefixOf "file://" url = url+ makeHyperlinkUrl url = ".." </> url -externalModHyperlink :: SrcMap -> GHC.ModuleName -> Html -> Html-externalModHyperlink (_, srcs) name content = case Map.lookup name srcs of- Just SrcLocal -> Html.anchor content !- [ Html.href $ hypSrcModuleUrl' name ]- Just (SrcExternal path) -> Html.anchor content !- [ Html.href $ path </> hypSrcModuleUrl' name ]- Nothing -> content+ internalHyperlink name content =+ 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 Nothing (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' Nothing (Just moduleName) Nothing Nothing hyperlinkUrl ]+ Nothing -> content++ renderSpace :: Int -> String -> Html-renderSpace _ [] = Html.noHtml-renderSpace line ('\n':rest) = mconcat- [ Html.thespan . Html.toHtml $ "\n"+renderSpace !_ "" = Html.noHtml+renderSpace !line ('\n':rest) = mconcat+ [ Html.thespan (Html.toHtml '\n') , lineAnchor (line + 1) , renderSpace (line + 1) rest ]@@ -186,4 +291,4 @@ lineAnchor :: Int -> Html-lineAnchor line = Html.anchor Html.noHtml ! [ Html.name $ hypSrcLineUrl line ]+lineAnchor line = Html.thespan Html.noHtml ! [ Html.identifier $ hypSrcLineUrl line ]
src/Haddock/Backends/Hyperlinker/Types.hs view
@@ -1,30 +1,26 @@+{-# LANGUAGE PatternSynonyms, OverloadedStrings #-} module Haddock.Backends.Hyperlinker.Types where - import qualified GHC -import Data.Map (Map)-import qualified Data.Map as Map+import Data.ByteString ( ByteString ) +import Data.Map (Map) data Token = Token { tkType :: TokenType- , tkValue :: String- , tkSpan :: Span+ , tkValue :: ByteString -- ^ UTF-8 encoded+ , tkSpan :: {-# UNPACK #-} !Span } deriving (Show) -data Position = Position- { posRow :: !Int- , posCol :: !Int- }- deriving (Show)+pattern BacktickTok, OpenParenTok, CloseParenTok :: Span -> Token+pattern BacktickTok sp = Token TkSpecial "`" sp+pattern OpenParenTok sp = Token TkSpecial "(" sp+pattern CloseParenTok sp = Token TkSpecial ")" sp -data Span = Span- { spStart :: Position- , spEnd :: Position- }- deriving (Show)+type Position = GHC.RealSrcLoc+type Span = GHC.RealSrcSpan data TokenType = TkIdentifier@@ -42,29 +38,6 @@ | TkUnknown deriving (Show, Eq) --data RichToken = RichToken- { rtkToken :: Token- , rtkDetails :: Maybe TokenDetails- }--data TokenDetails- = RtkVar GHC.Name- | RtkType GHC.Name- | RtkBind GHC.Name- | RtkDecl GHC.Name- | RtkModule GHC.ModuleName- deriving (Eq)---rtkName :: TokenDetails -> Either GHC.Name GHC.ModuleName-rtkName (RtkVar name) = Left name-rtkName (RtkType name) = Left name-rtkName (RtkBind name) = Left name-rtkName (RtkDecl name) = Left name-rtkName (RtkModule name) = Right name-- -- | Path for making cross-package hyperlinks in generated sources. -- -- Used in 'SrcMap' to determine whether module originates in current package@@ -74,15 +47,5 @@ | SrcLocal -- | Mapping from modules to cross-package source paths.------ This mapping is actually a pair of maps instead of just one map. The reason--- for this is because when hyperlinking modules in import lists we have no--- 'GHC.Module' available. On the other hand, we can't just use map with--- 'GHC.ModuleName' as indices because certain modules may have common name--- but originate in different packages. Hence, we use both /rich/ and /poor/--- versions, where the /poor/ is just projection of /rich/ one cached in pair--- for better performance.-type SrcMap = (Map GHC.Module SrcPath, Map GHC.ModuleName SrcPath)+type SrcMaps = (Map GHC.Module SrcPath, Map GHC.ModuleName SrcPath) -mkSrcMap :: Map GHC.Module SrcPath -> SrcMap-mkSrcMap srcs = (srcs, Map.mapKeys GHC.moduleName srcs)
src/Haddock/Backends/Hyperlinker/Utils.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} module Haddock.Backends.Hyperlinker.Utils ( hypSrcDir, hypSrcModuleFile, hypSrcModuleFile' , hypSrcModuleUrl, hypSrcModuleUrl'@@ -6,21 +7,35 @@ , hypSrcModuleNameUrl, hypSrcModuleLineUrl , hypSrcModuleUrlFormat , hypSrcModuleNameUrlFormat, hypSrcModuleLineUrlFormat- ) where+ , spliceURL, spliceURL' + -- * HIE file processing+ , PrintedType+ , recoverFullIfaceTypes+ ) where +import Haddock.Utils import Haddock.Backends.Xhtml.Utils import GHC-import FastString-import System.FilePath.Posix ((</>))+import GHC.Iface.Ext.Types ( HieAST(..), HieType(..), HieArgs(..), TypeIndex, HieTypeFlat )+import GHC.Iface.Type+import GHC.Types.Name ( getOccFS, getOccString )+import GHC.Driver.Ppr ( showSDoc )+import GHC.Types.Var ( VarBndr(..), visArg, invisArg, TypeOrConstraint(..) ) +import System.FilePath.Posix ((</>), (<.>)) +import qualified Data.Array as A+++{-# INLINE hypSrcDir #-} hypSrcDir :: FilePath hypSrcDir = "src" +{-# INLINE hypSrcModuleFile #-} hypSrcModuleFile :: Module -> FilePath-hypSrcModuleFile = hypSrcModuleFile' . moduleName+hypSrcModuleFile m = moduleNameString (moduleName m) <.> "html" hypSrcModuleFile' :: ModuleName -> FilePath hypSrcModuleFile' mdl = spliceURL'@@ -32,20 +47,19 @@ hypSrcModuleUrl' :: ModuleName -> String hypSrcModuleUrl' = hypSrcModuleFile' +{-# INLINE hypSrcNameUrl #-} hypSrcNameUrl :: Name -> String-hypSrcNameUrl name = spliceURL- Nothing Nothing (Just name) Nothing nameFormat+hypSrcNameUrl = escapeStr . getOccString +{-# INLINE hypSrcLineUrl #-} hypSrcLineUrl :: Int -> String-hypSrcLineUrl line = spliceURL- Nothing Nothing Nothing (Just spn) lineFormat- where- loc = mkSrcLoc nilFS line 1- spn = mkSrcSpan loc loc+hypSrcLineUrl line = "line-" ++ show line +{-# INLINE hypSrcModuleNameUrl #-} hypSrcModuleNameUrl :: Module -> Name -> String hypSrcModuleNameUrl mdl name = hypSrcModuleUrl mdl ++ "#" ++ hypSrcNameUrl name +{-# INLINE hypSrcModuleLineUrl #-} hypSrcModuleLineUrl :: Module -> Int -> String hypSrcModuleLineUrl mdl line = hypSrcModuleUrl mdl ++ "#" ++ hypSrcLineUrl line @@ -66,3 +80,65 @@ lineFormat :: String lineFormat = "line-%{LINE}"+++-- * HIE file processing++-- This belongs in GHC.Iface.Ext.Utils...++-- | Pretty-printed type, ready to be turned into HTML by @xhtml@+type PrintedType = String++-- | Expand the flattened HIE AST into one where the types printed out and+-- ready for end-users to look at.+--+-- Using just primitives found in GHC's HIE utilities, we could write this as+-- follows:+--+-- > 'recoverFullIfaceTypes' dflags hieTypes hieAst+-- > = 'fmap' (\ti -> 'showSDoc' df .+-- > 'pprIfaceType' $+-- > 'recoverFullType' ti hieTypes)+-- > hieAst+--+-- However, this is very inefficient (both in time and space) because the+-- multiple calls to 'recoverFullType' don't share intermediate results. This+-- function fixes that.+recoverFullIfaceTypes+ :: DynFlags+ -> A.Array TypeIndex HieTypeFlat -- ^ flat types+ -> HieAST TypeIndex -- ^ flattened AST+ -> HieAST PrintedType -- ^ full AST+recoverFullIfaceTypes df flattened ast = fmap (printed A.!) ast+ 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+ printed = fmap (showSDoc df . pprIfaceType) unflattened++ -- The recursion in 'unflattened' is crucial - it's what gives us sharing+ -- between the IfaceType's produced+ unflattened :: A.Array TypeIndex IfaceType+ unflattened = fmap (\flatTy -> go (fmap (unflattened A.!) flatTy)) flattened++ -- Unfold an 'HieType' whose subterms have already been unfolded+ go :: HieType IfaceType -> IfaceType+ go (HTyVarTy n) = IfaceTyVar (getOccFS n)+ go (HAppTy a b) = IfaceAppTy a (hieToIfaceArgs b)+ go (HLitTy l) = IfaceLitTy l+ go (HForAllTy ((n,k),af) t) = let b = (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 "<coercion type>"+ go (HTyConApp a xs) = IfaceTyConApp a (hieToIfaceArgs xs)++ -- This isn't fully faithful - we can't produce the 'Inferred' case+ hieToIfaceArgs :: HieArgs IfaceType -> IfaceAppArgs+ 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
src/Haddock/Backends/LaTeX.hs view
@@ -1,1270 +1,1454 @@ {-# OPTIONS_GHC -fno-warn-name-shadowing #-} {-# LANGUAGE RecordWildCards #-}--------------------------------------------------------------------------------- |--- Module : Haddock.Backends.LaTeX--- Copyright : (c) Simon Marlow 2010,--- Mateusz Kowalczyk 2013--- License : BSD-like------ Maintainer : haddock@projects.haskell.org--- Stability : experimental--- Portability : portable-------------------------------------------------------------------------------module Haddock.Backends.LaTeX (- ppLaTeX-) where---import Haddock.Types-import Haddock.Utils-import Haddock.GhcUtils-import Pretty hiding (Doc, quote)-import qualified Pretty--import GHC-import OccName-import Name ( nameOccName )-import RdrName ( rdrNameOcc )-import FastString ( unpackFS, unpackLitString, zString )-import Outputable ( panic)--import qualified Data.Map as Map-import System.Directory-import System.FilePath-import Data.Char-import Control.Monad-import Data.Maybe-import Data.List--import Haddock.Doc (combineDocumentation)---- import Debug.Trace--{- SAMPLE OUTPUT--\haddockmoduleheading{\texttt{Data.List}}-\hrulefill-{\haddockverb\begin{verbatim}-module Data.List (- (++), head, last, tail, init, null, length, map, reverse,- ) where\end{verbatim}}-\hrulefill--\section{Basic functions}-\begin{haddockdesc}-\item[\begin{tabular}{@{}l}-head\ ::\ {\char 91}a{\char 93}\ ->\ a-\end{tabular}]\haddockbegindoc-Extract the first element of a list, which must be non-empty.-\par--\end{haddockdesc}-\begin{haddockdesc}-\item[\begin{tabular}{@{}l}-last\ ::\ {\char 91}a{\char 93}\ ->\ a-\end{tabular}]\haddockbegindoc-Extract the last element of a list, which must be finite and non-empty.-\par--\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---haddockSty :: FilePath-haddockSty = "haddock.sty"---type LaTeX = Pretty.Doc---ppLaTeXTop- :: 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}"- ]-- mods = sort (map (moduleBasename.ifaceMod) ifaces)-- filename = odir </> (fromMaybe "haddock" packageStr <.> "tex")-- writeFile 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 (text ", ") $- map exportListItem $- filter forSummary exports),- text " ) where"- ],- text "\\haddockendheader" $$ text "",- description,- body- ]-- description- = (fromMaybe empty . documentationToLaTeX . ifaceRnDoc) iface-- body = processExports exports- --- writeFile (odir </> moduleLaTeXFile mdl) (fullRender PageMode 80 1 string_txt "" tex)---string_txt :: TextDetails -> String -> String-string_txt (Chr c) s = c:s-string_txt (Str s1) s2 = s1 ++ s2-string_txt (PStr s1) s2 = unpackFS s1 ++ s2-string_txt (ZStr s1) s2 = zString s1 ++ s2-string_txt (LStr s1 _) s2 = unpackLitString s1 ++ s2---exportListItem :: ExportItem DocName -> 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)))-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 DocName] -> 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-processExports (e : es) =- processExport e $$ processExports es---isSimpleSig :: ExportItem DocName -> Maybe ([DocName], HsType DocName)-isSimpleSig ExportDecl { expItemDecl = L _ (SigD (TypeSig lnames t))- , expItemMbDoc = (Documentation Nothing Nothing, argDocs) }- | Map.null argDocs = Just (map unLoc lnames, unLoc (hsSigWcType t))-isSimpleSig _ = Nothing---isExportModule :: ExportItem DocName -> Maybe Module-isExportModule (ExportModule m) = Just m-isExportModule _ = Nothing---processExport :: ExportItem DocName -> LaTeX-processExport (ExportGroup lev _id0 doc)- = ppDocGroup lev (docToLaTeX doc)-processExport (ExportDecl decl doc subdocs insts fixities _splice)- = ppDecl decl 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"---declNames :: LHsDecl DocName -> [DocName]-declNames (L _ decl) = case decl of- TyClD d -> [tcdName d]- SigD (TypeSig lnames _ ) -> map unLoc lnames- SigD (PatSynSig lname _) -> [unLoc lname]- ForD (ForeignImport (L _ n) _ _ _) -> [n]- ForD (ForeignExport (L _ n) _ _ _) -> [n]- _ -> error "declaration not supported by declNames"---forSummary :: (ExportItem DocName) -> Bool-forSummary (ExportGroup _ _ _) = False-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))------------------------------------------------------------------------------------- * Decls-----------------------------------------------------------------------------------ppDecl :: LHsDecl DocName- -> DocForDecl DocName- -> [DocInstance DocName]- -> [(DocName, DocForDecl DocName)]- -> [(DocName, Fixity)]- -> LaTeX--ppDecl (L loc decl) (doc, fnArgsDoc) instances subdocs _fixities = case decl of- TyClD d@(FamDecl {}) -> ppTyFam False loc doc d unicode- TyClD d@(DataDecl {})- -> ppDataDecl instances subdocs loc (Just doc) d unicode- TyClD d@(SynDecl {}) -> ppTySyn loc (doc, fnArgsDoc) d unicode--- Family instances happen via FamInst now--- 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 lname ty) ->- ppLPatSig loc (doc, fnArgsDoc) lname ty unicode- ForD d -> ppFor loc (doc, fnArgsDoc) d unicode- InstD _ -> empty- _ -> error "declaration not supported by ppDecl"- where- unicode = False---ppTyFam :: Bool -> SrcSpan -> Documentation DocName ->- TyClDecl DocName -> Bool -> LaTeX-ppTyFam _ _ _ _ _ =- error "type family declarations are currently not supported by --latex"---ppFor :: SrcSpan -> DocForDecl DocName -> ForeignDecl DocName -> 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"--- error "foreign declarations are currently not supported by --latex"------------------------------------------------------------------------------------- * Type Synonyms------------------------------------------------------------------------------------- we skip type patterns for now-ppTySyn :: SrcSpan -> DocForDecl DocName -> TyClDecl DocName -> Bool -> LaTeX--ppTySyn loc doc (SynDecl { tcdLName = L _ name, tcdTyVars = ltyvars- , tcdRhs = ltype }) unicode- = ppTypeOrFunSig loc [name] (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"------------------------------------------------------------------------------------- * Function signatures-----------------------------------------------------------------------------------ppFunSig :: SrcSpan -> DocForDecl DocName -> [DocName] -> LHsType DocName- -> Bool -> LaTeX-ppFunSig loc doc docnames (L _ typ) unicode =- ppTypeOrFunSig loc docnames typ doc- ( ppTypeSig names typ False- , hsep . punctuate comma $ map ppSymName names- , dcolon unicode)- unicode- where- names = map getName docnames--ppLPatSig :: SrcSpan -> DocForDecl DocName -> Located DocName- -> LHsSigType DocName- -> Bool -> LaTeX-ppLPatSig _loc (doc, _argDocs) (L _ name) ty unicode- = declWithDoc pref1 (documentationToLaTeX doc)- where- pref1 = hsep [ keyword "pattern"- , ppDocBinder name- , dcolon unicode- , ppLType unicode (hsSigType ty)- ]--ppTypeOrFunSig :: SrcSpan -> [DocName] -> HsType DocName- -> 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 $- text "\\haddockbeginargs" $$- do_args 0 sep0 typ $$- text "\\end{tabulary}\\par" $$- fromMaybe empty (documentationToLaTeX doc)- 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 DocName -> 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---ppTypeSig :: [Name] -> HsType DocName -> Bool -> LaTeX-ppTypeSig nms ty unicode =- hsep (punctuate comma $ map ppSymName nms)- <+> dcolon unicode- <+> ppType unicode ty---ppTyVars :: [LHsTyVarBndr DocName] -> [LaTeX]-ppTyVars = map (ppSymName . getName . hsLTyVarName)---tyvarNames :: LHsQTyVars DocName -> [Name]-tyvarNames = map (getName . hsLTyVarName) . hsQTvExplicit---declWithDoc :: LaTeX -> Maybe LaTeX -> LaTeX-declWithDoc decl doc =- text "\\begin{haddockdesc}" $$- text "\\item[\\begin{tabular}{@{}l}" $$- text (latexMonoFilter (show decl)) $$- text "\\end{tabular}]" <>- (if isNothing doc then empty else text "\\haddockbegindoc") $$- maybe empty id 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[" $$- text (latexMonoFilter (show decl)) $$- text "]"- | 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 = maybeDoc . fmap latexStripTrailingWhitespace------------------------------------------------------------------------------------- * Class declarations-----------------------------------------------------------------------------------ppClassHdr :: Bool -> Located [LHsType DocName] -> DocName- -> LHsQTyVars DocName -> [Located ([Located DocName], [Located DocName])]- -> Bool -> LaTeX-ppClassHdr summ lctxt n tvs fds unicode =- keyword "class"- <+> (if not . null . unLoc $ lctxt then ppLContext lctxt unicode else empty)- <+> ppAppDocNameNames summ n (tyvarNames tvs)- <+> ppFds fds unicode---ppFds :: [Located ([Located DocName], [Located DocName])] -> Bool -> LaTeX-ppFds fds unicode =- if null fds then empty else- char '|' <+> hsep (punctuate comma (map (fundep . unLoc) fds))- where- fundep (vars1,vars2) = hsep (map (ppDocName . unLoc) vars1) <+> arrow unicode <+>- hsep (map (ppDocName . unLoc) vars2)---ppClassDecl :: [DocInstance DocName] -> SrcSpan- -> Documentation DocName -> [(DocName, DocForDecl DocName)]- -> TyClDecl DocName -> Bool -> LaTeX-ppClassDecl instances loc 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 = atTable $$ methodTable- | otherwise = error "LaTeX.ppClassDecl"-- methodTable =- text "\\haddockpremethods{}\\textbf{Methods}" $$- vcat [ ppFunSig loc doc names (hsSigWcType typ) unicode- | L _ (TypeSig lnames typ) <- lsigs- , 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?-- instancesBit = ppDocInstances unicode instances--ppClassDecl _ _ _ _ _ _ = error "declaration type not supported by ppShortClassDecl"--ppDocInstances :: Bool -> [DocInstance DocName] -> 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- where- (is, rest') = spanWith isUndocdInstance rest--isUndocdInstance :: DocInstance a -> Maybe (InstHead a)-isUndocdInstance (i,Nothing,_) = Just i-isUndocdInstance _ = Nothing---- | Print a possibly commented instance. The instance header is printed inside--- an 'argBox'. The comment is printed to the right of the box in normal comment--- style.-ppDocInstance :: Bool -> DocInstance DocName -> LaTeX-ppDocInstance unicode (instHead, doc, _) =- declWithDoc (ppInstDecl unicode instHead) (fmap docToLaTeX $ fmap _doc doc)---ppInstDecl :: Bool -> InstHead DocName -> LaTeX-ppInstDecl unicode instHead = keyword "instance" <+> ppInstHead unicode instHead---ppInstHead :: Bool -> InstHead DocName -> LaTeX-ppInstHead unicode (InstHead {..}) = case ihdInstType of- ClassInst ctx _ _ _ -> ppContextNoLocs ctx unicode <+> typ- TypeInst rhs -> keyword "type" <+> typ <+> tibody rhs- DataInst _ -> error "data instances not supported by --latex yet"- where- typ = ppAppNameTypes ihdClsName ihdKinds ihdTypes unicode- tibody = maybe empty (\t -> equals <+> ppType unicode t)--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-----------------------------------------------------------------------------------ppDataDecl :: [DocInstance DocName] ->- [(DocName, DocForDecl DocName)] -> SrcSpan ->- Maybe (Documentation DocName) -> TyClDecl DocName -> Bool ->- LaTeX-ppDataDecl instances subdocs _loc doc dataDecl unicode-- = declWithDoc (ppDataHeader dataDecl unicode <+> whereBit)- (if null body then Nothing else Just (vcat body))- $$ instancesBit-- where- cons = dd_cons (tcdDataDefn dataDecl)- resTy = (unLoc . head) cons-- body = catMaybes [constrBit, doc >>= documentationToLaTeX]-- (whereBit, leaders)- | null cons = (empty,[])- | otherwise = case resTy of- ConDeclGADT{} -> (decltt (keyword "where"), repeat empty)- _ -> (empty, (decltt (text "=") : repeat (decltt (text "|"))))-- constrBit- | null cons = Nothing- | otherwise = Just $- text "\\haddockbeginconstrs" $$- vcat (zipWith (ppSideBySideConstr subdocs unicode) leaders cons) $$- text "\\end{tabulary}\\par"-- instancesBit = ppDocInstances unicode instances----- ppConstrHdr is for (non-GADT) existentials constructors' syntax-ppConstrHdr :: Bool -> [Name] -> HsContext DocName -> Bool -> LaTeX-ppConstrHdr forall tvs ctxt unicode- = (if null tvs then empty else ppForall)- <+>- (if null ctxt then empty else ppContextNoArrow ctxt unicode <+> darrow unicode <+> text " ")- where- ppForall = case forall of- True -> forallSymbol unicode <+> hsep (map ppName tvs) <+> text ". "- False -> empty---ppSideBySideConstr :: [(DocName, DocForDecl DocName)] -> Bool -> LaTeX- -> LConDecl DocName -> LaTeX-ppSideBySideConstr subdocs unicode leader (L _ con@(ConDeclH98 {})) =- leader <->- case con_details 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-- where- doRecordFields fields =- vcat (map (ppSideBySideField subdocs unicode) (map unLoc fields))--- 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 = tyvarNames (fromMaybe (HsQTvs PlaceHolder [] PlaceHolder) (con_qvars con))- context = unLoc (fromMaybe (noLoc []) (con_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.- mbDoc = case getConNames con of- [] -> panic "empty con_names"- (cn:_) -> lookup (unLoc cn) subdocs >>=- fmap _doc . combineDocumentation . fst--ppSideBySideConstr subdocs unicode leader (L _ con@(ConDeclGADT {})) =- leader <->- doGADTCon (hsib_body $ con_type 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-{- old--ppSideBySideConstr :: [(DocName, DocForDecl DocName)] -> Bool -> LaTeX- -> LConDecl DocName -> LaTeX-ppSideBySideConstr subdocs unicode leader (L loc con) =- leader <->- case con_res con of- ResTyH98 -> case con_details 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-- ResTyGADT _ resTy -> case con_details con of- -- prefix & infix could also use hsConDeclArgTys if it seemed to- -- simplify the code.- PrefixCon args -> doGADTCon args resTy- cd@(RecCon (L _ fields)) -> doGADTCon (hsConDeclArgTys cd) resTy <+> nl $$- doRecordFields fields- InfixCon arg1 arg2 -> doGADTCon [arg1, arg2] resTy-- where- doRecordFields fields =- vcat (map (ppSideBySideField subdocs unicode) (map unLoc fields))-- doGADTCon args resTy = decltt (ppOcc <+> dcolon unicode <+>- ppLType unicode (mk_forall $ mk_phi $- foldr mkFunTy resTy args)- ) <-> rDoc mbDoc--- header_ = ppConstrHdr (con_explicit con) tyVars context- occ = map (nameOccName . getName . unLoc) $ con_names con- ppOcc = case occ of- [one] -> ppBinder one- _ -> cat (punctuate comma (map ppBinder occ))- ltvs = con_qvars con- tyVars = tyvarNames (con_qvars con)- context = unLoc (con_cxt con)-- mk_forall ty | con_explicit con = L loc (HsForAllTy (hsQTvExplicit ltvs) ty)- | otherwise = ty- mk_phi ty | null context = ty- | otherwise = L loc (HsQualTy (con_cxt con) ty)-- -- 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 con_names con of- [] -> panic "empty con_names"- (cn:_) -> lookup (unLoc cn) subdocs >>=- fmap _doc . combineDocumentation . fst- mkFunTy a b = noLoc (HsFunTy a b)--}--ppSideBySideField :: [(DocName, DocForDecl DocName)] -> Bool -> ConDeclField DocName -> LaTeX-ppSideBySideField subdocs unicode (ConDeclField names ltype _) =- decltt (cat (punctuate comma (map (ppBinder . rdrNameOcc . unLoc . rdrNameFieldOcc . 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 (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 ]--- -}----- | Print the LHS of a data\/newtype declaration.--- Currently doesn't handle 'data instance' decls or kind signatures-ppDataHeader :: TyClDecl DocName -> Bool -> LaTeX-ppDataHeader (DataDecl { tcdLName = L _ name, tcdTyVars = tyvars- , tcdDataDefn = HsDataDefn { dd_ND = nd, dd_ctxt = ctxt } }) unicode- = -- newtype or data- (case nd of { NewType -> keyword "newtype"; DataType -> 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-------------------------------------------------------------------------------------- | Print an application of a DocName and two lists of HsTypes (kinds, types)-ppAppNameTypes :: DocName -> [HsType DocName] -> [HsType DocName] -> Bool -> LaTeX-ppAppNameTypes n ks ts unicode = ppTypeApp n ks ts ppDocName (ppParendType unicode)----- | 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] -> [a] -> (DocName -> LaTeX) -> (a -> LaTeX) -> LaTeX-ppTypeApp n [] (t1:t2:rest) ppDN ppT- | operator, not . null $ rest = parens opApp <+> hsep (map ppT rest)- | operator = opApp- where- operator = isNameSym . getName $ n- opApp = ppT t1 <+> ppDN n <+> ppT t2--ppTypeApp n ks ts ppDN ppT = ppDN n <+> hsep (map ppT $ ks ++ ts)------------------------------------------------------------------------------------- * Contexts-----------------------------------------------------------------------------------ppLContext, ppLContextNoArrow :: Located (HsContext DocName) -> Bool -> LaTeX-ppLContext = ppContext . unLoc-ppLContextNoArrow = ppContextNoArrow . unLoc--ppContextNoLocsMaybe :: [HsType DocName] -> Bool -> Maybe LaTeX-ppContextNoLocsMaybe [] _ = Nothing-ppContextNoLocsMaybe cxt unicode = Just $ pp_hs_context cxt unicode--ppContextNoArrow :: HsContext DocName -> Bool -> LaTeX-ppContextNoArrow cxt unicode = fromMaybe empty $- ppContextNoLocsMaybe (map unLoc cxt) unicode---ppContextNoLocs :: [HsType DocName] -> Bool -> LaTeX-ppContextNoLocs cxt unicode = maybe empty (<+> darrow unicode) $- ppContextNoLocsMaybe cxt unicode---ppContext :: HsContext DocName -> Bool -> LaTeX-ppContext cxt unicode = ppContextNoLocs (map unLoc cxt) unicode---pp_hs_context :: [HsType DocName] -> Bool -> LaTeX-pp_hs_context [] _ = empty-pp_hs_context [p] unicode = ppType 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---tupleParens :: HsTupleSort -> [LaTeX] -> LaTeX-tupleParens HsUnboxedTuple = ubxParenList-tupleParens _ = parenList------------------------------------------------------------------------------------- * Rendering of HsType------ Stolen from Html and tweaked for LaTeX generation-----------------------------------------------------------------------------------pREC_TOP, pREC_FUN, pREC_OP, pREC_CON :: Int--pREC_TOP = (0 :: Int) -- type in ParseIface.y in GHC-pREC_FUN = (1 :: Int) -- btype in ParseIface.y in GHC- -- Used for LH arg of (->)-pREC_OP = (2 :: Int) -- Used for arg of any infix operator- -- (we don't keep their fixities around)-pREC_CON = (3 :: Int) -- Used for arg of type applicn:- -- always parenthesise unless atomic--maybeParen :: Int -- Precedence of context- -> Int -- Precedence of top-level operator- -> LaTeX -> LaTeX -- Wrap in parens if (ctxt >= op)-maybeParen ctxt_prec op_prec p | ctxt_prec >= op_prec = parens p- | otherwise = p---ppLType, ppLParendType, ppLFunLhType :: Bool -> Located (HsType DocName) -> LaTeX-ppLType unicode y = ppType unicode (unLoc y)-ppLParendType unicode y = ppParendType unicode (unLoc y)-ppLFunLhType unicode y = ppFunLhType unicode (unLoc y)---ppType, ppParendType, ppFunLhType :: Bool -> HsType DocName -> LaTeX-ppType unicode ty = ppr_mono_ty pREC_TOP ty unicode-ppParendType unicode ty = ppr_mono_ty pREC_CON ty unicode-ppFunLhType unicode ty = ppr_mono_ty pREC_FUN ty unicode--ppLKind :: Bool -> LHsKind DocName -> LaTeX-ppLKind unicode y = ppKind unicode (unLoc y)--ppKind :: Bool -> HsKind DocName -> LaTeX-ppKind unicode ki = ppr_mono_ty pREC_TOP ki unicode----- Drop top-level for-all type variables in user style--- since they are implicit in Haskell--ppr_mono_lty :: Int -> LHsType DocName -> Bool -> LaTeX-ppr_mono_lty ctxt_prec ty unicode = ppr_mono_ty ctxt_prec (unLoc ty) unicode---ppr_mono_ty :: Int -> HsType DocName -> Bool -> LaTeX-ppr_mono_ty ctxt_prec (HsForAllTy tvs ty) unicode- = maybeParen ctxt_prec pREC_FUN $- sep [ hsep (forallSymbol unicode : ppTyVars tvs) <> dot- , ppr_mono_lty pREC_TOP ty unicode ]-ppr_mono_ty ctxt_prec (HsQualTy ctxt ty) unicode- = maybeParen ctxt_prec pREC_FUN $- sep [ ppLContext ctxt unicode- , ppr_mono_lty pREC_TOP ty unicode ]--ppr_mono_ty _ (HsBangTy b ty) u = ppBang b <> ppLParendType u ty-ppr_mono_ty _ (HsTyVar (L _ name)) _ = ppDocName name-ppr_mono_ty ctxt_prec (HsFunTy ty1 ty2) u = ppr_fun_ty ctxt_prec ty1 ty2 u-ppr_mono_ty _ (HsTupleTy con tys) u = tupleParens con (map (ppLType u) tys)-ppr_mono_ty _ (HsKindSig ty kind) u = parens (ppr_mono_lty pREC_TOP ty u <+> dcolon u <+> ppLKind u kind)-ppr_mono_ty _ (HsListTy ty) u = brackets (ppr_mono_lty pREC_TOP ty u)-ppr_mono_ty _ (HsPArrTy ty) u = pabrackets (ppr_mono_lty pREC_TOP ty u)-ppr_mono_ty _ (HsIParamTy 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 _ (HsCoreTy {}) _ = error "ppr_mono_ty HsCoreTy"-ppr_mono_ty _ (HsExplicitListTy _ tys) u = Pretty.quote $ brackets $ hsep $ punctuate comma $ map (ppLType u) tys-ppr_mono_ty _ (HsExplicitTupleTy _ tys) u = Pretty.quote $ parenList $ map (ppLType u) tys--ppr_mono_ty ctxt_prec (HsEqTy ty1 ty2) unicode- = maybeParen ctxt_prec pREC_OP $- ppr_mono_lty pREC_OP ty1 unicode <+> char '~' <+> ppr_mono_lty pREC_OP ty2 unicode--ppr_mono_ty ctxt_prec (HsAppTy fun_ty arg_ty) unicode- = maybeParen ctxt_prec pREC_CON $- hsep [ppr_mono_lty pREC_FUN fun_ty unicode, ppr_mono_lty pREC_CON arg_ty unicode]--ppr_mono_ty ctxt_prec (HsOpTy ty1 op ty2) unicode- = maybeParen ctxt_prec pREC_FUN $- ppr_mono_lty pREC_OP ty1 unicode <+> ppr_op <+> ppr_mono_lty pREC_OP ty2 unicode- where- ppr_op = if not (isSymOcc occName) then char '`' <> ppLDocName op <> char '`' else ppLDocName op- occName = nameOccName . getName . unLoc $ op--ppr_mono_ty ctxt_prec (HsParTy ty) unicode--- = parens (ppr_mono_lty pREC_TOP ty)- = ppr_mono_lty ctxt_prec ty unicode--ppr_mono_ty ctxt_prec (HsDocTy ty _) unicode- = ppr_mono_lty ctxt_prec ty unicode--ppr_mono_ty _ (HsWildCardTy (AnonWildCard _)) _ = char '_'--ppr_mono_ty _ (HsTyLit t) u = ppr_tylit t u--ppr_mono_ty _ (HsAppsTy {}) _ = panic "ppr_mono_ty:HsAppsTy"---ppr_tylit :: HsTyLit -> Bool -> LaTeX-ppr_tylit (HsNumTy _ n) _ = integer n-ppr_tylit (HsStrTy _ s) _ = text (show s)- -- XXX: Ok in verbatim, but not otherwise- -- XXX: Do something with Unicode parameter?---ppr_fun_ty :: Int -> LHsType DocName -> LHsType DocName -> Bool -> LaTeX-ppr_fun_ty ctxt_prec ty1 ty2 unicode- = let p1 = ppr_mono_lty pREC_FUN ty1 unicode- p2 = ppr_mono_lty pREC_TOP ty2 unicode- in- maybeParen ctxt_prec pREC_FUN $- sep [p1, arrow unicode <+> p2]------------------------------------------------------------------------------------- * Names-----------------------------------------------------------------------------------ppBinder :: OccName -> LaTeX-ppBinder n- | isInfixName n = parens $ ppOccName n- | otherwise = ppOccName n--isInfixName :: OccName -> Bool-isInfixName n = isVarSym n || isConSym n--ppSymName :: Name -> LaTeX-ppSymName name- | isNameSym name = parens $ ppName name- | otherwise = ppName name---ppVerbOccName :: OccName -> LaTeX-ppVerbOccName = text . latexFilter . occNameString--ppIPName :: HsIPName -> LaTeX-ppIPName ip = text $ unpackFS $ hsIPNameFS ip--ppOccName :: OccName -> LaTeX-ppOccName = text . occNameString---ppVerbDocName :: DocName -> LaTeX-ppVerbDocName = ppVerbOccName . nameOccName . getName---ppVerbRdrName :: RdrName -> LaTeX-ppVerbRdrName = ppVerbOccName . rdrNameOcc---ppDocName :: DocName -> LaTeX-ppDocName = ppOccName . nameOccName . getName---ppLDocName :: Located 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 '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---latexMonoMunge :: Char -> String -> String-latexMonoMunge ' ' s = '\\' : ' ' : s-latexMonoMunge '\n' s = '\\' : '\\' : s-latexMonoMunge c s = latexMunge c s------------------------------------------------------------------------------------- * Doc Markup-----------------------------------------------------------------------------------parLatexMarkup :: (a -> LaTeX) -> DocMarkup a (StringContext -> LaTeX)-parLatexMarkup ppId = Markup {- markupParagraph = \p v -> p v <> text "\\par" $$ text "",- markupEmpty = \_ -> empty,- markupString = \s v -> text (fixString v s),- markupAppend = \l r v -> l v <> r v,- markupIdentifier = markupId ppId,- markupIdentifierUnchecked = markupId (ppVerbOccName . snd),- markupModule = \m _ -> let (mdl,_ref) = break (=='#') m in tt (text mdl),- markupWarning = \p v -> emph (p v),- markupEmphasis = \p v -> emph (p v),- markupBold = \p v -> bold (p v),- markupMonospaced = \p _ -> tt (p Mono),- markupUnorderedList = \p v -> itemizedList (map ($v) p) $$ text "",- markupPic = \p _ -> markupPic p,- markupMathInline = \p _ -> markupMathInline p,- markupMathDisplay = \p _ -> markupMathDisplay p,- markupOrderedList = \p v -> enumeratedList (map ($v) p) $$ text "",- markupDefList = \l v -> descriptionList (map (\(a,b) -> (a v, b v)) l),- markupCodeBlock = \p _ -> quote (verb (p Verb)) $$ text "",- markupHyperlink = \l _ -> markupLink l,- markupAName = \_ _ -> empty,- markupProperty = \p _ -> quote $ verb $ text p,- markupExample = \e _ -> quote $ verb $ text $ unlines $ map exampleToString e,- markupHeader = \(Header l h) p -> header l (h p)- }- where- header 1 d = text "\\section*" <> braces d- header 2 d = text "\\subsection*" <> braces d- header l d- | l > 0 && l <= 6 = text "\\subsubsection*" <> braces d- header l _ = error $ "impossible header level in LaTeX generation: " ++ show l-- fixString Plain s = latexFilter s- fixString Verb s = s- fixString Mono s = latexMonoFilter s-- markupLink (Hyperlink url mLabel) = case mLabel of- Just label -> text "\\href" <> braces (text url) <> braces (text label)- Nothing -> text "\\url" <> braces (text url)-- -- Is there a better way of doing this? Just a space is an aribtrary choice.- markupPic (Picture uri title) = parens (imageText title)- where- imageText Nothing = beg- imageText (Just t) = beg <> text " " <> text t-- beg = text "image: " <> text uri-- markupMathInline mathjax = text "\\(" <> text mathjax <> text "\\)"-- markupMathDisplay mathjax = text "\\[" <> text mathjax <> text "\\]"-- markupId ppId_ id v =- case v of- Verb -> theid- Mono -> theid- Plain -> text "\\haddockid" <> braces theid- where theid = ppId_ id---latexMarkup :: DocMarkup DocName (StringContext -> LaTeX)-latexMarkup = parLatexMarkup ppVerbDocName---rdrLatexMarkup :: DocMarkup RdrName (StringContext -> LaTeX)-rdrLatexMarkup = parLatexMarkup ppVerbRdrName---docToLaTeX :: Doc DocName -> LaTeX-docToLaTeX doc = markup latexMarkup doc Plain---documentationToLaTeX :: Documentation DocName -> Maybe LaTeX-documentationToLaTeX = fmap docToLaTeX . fmap _doc . combineDocumentation---rdrDocToLaTeX :: Doc RdrName -> LaTeX-rdrDocToLaTeX doc = markup rdrLatexMarkup doc Plain---data StringContext = Plain | Verb | Mono---latexStripTrailingWhitespace :: Doc a -> Doc a-latexStripTrailingWhitespace (DocString s)- | null s' = DocEmpty- | otherwise = DocString s- where s' = reverse (dropWhile isSpace (reverse s))-latexStripTrailingWhitespace (DocAppend l r)- | DocEmpty <- r' = latexStripTrailingWhitespace l- | otherwise = DocAppend l r'- where- r' = latexStripTrailingWhitespace r-latexStripTrailingWhitespace (DocParagraph p) =- latexStripTrailingWhitespace p-latexStripTrailingWhitespace other = other------------------------------------------------------------------------------------- * LaTeX utils-----------------------------------------------------------------------------------itemizedList :: [LaTeX] -> LaTeX-itemizedList items =- text "\\begin{itemize}" $$- vcat (map (text "\\item" $$) items) $$- text "\\end{itemize}"---enumeratedList :: [LaTeX] -> LaTeX-enumeratedList items =- text "\\begin{enumerate}" $$- vcat (map (text "\\item " $$) items) $$- text "\\end{enumerate}"---descriptionList :: [(LaTeX,LaTeX)] -> LaTeX-descriptionList items =- text "\\begin{description}" $$- vcat (map (\(a,b) -> text "\\item" <> brackets a <+> b) items) $$- text "\\end{description}"---tt :: LaTeX -> LaTeX-tt ltx = text "\\haddocktt" <> braces ltx---decltt :: LaTeX -> LaTeX-decltt ltx = text "\\haddockdecltt" <> braces ltx---emph :: LaTeX -> LaTeX-emph ltx = text "\\emph" <> braces ltx--bold :: LaTeX -> LaTeX-bold ltx = text "\\textbf" <> braces ltx--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.---quote :: LaTeX -> LaTeX-quote doc = text "\\begin{quote}" $$ doc $$ text "\\end{quote}"---dcolon, arrow, darrow, forallSymbol :: Bool -> LaTeX-dcolon unicode = text (if unicode then "∷" else "::")-arrow unicode = text (if unicode then "→" else "->")-darrow unicode = text (if unicode then "⇒" else "=>")-forallSymbol unicode = text (if unicode then "∀" else "forall")---dot :: LaTeX-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 "#)"---pabrackets :: LaTeX -> LaTeX-pabrackets h = text "[:" <> h <> text ":]"+{-# LANGUAGE TypeFamilies #-}++-----------------------------------------------------------------------------+-- |+-- Module : Haddock.Backends.LaTeX+-- Copyright : (c) Simon Marlow 2010,+-- Mateusz Kowalczyk 2013+-- License : BSD-like+--+-- Maintainer : haddock@projects.haskell.org+-- Stability : experimental+-- Portability : portable+-----------------------------------------------------------------------------+module Haddock.Backends.LaTeX (+ ppLaTeX,+) where++import Documentation.Haddock.Markup+import Haddock.Doc (combineDocumentation)+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.Types.Name.Occurrence+import GHC.Types.Name ( nameOccName )+import GHC.Types.Name.Reader ( rdrNameOcc )+import GHC.Core.Type ( Specificity(..) )+import GHC.Data.FastString ( unpackFS )++import qualified Data.Map as Map+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++\haddockmoduleheading{\texttt{Data.List}}+\hrulefill+{\haddockverb\begin{verbatim}+module Data.List (+ (++), head, last, tail, init, null, length, map, reverse,+ ) where\end{verbatim}}+\hrulefill++\section{Basic functions}+\begin{haddockdesc}+\item[\begin{tabular}{@{}l}+head\ ::\ {\char 91}a{\char 93}\ ->\ a+\end{tabular}]\haddockbegindoc+Extract the first element of a list, which must be non-empty.+\par++\end{haddockdesc}+\begin{haddockdesc}+\item[\begin{tabular}{@{}l}+last\ ::\ {\char 91}a{\char 93}\ ->\ a+\end{tabular}]\haddockbegindoc+Extract the last element of a list, which must be finite and non-empty.+\par++\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+++haddockSty :: FilePath+haddockSty = "haddock.sty"+++type LaTeX = Pretty.Doc++-- | Default way of rendering a 'LaTeX'. The width is 90 by default (since 100+-- often overflows the line).+latex2String :: LaTeX -> String+latex2String = fullRender (PageMode True) 90 1 txtPrinter ""++ppLaTeXTop+ :: 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}"+ ]++ 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+ --+ 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+ ( RnExportD+ { rnExpDExpD =+ ( ExportD+ { expDDecl = decl+ , expDSubDocs = 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)+ = 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+processExports (e : es) =+ processExport e $$ processExports es+++isSimpleSig :: ExportItem DocNameI -> Maybe ([DocName], HsSigType DocNameI)+isSimpleSig+ ( ExportDecl+ ( RnExportD+ { 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+++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"+++-- | 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 -> (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+++moduleLaTeXFile :: Module -> FilePath+moduleLaTeXFile mdl = moduleBasename mdl ++ ".tex"+++moduleBasename :: Module -> FilePath+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 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+ 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+++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"+++-------------------------------------------------------------------------------+-- * 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 associated doc instances decl unicode =+ 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++ 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")+ | 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)+ ]++ 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++++-------------------------------------------------------------------------------+-- * 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 _ _ _ = 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+ -> LaTeX+ppFunSig leader doc docnames (L _ typ) unicode =+ 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++-- | 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++-- | 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 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)++-- | 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 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 }) =+ case outer_bndrs of+ HsOuterExplicit{hso_bndrs = bndrs} ->+ [ ( decltt leader+ , decltt (ppHsForAllTelescope (mkHsForAllInvisTeleI bndrs) unicode)+ <+> ppLType unicode ltype+ ) ]+ HsOuterImplicit{} -> do_largs n leader ltype++ do_largs :: Int -> LaTeX -> LHsType DocNameI -> [(LaTeX, LaTeX)]+ 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 _ 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+ --+ -- 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) (char ' ')) <> char ','+ gadtEnd = hcat (replicate (if unicode then 3 else 4) (char ' ')) <> char '}'+ gadtOpen = char '{'+++ppTypeSig :: [Name] -> HsSigType DocNameI -> Bool -> LaTeX+ppTypeSig nms ty unicode =+ hsep (punctuate comma $ map ppSymName nms)+ <+> dcolon unicode+ <+> ppSigType unicode ty++ppHsOuterTyVarBndrs :: HsOuterTyVarBndrs flag DocNameI -> Bool -> LaTeX+ppHsOuterTyVarBndrs (HsOuterImplicit{}) _ = empty+ppHsOuterTyVarBndrs (HsOuterExplicit{hso_bndrs = bndrs}) unicode =+ hsep (forallSymbol unicode : ppTyVars bndrs) <> dot++ppHsForAllTelescope :: HsForAllTelescope DocNameI -> Bool -> LaTeX+ppHsForAllTelescope tele unicode = case tele of+ HsForAllVis { hsf_vis_bndrs = bndrs } ->+ hsep (forallSymbol unicode : ppTyVars bndrs) <> text "\\" <> arrow unicode+ HsForAllInvis { hsf_invis_bndrs = bndrs } ->+ hsep (forallSymbol unicode : ppTyVars bndrs) <> dot+++ppTyVars :: [LHsTyVarBndr flag DocNameI] -> [LaTeX]+ppTyVars = map (ppSymName . getName . hsLTyVarNameI)+++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}"+++-- 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}"+++-------------------------------------------------------------------------------+-- * 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 = maybeDoc . fmap latexStripTrailingWhitespace+++-------------------------------------------------------------------------------+-- * Class declarations+-------------------------------------------------------------------------------+++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++-- 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))+ where+ 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+ | 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+ | L _ (ClassOpSig _ is_def lnames typ) <- lsigs+ , let doc | is_def = noDocForDecl+ | otherwise = lookupAnySubdoc (head names) subdocs+ names = map 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.++ 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+ 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 _ = Nothing++-- | Print a possibly commented instance. The instance header is printed inside+-- an 'argBox'. The comment is printed to the right of the box in normal comment+-- style.+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+ 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+ where+ typ = ppAppNameTypes ihdClsName ihdTypes unicode+ tibody = maybe empty (\t -> equals <+> ppType unicode t)++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 pats instances subdocs doc dataDecl unicode =+ declWithDoc (ppDataHeader dataDecl unicode <+> whereBit)+ (if null body then Nothing else Just (vcat body))+ $$ instancesBit++ where+ cons = dd_cons (tcdDataDefn dataDecl)++ body = catMaybes [doc >>= documentationToLaTeX, constrBit,patternBit]++ (whereBit, leaders)+ | null cons+ , 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 "|"))))++ 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"++ 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"++ 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+ -> LaTeX+ppConstrHdr forall_ tvs ctxt unicode = ppForall <> ppCtxt+ where+ ppForall+ | null tvs || not forall_ = empty+ | otherwise = ppHsForAllTelescope (mkHsForAllInvisTeleI tvs) unicode++ 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 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)+ L _ aConName :| _ = getConNamesI con++ occ = toList $ nameOccName . getName . unLoc <$> getConNamesI 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 = 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)+ ]++ 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++ 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++ 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)+ ]+++ -- 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+++-- | 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 . 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 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+ , 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)+ ]++ 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 _ _ = error "ppDataHeader: illegal argument"+++--------------------------------------------------------------------------------+-- * Type applications+--------------------------------------------------------------------------------++ppAppDocNameTyVarBndrs :: RenderableBndrFlag flag =>+ Bool -> DocName -> [LHsTyVarBndr flag DocNameI] -> LaTeX+ppAppDocNameTyVarBndrs unicode n vs =+ 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)++-- | 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+ | operator, not . null $ rest = parens opApp <+> hsep (map ppT rest)+ | 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++ppLContextNoArrow :: LHsContext DocNameI -> Bool -> LaTeX+ppLContextNoArrow ctxt unicode = ppContextNoArrow (unLoc ctxt) unicode++ppContextNoLocsMaybe :: [HsType DocNameI] -> Bool -> Maybe LaTeX+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+++ppContextNoLocs :: [HsType DocNameI] -> Bool -> LaTeX+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 [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+++tupleParens :: HsTupleSort -> [LaTeX] -> LaTeX+tupleParens HsUnboxedTuple = ubxParenList+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)+ppLParendType unicode y = ppParendType 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+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++ppSigType :: Bool -> HsSigType DocNameI -> LaTeX+ppSigType unicode sig_ty = ppr_sig_ty (reparenSigType sig_ty) unicode++ppLHsTypeArg :: Bool -> LHsTypeArg DocNameI -> LaTeX+ppLHsTypeArg unicode (HsValArg ty) = ppLParendType unicode ty+ppLHsTypeArg unicode (HsTypeArg _ ki) = atSign unicode <>+ ppLParendType unicode ki+ppLHsTypeArg _ (HsArgPar _) = text ""++class RenderableBndrFlag flag where+ ppHsTyVarBndr :: Bool -> HsTyVarBndr flag DocNameI -> LaTeX++instance RenderableBndrFlag () where+ ppHsTyVarBndr _ (UserTyVar _ _ (L _ name)) = ppDocName name+ ppHsTyVarBndr unicode (KindedTyVar _ _ (L _ name) kind) =+ parens (ppDocName name) <+> dcolon unicode <+> ppLKind unicode kind++instance RenderableBndrFlag Specificity where+ ppHsTyVarBndr _ (UserTyVar _ SpecifiedSpec (L _ name)) = ppDocName name+ ppHsTyVarBndr _ (UserTyVar _ InferredSpec (L _ name)) = braces $ ppDocName name+ ppHsTyVarBndr unicode (KindedTyVar _ SpecifiedSpec (L _ name) kind) =+ parens (ppDocName name) <+> dcolon unicode <+> ppLKind unicode kind+ ppHsTyVarBndr unicode (KindedTyVar _ InferredSpec (L _ name) kind) =+ braces (ppDocName name) <+> dcolon unicode <+> ppLKind unicode kind++ppLKind :: Bool -> LHsKind DocNameI -> LaTeX+ppLKind unicode y = ppKind unicode (unLoc y)++ppKind :: Bool -> HsKind DocNameI -> LaTeX+ppKind unicode ki = ppr_mono_ty (reparenTypePrec PREC_TOP ki) unicode++-- Drop top-level for-all type variables in user style+-- 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_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 (HsTyVar _ NotPromoted (L _ name)) _ = 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 (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 (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 (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 unicode <> 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_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?+++-------------------------------------------------------------------------------+-- * Names+-------------------------------------------------------------------------------+++ppBinder :: OccName -> LaTeX+ppBinder n+ | isSymOcc n = parens $ ppOccName n+ | otherwise = ppOccName n++ppBinderInfix :: OccName -> LaTeX+ppBinderInfix n+ | isSymOcc n = ppOccName n+ | 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++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 '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+++latexMonoMunge :: Char -> String -> String+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)+ }+ where+ blockElem :: LaTeX -> LaTeX -> LaTeX+ blockElem = ($$)++ inlineElem :: LaTeX -> LaTeX -> LaTeX+ inlineElem = (<>)++ header 1 d = text "\\section*" <> braces d+ header 2 d = text "\\subsection*" <> braces d+ header l d+ | l > 0 && l <= 6 = text "\\subsubsection*" <> braces d+ header l _ = error $ "impossible header level in LaTeX generation: " ++ show l++ table _ _ _ = text "{TODO: Table}"++ fixString Plain s = latexFilter 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)++ -- Is there a better way of doing this? Just a space is an arbitrary choice.+ markupPic (Picture uri title) = parens (imageText title)+ where+ imageText Nothing = beg+ imageText (Just t) = beg <> text " " <> text t++ beg = text "image: " <> text uri++ markupMathInline mathjax = text "\\(" <> text mathjax <> text "\\)"++ markupMathDisplay mathjax = text "\\[" <> text mathjax <> text "\\]"++ markupId v wrappedOcc =+ case v of+ Verb -> text i+ Mono -> text "\\haddockid" <> braces (text . latexMonoFilter $ i)+ Plain -> text "\\haddockid" <> braces (text . latexFilter $ i)+ where i = showWrapped occNameString wrappedOcc++docToLaTeX :: Doc DocName -> LaTeX+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+++latexStripTrailingWhitespace :: Doc a -> Doc a+latexStripTrailingWhitespace (DocString s)+ | null s' = DocEmpty+ | otherwise = DocString s+ where s' = reverse (dropWhile isSpace (reverse s))+latexStripTrailingWhitespace (DocAppend l r)+ | DocEmpty <- r' = latexStripTrailingWhitespace l+ | 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}}"+++enumeratedList :: [LaTeX] -> LaTeX+enumeratedList items =+ text "\\vbox{\\begin{enumerate}" $$+ vcat (map (text "\\item " $$) items) $$+ text "\\end{enumerate}}"+++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}}"+++tt :: LaTeX -> LaTeX+tt ltx = text "\\haddocktt" <> braces ltx+++decltt :: LaTeX -> LaTeX+decltt ltx = text "\\haddockdecltt" <> braces (text filtered)+ where filtered = latexMonoFilter (latex2String ltx)++emph :: LaTeX -> LaTeX+emph ltx = text "\\emph" <> braces ltx++bold :: LaTeX -> LaTeX+bold ltx = text "\\textbf" <> braces ltx++-- TODO: @verbatim@ is too much since+--+-- * Haddock supports markup _inside_ of code blocks. Right now, the LaTeX+-- representing that markup gets printed verbatim+-- * Verbatim environments are not supported everywhere (example: not nested+-- 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.+++quote :: LaTeX -> LaTeX+quote doc = text "\\begin{quote}" $$ doc $$ text "\\end{quote}"+++dcolon, arrow, lollipop, darrow, forallSymbol, starSymbol, atSign :: Bool -> LaTeX+dcolon 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")+starSymbol unicode = text (if unicode then "★" else "*")+atSign unicode = text (if unicode then "@" else "@")++multAnnotation :: LaTeX+multAnnotation = text "%"++dot :: LaTeX+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
src/Haddock/Backends/Xhtml.hs view
@@ -11,10 +11,17 @@ -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------{-# LANGUAGE CPP #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE BangPatterns #-}+ module Haddock.Backends.Xhtml ( ppHtml, copyHtmlBits, ppHtmlIndex, ppHtmlContents,+ ppJsonIndex ) where @@ -27,108 +34,154 @@ import Haddock.Backends.Xhtml.Themes import Haddock.Backends.Xhtml.Types import Haddock.Backends.Xhtml.Utils+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 qualified Text.XHtml as XHtml import Haddock.GhcUtils import Control.Monad ( when, unless )+import qualified Data.ByteString.Builder as Builder+import Control.DeepSeq (force)+import Data.Bifunctor ( bimap ) import Data.Char ( toUpper, isSpace )-import Data.List ( sortBy, intercalate, isPrefixOf, intersperse )+import Data.Either ( partitionEithers )+import Data.Foldable ( traverse_, foldl')+import Data.List ( sortBy, isPrefixOf, intersperse ) import Data.Maybe-import System.FilePath hiding ( (</>) ) import System.Directory-import Data.Map ( Map )-import qualified Data.Map as Map hiding ( Map )+import System.FilePath hiding ( (</>) )+import qualified System.IO as IO+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 DynFlags (Language(..))-import GHC hiding ( NoLink, moduleInfo )-import Name-import Module+import GHC hiding ( NoLink, moduleInfo,LexicalFixity(..), anchor )+import GHC.Types.Name+import GHC.Unit.State -------------------------------------------------------------------------------- -- * Generating HTML documentation -------------------------------------------------------------------------------- --ppHtml :: DynFlags+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 dflags doctitle maybe_package ifaces odir prologue+ppHtml state doctitle maybe_package ifaces reexported_ifaces odir prologue themes maybe_mathjax_url maybe_source_url maybe_wiki_url- maybe_contents_url maybe_index_url unicode- qual debug = do+ 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 dflags odir doctitle maybe_package+ ppHtmlContents state odir doctitle maybe_package themes maybe_mathjax_url maybe_index_url maybe_source_url maybe_wiki_url- (map toInstalledIface visible_ifaces)+ withQuickjump+ [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 (makeContentsQual qual)+ prologue debug pkg (makeContentsQual qual) - when (isNothing maybe_index_url) $+ when (isNothing maybe_index_url) $ do ppHtmlIndex odir doctitle maybe_package themes maybe_mathjax_url maybe_contents_url maybe_source_url maybe_wiki_url- (map toInstalledIface visible_ifaces) debug+ 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_contents_url maybe_index_url unicode qual debug) visible_ifaces+ 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 -> IO ()-copyHtmlBits odir libdir themes = do+copyHtmlBits :: FilePath -> FilePath -> Themes -> Bool -> IO ()+copyHtmlBits odir libdir themes withQuickjump = do let libhtmldir = joinPath [libdir, "html"] copyCssFile f = copyFile f (combine odir (takeFileName f)) copyLibFile f = copyFile (joinPath [libhtmldir, f]) (joinPath [odir, f]) mapM_ copyCssFile (cssFiles themes)- copyLibFile jsFile+ copyLibFile haddockJsFile+ copyCssFile (joinPath [libhtmldir, quickJumpCssFile])+ when withQuickjump (copyLibFile jsQuickJumpFile) return () -headHtml :: String -> Maybe String -> Themes -> Maybe String -> Html-headHtml docTitle miniPage themes mathjax_url =- header << [- meta ! [httpequiv "Content-Type", content "text/html; charset=UTF-8"],- thetitle << docTitle,- styleSheet themes,- script ! [src jsFile, thetype "text/javascript"] << noHtml,- script ! [src mjUrl, thetype "text/javascript"] << noHtml,- script ! [thetype "text/javascript"]- -- NB: Within XHTML, the content of script tags needs to be- -- a <![CDATA[ section. Will break if the miniPage name could- -- have "]]>" in it!- << primHtml (- "//<![CDATA[\nwindow.onload = function () {pageLoad();"- ++ setSynopsis ++ "};\n//]]>\n")+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 ] where- setSynopsis = maybe "" (\p -> "setSynopsis(\"" ++ p ++ "\");") miniPage- mjUrl = maybe "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML" id mathjax_url+ 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+-- The TypeScript should replace this <li> 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 False = Nothing+ srcButton :: SourceURLs -> Maybe Interface -> Maybe Html srcButton (Just src_base_url, _, _, _) Nothing = Just (anchor ! [href src_base_url] << "Source")@@ -167,20 +220,18 @@ 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 ! [theclass "no-frame"] << [+ body << [ divPackageHeader << [- unordList (catMaybes [- srcButton maybe_source_url iface,- wikiButton maybe_wiki_url (ifaceMod <$> iface),- contentsButton maybe_contents_url,- indexButton maybe_index_url])- ! [theclass "links", identifier "page-menu"],- nonEmptySectionName << doctitle+ nonEmptySectionName << doctitle,+ ulist ! [theclass "links", identifier "page-menu"]+ << catMaybes (quickJumpButtonLi withQuickjump : otherButtonLis) ], divContent << pageContent, divFooter << paragraph << (@@ -189,7 +240,13 @@ (" 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 =@@ -210,10 +267,7 @@ ("Language", lg) ] ++ extsForm where- lg inf = case hmi_language inf of- Nothing -> Nothing- Just Haskell98 -> Just "Haskell98"- Just Haskell2010 -> Just "Haskell2010"+ lg inf = fmap show (hmi_language inf) multilineRow :: String -> [String] -> HtmlTable multilineRow title xs = (th ! [valign "top"]) << title <-> td << (toLines xs)@@ -246,7 +300,7 @@ ppHtmlContents- :: DynFlags+ :: UnitState -> FilePath -> String -> Maybe String@@ -255,82 +309,244 @@ -> Maybe String -> SourceURLs -> WikiURLs- -> [InstalledInterface] -> Bool -> Maybe (MDoc GHC.RdrName)+ -> Bool -- ^ With Quick Jump?+ -> [PackageInterfaces] -> Bool -> Maybe (MDoc GHC.RdrName) -> Bool+ -> Maybe Package -- ^ Current package -> Qualification -- ^ How to qualify names -> IO ()-ppHtmlContents dflags odir doctitle _maybe_package+ppHtmlContents state odir doctitle _maybe_package themes mathjax_url maybe_index_url- maybe_source_url maybe_wiki_url ifaces showPkgs prologue debug qual = do- let tree = mkModuleTree dflags showPkgs- [(instMod iface, toInstalledDescription iface) | iface <- ifaces]+ 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 Nothing themes mathjax_url ++++ headHtml doctitle themes mathjax_url Nothing +++ bodyHtml doctitle Nothing maybe_source_url maybe_wiki_url- Nothing maybe_index_url << [- ppPrologue qual doctitle prologue,- ppModuleTree qual tree+ Nothing maybe_index_url withQuickjump << [+ ppPrologue pkg qual doctitle prologue,+ ppSignatureTrees pkg qual sig_trees,+ ppModuleTrees pkg qual trees ] createDirectoryIfMissing True odir- writeFile (joinPath [odir, contentsHtmlFile]) (renderToString debug html)+ 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 :: Qualification -> String -> Maybe (MDoc GHC.RdrName) -> Html-ppPrologue _ _ Nothing = noHtml-ppPrologue qual title (Just doc) =- divDescription << (h1 << title +++ docElement thediv (rdrDocToHtml qual doc))+ppPrologue :: Maybe Package -> Qualification -> String -> Maybe (MDoc GHC.RdrName) -> Html+ppPrologue _ _ _ Nothing = noHtml+ppPrologue pkg qual title (Just doc) =+ divDescription << (h1 << title +++ docElement thediv (rdrDocToHtml pkg qual doc)) +ppSignatureTrees :: Maybe Package -> Qualification -> [(PackageInfo, [ModuleTree])] -> Html+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+ ]) -ppModuleTree :: Qualification -> [ModuleTree] -> Html-ppModuleTree qual ts =- divModuleList << (sectionName << "Modules" +++ mkNodeList qual [] "n" ts)+ppSignatureTree :: Maybe Package -> Qualification -> String -> PackageInfo -> [ModuleTree] -> Html+ppSignatureTree _ _ _ _ [] = mempty+ppSignatureTree pkg qual p info ts =+ divModuleList << (sectionName << ppPackageInfo info +++ mkNodeList pkg qual [] p ts) +ppModuleTrees :: Maybe Package -> Qualification -> [(PackageInfo, [ModuleTree])] -> Html+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+ ]) -mkNodeList :: Qualification -> [String] -> String -> [ModuleTree] -> Html-mkNodeList qual ss p ts = case ts of+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 qual ss) ps ts)+ _ -> unordList (zipWith (mkNode pkg qual ss) ps ts) where ps = [ p ++ '.' : show i | i <- [(1::Int)..]] -mkNode :: Qualification -> [String] -> String -> ModuleTree -> Html-mkNode qual ss p (Node s leaf pkg srcPkg short ts) =+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- (_:_, False) -> collapseControl p True "module"+ (_:_, Nothing) -> collapseControl p "module" (_, _ ) -> [theclass "module"] cBtn = case (ts, leaf) of- (_:_, True) -> thespan ! collapseControl p True "" << spaceHtml+ (_:_, 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 +++- if leaf- then ppModule (mkModule (stringToUnitId (fromMaybe "" pkg))- (mkModuleName mdl))- else toHtml s+ case leaf of+ Just m -> ppModule m+ Nothing -> toHtml s ) - mdl = intercalate "." (reverse (s:ss))-- shortDescr = maybe noHtml (origDocToHtml qual) short+ shortDescr = maybe noHtml (origDocToHtml pkg qual) short htmlPkg = maybe noHtml (thespan ! [theclass "package"] <<) srcPkg - subtree = mkNodeList qual (s:ss) p ts ! collapseSection p True ""--+ subtree =+ 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 +instance ToJSON JsonIndexEntry where+ toJSON JsonIndexEntry+ { jieHtmlFragment+ , jieName+ , jieModule+ , jieLink } =+ Object+ [ "display_html" .= String jieHtmlFragment+ , "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 ()+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+ 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+ IO.withBinaryFile (joinPath [odir, indexJsonFile]) IO.WriteMode $ \h ->+ Builder.hPutBuilder+ h (encodeToBuilder (encodeIndexes (concat installedIndexes)))+ where+ encodeIndexes :: [JsonIndexEntry] -> Value+ encodeIndexes installedIndexes =+ toJSON+ (concatMap fromInterface ifaces+ ++ installedIndexes)++ fromInterface :: Interface -> [JsonIndexEntry]+ fromInterface iface =+ mkIndex mdl qual `mapMaybe` ifaceRnExportItems iface+ where+ aliases = ifaceModuleAliases iface+ qual = makeModuleQual qual_opt aliases 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))+ }+ | otherwise = Nothing+ where+ names = exportName item ++ exportSubs item++ exportSubs :: ExportItem DocNameI -> [IdP DocNameI]+ 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 _ = []++ nameLink :: NamedThing name => Module -> name -> String+ nameLink mdl = moduleNameUrl' (moduleName mdl) . nameOccName . getName++ links_info = (maybe_source_url, maybe_wiki_url)++ -- update link using relative path to output directory+ fixLink :: FilePath+ -> JsonIndexEntry -> JsonIndexEntry+ fixLink ifaceFile jie =+ jie { jieLink = makeRelative odir (takeDirectory ifaceFile)+ FilePath.</> jieLink jie }+ ppHtmlIndex :: FilePath -> String -> Maybe String@@ -339,11 +555,12 @@ -> 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 ifaces debug = do+ 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) @@ -353,16 +570,16 @@ 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- writeFile (joinPath [odir, subIndexHtmlFile merged_name]) (renderToString debug mergedhtml)+ writeUtf8File (joinPath [odir, subIndexHtmlFile merged_name]) (renderToString debug mergedhtml) - writeFile (joinPath [odir, indexHtmlFile]) (renderToString debug html)+ writeUtf8File (joinPath [odir, indexHtmlFile]) (renderToString debug html) where indexPage showLetters ch items =- headHtml (doctitle ++ " (" ++ indexName ch ++ ")") Nothing themes maybe_mathjax_url ++++ headHtml (doctitle ++ " (" ++ indexName ch ++ ")") themes maybe_mathjax_url Nothing +++ bodyHtml doctitle Nothing maybe_source_url maybe_wiki_url- maybe_contents_url Nothing << [+ maybe_contents_url Nothing withQuickjump << [ if showLetters then indexInitialLetterLinks else noHtml, if null items then noHtml else divIndex << [sectionName << indexName ch, buildIndex items]@@ -396,7 +613,7 @@ do_sub_index this_ix c = unless (null index_part) $- writeFile (joinPath [odir, subIndexHtmlFile [c]]) (renderToString debug html)+ 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]@@ -411,14 +628,34 @@ -- 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 = Map.fromListWith (flip (Map.unionWith (++)))- (concatMap getIfaceIndex ifaces)+ 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 =- [ (getOccString name- , Map.fromList [(name, [(mdl, name `Set.member` visible)])])- | name <- instExports 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) @@ -459,46 +696,49 @@ ppHtmlModule :: FilePath -> String -> Themes- -> Maybe String -> SourceURLs -> WikiURLs- -> Maybe String -> Maybe String -> Bool -> QualOption+ -> 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_contents_url maybe_index_url unicode qual debug iface = do+ 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 aliases = ifaceModuleAliases iface mdl_str = moduleString mdl+ 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 real_qual = makeModuleQual qual aliases mdl html =- headHtml mdl_str (Just $ "mini_" ++ moduleHtmlFile mdl) themes maybe_mathjax_url ++++ 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 << [- divModuleHeader << (moduleInfo iface +++ (sectionName << mdl_str)),- ifaceToHtml maybe_source_url maybe_wiki_url iface unicode real_qual+ 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- writeFile (joinPath [odir, moduleHtmlFile mdl]) (renderToString debug html)- ppHtmlModuleMiniSynopsis odir doctitle themes maybe_mathjax_url iface unicode real_qual debug+ writeUtf8File (joinPath [odir, moduleHtmlFile mdl]) (renderToString debug html) -ppHtmlModuleMiniSynopsis :: FilePath -> String -> Themes- -> Maybe String -> Interface -> Bool -> Qualification -> Bool -> IO ()-ppHtmlModuleMiniSynopsis odir _doctitle themes maybe_mathjax_url iface unicode qual debug = do- let mdl = ifaceMod iface- html =- headHtml (moduleString mdl) Nothing themes maybe_mathjax_url +++- miniBody <<- (divModuleHeader << sectionName << moduleString mdl +++- miniSynopsis mdl iface unicode qual)- createDirectoryIfMissing True odir- writeFile (joinPath [odir, "mini_" ++ moduleHtmlFile mdl]) (renderToString debug html)+signatureDocURL :: String+signatureDocURL = "https://wiki.haskell.org/Module_signature" -ifaceToHtml :: SourceURLs -> WikiURLs -> Interface -> Bool -> Qualification -> Html-ifaceToHtml maybe_source_url maybe_wiki_url iface unicode qual- = ppModuleContents qual exports (not . null $ ifaceRnOrphanInstances iface) ++++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)@@ -507,7 +747,17 @@ -- todo: if something has only sub-docs, or fn-args-docs, should -- it be measured here and thus prevent omitting the synopsis?- has_doc ExportDecl { expItemMbDoc = (Documentation mDoc mWarning, _) } = isJust mDoc || isJust mWarning+ has_doc+ ( ExportDecl+ ( RnExportD+ { rnExpDExpD =+ ExportD+ { expDMbDoc =+ ( Documentation mDoc mWarn, _ )+ }+ }+ )+ ) = isJust mDoc || isJust mWarn has_doc (ExportNoDecl _ _) = False has_doc (ExportModule _) = False has_doc _ = True@@ -516,17 +766,19 @@ description | isNoHtml doc = doc | otherwise = divDescription $ sectionName << "Description" +++ doc- where doc = docSection Nothing qual (ifaceRnDoc iface)+ where doc = docSection Nothing pkg qual (ifaceRnDoc iface) -- omit the synopsis if there are no documentation annotations at all synopsis | no_doc_at_all = noHtml | otherwise = divSynopsis $- paragraph ! collapseControl "syn" False "caption" << "Synopsis" +++- shortDeclList (- mapMaybe (processExport True linksInfo unicode qual) exports- ) ! (collapseSection "syn" False "" ++ collapseToggle "syn")+ 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").@@ -538,76 +790,40 @@ bdy = foldr (+++) noHtml $- mapMaybe (processExport False linksInfo unicode qual) exports+ mapMaybe (processExport False linksInfo unicode pkg qual) exports orphans =- ppOrphanInstances linksInfo (ifaceRnOrphanInstances iface) False unicode qual+ ppOrphanInstances linksInfo (ifaceRnOrphanInstances iface) False unicode pkg qual linksInfo = (maybe_source_url, maybe_wiki_url) -miniSynopsis :: Module -> Interface -> Bool -> Qualification -> Html-miniSynopsis mdl iface unicode qual =- divInterface << concatMap (processForMiniSynopsis mdl unicode qual) exports- where- exports = numberSectionHeadings (ifaceRnExportItems iface)---processForMiniSynopsis :: Module -> Bool -> Qualification -> ExportItem DocName- -> [Html]-processForMiniSynopsis mdl unicode qual ExportDecl { expItemDecl = L _loc decl0 } =- ((divTopDecl <<).(declElem <<)) <$> case decl0 of- TyClD d -> let b = ppTyClBinderWithVarsMini mdl d in case d of- (FamDecl decl) -> [ppTyFamHeader True False decl unicode qual]- (DataDecl{}) -> [keyword "data" <+> b]- (SynDecl{}) -> [keyword "type" <+> b]- (ClassDecl {}) -> [keyword "class" <+> b]- SigD (TypeSig lnames _) ->- map (ppNameMini Prefix mdl . nameOccName . getName . unLoc) lnames- _ -> []-processForMiniSynopsis _ _ qual (ExportGroup lvl _id txt) =- [groupTag lvl << docToHtml Nothing qual (mkMeta txt)]-processForMiniSynopsis _ _ _ _ = []---ppNameMini :: Notation -> Module -> OccName -> Html-ppNameMini notation mdl nm =- anchor ! [ href (moduleNameUrl mdl nm)- , target mainFrameName ]- << ppBinder' notation nm---ppTyClBinderWithVarsMini :: Module -> TyClDecl DocName -> Html-ppTyClBinderWithVarsMini mdl decl =- let n = tcdName decl- ns = tyvarNames $ tcdTyVars decl -- it's safe to use tcdTyVars, see code above- in ppTypeApp n [] ns (\is_infix -> ppNameMini is_infix mdl . nameOccName . getName) ppTyName--ppModuleContents :: Qualification- -> [ExportItem DocName]- -> Bool -- ^ Orphans sections+ppModuleContents :: Maybe Package -- ^ This package+ -> Qualification+ -> [ExportItem DocNameI]+ -> Bool -- ^ Orphans sections -> Html-ppModuleContents qual exports orphan+ppModuleContents pkg qual exports orphan | null sections && not orphan = noHtml | otherwise = contentsDiv where- contentsDiv = divTableOfContents << (- sectionName << "Contents" +++- unordList (sections ++ orphanSection))+ 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 DocName] -> ([Html],[ExportItem DocName])+ 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) qual (mkMeta doc) +++ mk_subsections ssecs+ << 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@@ -617,32 +833,55 @@ -- we need to assign a unique id to each section heading so we can hyperlink -- them from the contents:-numberSectionHeadings :: [ExportItem DocName] -> [ExportItem DocName]+numberSectionHeadings :: [ExportItem DocNameI] -> [ExportItem DocNameI] numberSectionHeadings = go 1- where go :: Int -> [ExportItem DocName] -> [ExportItem DocName]+ where go :: Int -> [ExportItem DocNameI] -> [ExportItem DocNameI] go _ [] = [] go n (ExportGroup lev _ doc : es)- = ExportGroup lev (show n) doc : go (n+1) 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 -> Qualification- -> ExportItem DocName -> Maybe Html-processExport _ _ _ _ ExportDecl { expItemDecl = L _ (InstD _) } = Nothing -- Hide empty instances-processExport summary _ _ qual (ExportGroup lev id0 doc)- = nothingIf summary $ groupHeading lev id0 << docToHtml (Just id0) qual (mkMeta doc)-processExport summary links unicode qual (ExportDecl decl doc subdocs insts fixities splice)- = processDecl summary $ ppDecl summary links decl doc insts fixities subdocs splice unicode qual-processExport summary _ _ qual (ExportNoDecl y [])+processExport :: Bool -> LinksInfo -> Bool -> Maybe Package -> Qualification+ -> ExportItem DocNameI -> Maybe Html+processExport _ _ _ _ _+ ( ExportDecl+ ( RnExportD+ { rnExpDExpD =+ ExportD+ { expDDecl = L _ (InstD {})+ }+ }+ )+ )+ = Nothing -- Hide empty instances+processExport summary links unicode pkg qual+ ( ExportDecl+ ( RnExportD+ { 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)+processExport summary _ _ _ qual (ExportNoDecl y subs) = processDeclOneLiner summary $ ppDocName qual Prefix True y +++ parenList (map (ppDocName qual Prefix True) subs)-processExport summary _ _ qual (ExportDoc doc)- = nothingIf summary $ docSection_ Nothing qual doc-processExport summary _ _ _ (ExportModule mdl)+processExport summary _ _ pkg qual (ExportDoc doc)+ = nothingIf summary $ docSection_ Nothing pkg qual doc+processExport summary _ _ _ _ (ExportModule mdl) = processDeclOneLiner summary $ toHtml "module" <+> ppModule mdl @@ -664,7 +903,8 @@ processDeclOneLiner False = Just . divTopDecl . declElem groupHeading :: Int -> String -> Html -> Html-groupHeading lev id0 = groupTag lev ! [identifier (groupId id0)]+groupHeading lev id0 = linkedAnchor grpId . groupTag lev ! [identifier grpId]+ where grpId = groupId id0 groupTag :: Int -> Html -> Html groupTag lev
src/Haddock/Backends/Xhtml/Decl.hs view
@@ -1,1051 +1,1312 @@ {-# LANGUAGE TransformListComp #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE Rank2Types #-}--------------------------------------------------------------------------------- |--- Module : Haddock.Backends.Html.Decl--- Copyright : (c) Simon Marlow 2003-2006,--- David Waern 2006-2009,--- Mark Lentczner 2010--- License : BSD-like------ Maintainer : haddock@projects.haskell.org--- Stability : experimental--- Portability : portable-------------------------------------------------------------------------------module Haddock.Backends.Xhtml.Decl (- ppDecl,-- ppTyName, ppTyFamHeader, ppTypeApp, ppOrphanInstances,- tyvarNames-) 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.GhcUtils-import Haddock.Types-import Haddock.Doc (combineDocumentation)--import Data.List ( intersperse, sort )-import qualified Data.Map as Map-import Data.Maybe-import Text.XHtml hiding ( name, title, p, quote )--import GHC-import GHC.Exts-import Name-import BooleanFormula-import RdrName ( rdrNameOcc )--ppDecl :: Bool -> LinksInfo -> LHsDecl DocName- -> DocForDecl DocName -> [DocInstance DocName] -> [(DocName, Fixity)]- -> [(DocName, DocForDecl DocName)] -> Splice -> Unicode -> Qualification -> Html-ppDecl summ links (L loc decl) (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 splice unicode qual- TyClD d@(SynDecl {}) -> ppTySyn summ links fixities loc (mbDoc, fnArgsDoc) d splice unicode qual- 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 lname ty) -> ppLPatSig summ links loc (mbDoc, fnArgsDoc) lname- ty fixities splice unicode qual- ForD d -> ppFor summ links loc (mbDoc, fnArgsDoc) d fixities splice unicode qual- InstD _ -> noHtml- _ -> error "declaration not supported by ppDecl"---ppLFunSig :: Bool -> LinksInfo -> SrcSpan -> DocForDecl DocName ->- [Located DocName] -> LHsType DocName -> [(DocName, Fixity)] ->- Splice -> Unicode -> Qualification -> Html-ppLFunSig summary links loc doc lnames lty fixities splice unicode qual =- ppFunSig summary links loc doc (map unLoc lnames) lty fixities- splice unicode qual--ppFunSig :: Bool -> LinksInfo -> SrcSpan -> DocForDecl DocName ->- [DocName] -> LHsType DocName -> [(DocName, Fixity)] ->- Splice -> Unicode -> Qualification -> Html-ppFunSig summary links loc doc docnames typ fixities splice unicode qual =- ppSigLike summary links loc mempty doc docnames fixities (unLoc typ, pp_typ)- splice unicode qual- where- pp_typ = ppLType unicode qual typ--ppLPatSig :: Bool -> LinksInfo -> SrcSpan -> DocForDecl DocName ->- Located DocName -> LHsSigType DocName ->- [(DocName, Fixity)] ->- Splice -> Unicode -> Qualification -> Html-ppLPatSig summary links loc (doc, _argDocs) (L _ name) typ fixities splice unicode qual- | summary = pref1- | otherwise = topDeclElem links loc splice [name] (pref1 <+> ppFixities fixities qual)- +++ docSection Nothing qual doc- where- pref1 = hsep [ keyword "pattern"- , ppBinder summary occname- , dcolon unicode- , ppLType unicode qual (hsSigType typ)- ]-- occname = nameOccName . getName $ name--ppSigLike :: Bool -> LinksInfo -> SrcSpan -> Html -> DocForDecl DocName ->- [DocName] -> [(DocName, Fixity)] -> (HsType DocName, Html) ->- Splice -> Unicode -> Qualification -> Html-ppSigLike summary links loc leader doc docnames fixities (typ, pp_typ)- splice unicode qual =- ppTypeOrFunSig summary links loc docnames typ doc- ( addFixities $ leader <+> ppTypeSig summary occnames pp_typ unicode- , addFixities . concatHtml . punctuate comma $ map (ppBinder False) occnames- , dcolon unicode- )- splice unicode qual- where- occnames = map (nameOccName . getName) docnames- addFixities html- | summary = html- | otherwise = html <+> ppFixities fixities qual---ppTypeOrFunSig :: Bool -> LinksInfo -> SrcSpan -> [DocName] -> HsType DocName- -> DocForDecl DocName -> (Html, Html, Html)- -> Splice -> Unicode -> Qualification -> Html-ppTypeOrFunSig summary links loc docnames typ (doc, argDocs) (pref1, pref2, sep) splice unicode qual- | 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- where- curName = getName <$> listToMaybe docnames- argDoc n = Map.lookup n argDocs-- do_largs n leader (L _ t) = do_args n leader t-- do_args :: Int -> Html -> HsType DocName -> [SubDecl]- do_args n leader (HsForAllTy tvs ltype)- = do_largs n leader' ltype- where- leader' = leader <+> ppForAll tvs unicode qual-- do_args n leader (HsQualTy lctxt ltype)- | null (unLoc lctxt)- = do_largs n leader ltype- | otherwise- = (leader <+> ppLContextNoArrow lctxt unicode qual, Nothing, [])- : do_largs n (darrow unicode) ltype-- do_args n leader (HsFunTy lt r)- = (leader <+> ppLFunLhType unicode qual lt, argDoc n, [])- : do_largs (n+1) (arrow unicode) r- do_args n leader t- = [(leader <+> ppType unicode qual t, argDoc n, [])]--ppForAll :: [LHsTyVarBndr DocName] -> Unicode -> Qualification -> Html-ppForAll tvs unicode qual =- case [ppKTv n k | L _ (KindedTyVar (L _ n) k) <- tvs] of- [] -> noHtml- ts -> forallSymbol unicode <+> hsep ts +++ dot- where ppKTv n k = parens $- ppTyName (getName n) <+> dcolon unicode <+> ppLKind unicode qual k--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)-- 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 ]-- rightEdge = thespan ! [theclass "rightedge"] << noHtml----- | Pretty-print type variables.-ppTyVars :: [LHsTyVarBndr DocName] -> [Html]-ppTyVars tvs = map (ppTyName . getName . hsLTyVarName) tvs--tyvarNames :: LHsQTyVars DocName -> [Name]-tyvarNames = map (getName . hsLTyVarName) . hsQTvExplicit---ppFor :: Bool -> LinksInfo -> SrcSpan -> DocForDecl DocName- -> ForeignDecl DocName -> [(DocName, Fixity)]- -> Splice -> Unicode -> Qualification -> Html-ppFor summary links loc doc (ForeignImport (L _ name) typ _ _) fixities- splice unicode qual- = ppFunSig summary links loc doc [name] (hsSigType typ) fixities splice unicode qual-ppFor _ _ _ _ _ _ _ _ _ = error "ppFor"----- we skip type patterns for now-ppTySyn :: Bool -> LinksInfo -> [(DocName, Fixity)] -> SrcSpan- -> DocForDecl DocName -> TyClDecl DocName- -> Splice -> Unicode -> Qualification -> Html-ppTySyn summary links fixities loc doc (SynDecl { tcdLName = L _ name, tcdTyVars = ltyvars- , tcdRhs = ltype })- splice unicode qual- = ppTypeOrFunSig summary links loc [name] (unLoc ltype) doc- (full <+> fixs, hdr <+> fixs, spaceHtml +++ equals)- splice unicode qual- where- hdr = hsep ([keyword "type", ppBinder summary occ]- ++ ppTyVars (hsQTvExplicit ltyvars))- full = hdr <+> equals <+> ppLType unicode qual ltype- 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---ppTyName :: Name -> Html-ppTyName = ppName Prefix---ppSimpleSig :: LinksInfo -> Splice -> Unicode -> Qualification -> SrcSpan- -> [DocName] -> HsType DocName- -> Html-ppSimpleSig links splice unicode qual loc names typ =- topDeclElem' names $ ppTypeSig True occNames ppTyp unicode- where- topDeclElem' = topDeclElem links loc splice- ppTyp = ppType unicode qual typ- occNames = map getOccName names-------------------------------------------------------------------------------------- * Type families------------------------------------------------------------------------------------ppFamilyInfo :: Bool -> FamilyInfo DocName -> Html-ppFamilyInfo assoc OpenTypeFamily- | assoc = keyword "type"- | otherwise = keyword "type family"-ppFamilyInfo assoc DataFamily- | assoc = keyword "data"- | otherwise = keyword "data family"-ppFamilyInfo _ (ClosedTypeFamily _) = keyword "type family"---ppTyFamHeader :: Bool -> Bool -> FamilyDecl DocName- -> Unicode -> Qualification -> Html-ppTyFamHeader summary associated d@(FamilyDecl { fdInfo = info- , fdResultSig = L _ result- , fdInjectivityAnn = injectivity })- unicode qual =- (case info of- OpenTypeFamily- | associated -> keyword "type"- | otherwise -> keyword "type family"- DataFamily- | associated -> keyword "data"- | otherwise -> keyword "data family"- ClosedTypeFamily _- -> keyword "type family"- ) <+>-- ppFamDeclBinderWithVars summary unicode qual d <+>- ppResultSig result unicode qual <+>-- (case injectivity of- Nothing -> noHtml- Just (L _ injectivityAnn) -> ppInjectivityAnn unicode qual injectivityAnn- ) <+>-- (case info of- ClosedTypeFamily _ -> keyword "where ..."- _ -> mempty- )--ppResultSig :: FamilyResultSig DocName -> 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--ppPseudoFamilyHeader :: Unicode -> Qualification -> PseudoFamilyDecl DocName- -> Html-ppPseudoFamilyHeader unicode qual (PseudoFamilyDecl { .. }) =- ppFamilyInfo True pfdInfo <+>- ppAppNameTypes (unLoc pfdLName) [] (map unLoc pfdTyVars) unicode qual <+>- ppResultSig (unLoc pfdKindSig) unicode qual--ppInjectivityAnn :: Bool -> Qualification -> InjectivityAnn DocName -> Html-ppInjectivityAnn unicode qual (InjectivityAnn lhs rhs) =- char '|' <+> ppLDocName qual Raw lhs <+> arrow unicode <+>- hsep (map (ppLDocName qual Raw) rhs)---ppTyFam :: Bool -> Bool -> LinksInfo -> [DocInstance DocName] ->- [(DocName, Fixity)] -> SrcSpan -> Documentation DocName ->- FamilyDecl DocName -> Splice -> Unicode -> Qualification -> Html-ppTyFam summary associated links instances fixities loc doc decl splice unicode qual-- | summary = ppTyFamHeader True associated decl unicode qual- | otherwise = header_ +++ docSection Nothing qual doc +++ instancesBit-- where- docname = unLoc $ fdLName decl-- header_ = topDeclElem links loc splice [docname] $- ppTyFamHeader summary associated decl unicode qual <+> ppFixities fixities qual-- instancesBit- | FamilyDecl { fdInfo = ClosedTypeFamily mb_eqns } <- decl- , not summary- = subEquations qual $ map (ppTyFamEqn . unLoc) $ fromMaybe [] mb_eqns-- | otherwise- = ppInstances links (OriginFamily docname) instances splice unicode qual-- -- Individual equation of a closed type family- ppTyFamEqn TyFamEqn { tfe_tycon = n, tfe_rhs = rhs- , tfe_pats = HsIB { hsib_body = ts }}- = ( ppAppNameTypes (unLoc n) [] (map unLoc ts) unicode qual- <+> equals <+> ppType unicode qual (unLoc rhs)- , Nothing, [] )----ppPseudoFamilyDecl :: LinksInfo -> Splice -> Unicode -> Qualification- -> PseudoFamilyDecl DocName- -> Html-ppPseudoFamilyDecl links splice unicode qual- decl@(PseudoFamilyDecl { pfdLName = L loc name, .. }) =- wrapper $ ppPseudoFamilyHeader unicode qual decl- where- wrapper = topDeclElem links loc splice [name]-------------------------------------------------------------------------------------- * Associated Types------------------------------------------------------------------------------------ppAssocType :: Bool -> LinksInfo -> DocForDecl DocName -> LFamilyDecl DocName- -> [(DocName, Fixity)] -> Splice -> Unicode -> Qualification -> Html-ppAssocType summ links doc (L loc decl) fixities splice unicode qual =- ppTyFam summ True links [] fixities loc (fst doc) decl splice unicode qual-------------------------------------------------------------------------------------- * TyClDecl helpers------------------------------------------------------------------------------------- | Print a type family and its variables-ppFamDeclBinderWithVars :: Bool -> Unicode -> Qualification -> FamilyDecl DocName -> Html-ppFamDeclBinderWithVars summ unicode qual (FamilyDecl { fdLName = lname, fdTyVars = tvs }) =- ppAppDocNameTyVarBndrs summ unicode qual (unLoc lname) (map unLoc $ hsq_explicit tvs)---- | Print a newtype / data binder and its variables-ppDataBinderWithVars :: Bool -> TyClDecl DocName -> Html-ppDataBinderWithVars summ decl =- ppAppDocNameNames summ (tcdName decl) (tyvarNames $ tcdTyVars decl)------------------------------------------------------------------------------------- * Type applications-----------------------------------------------------------------------------------ppAppDocNameTyVarBndrs :: Bool -> Unicode -> Qualification -> DocName -> [HsTyVarBndr DocName] -> Html-ppAppDocNameTyVarBndrs summ unicode qual n vs =- ppTypeApp n [] vs ppDN (ppHsTyVarBndr unicode qual)- where- ppDN notation = ppBinderFixity notation summ . nameOccName . getName- ppBinderFixity Infix = ppBinderInfix- ppBinderFixity _ = ppBinder---- | Print an application of a 'DocName' and two lists of 'HsTypes' (kinds, types)-ppAppNameTypes :: DocName -> [HsType DocName] -> [HsType DocName]- -> Unicode -> Qualification -> Html-ppAppNameTypes n ks ts unicode qual =- ppTypeApp n ks ts (\p -> ppDocName qual p True) (ppParendType unicode qual)----- | Print an application of a 'DocName' and a list of 'Names'-ppAppDocNameNames :: Bool -> DocName -> [Name] -> Html-ppAppDocNameNames summ n ns =- ppTypeApp n [] ns ppDN ppTyName- where- ppDN notation = ppBinderFixity notation summ . nameOccName . getName- ppBinderFixity Infix = ppBinderInfix- ppBinderFixity _ = ppBinder---- | General printing of type applications-ppTypeApp :: DocName -> [a] -> [a] -> (Notation -> DocName -> Html) -> (a -> Html) -> Html-ppTypeApp n [] (t1:t2:rest) ppDN ppT- | operator, not . null $ rest = parens opApp <+> hsep (map ppT rest)- | operator = opApp- where- operator = isNameSym . getName $ n- opApp = ppT t1 <+> ppDN Infix n <+> ppT t2--ppTypeApp n ks ts ppDN ppT = ppDN Prefix n <+> hsep (map ppT $ ks ++ ts)------------------------------------------------------------------------------------- * Contexts-----------------------------------------------------------------------------------ppLContext, ppLContextNoArrow :: Located (HsContext DocName) -> Unicode- -> Qualification -> Html-ppLContext = ppContext . unLoc-ppLContextNoArrow = ppContextNoArrow . unLoc--ppContextNoArrow :: HsContext DocName -> Unicode -> Qualification -> Html-ppContextNoArrow cxt unicode qual = fromMaybe noHtml $- ppContextNoLocsMaybe (map unLoc cxt) unicode qual---ppContextNoLocs :: [HsType DocName] -> Unicode -> Qualification -> Html-ppContextNoLocs cxt unicode qual = maybe noHtml (<+> darrow unicode) $- ppContextNoLocsMaybe cxt unicode qual---ppContextNoLocsMaybe :: [HsType DocName] -> Unicode -> Qualification -> Maybe Html-ppContextNoLocsMaybe [] _ _ = Nothing-ppContextNoLocsMaybe cxt unicode qual = Just $ ppHsContext cxt unicode qual--ppContext :: HsContext DocName -> Unicode -> Qualification -> Html-ppContext cxt unicode qual = ppContextNoLocs (map unLoc cxt) unicode qual---ppHsContext :: [HsType DocName] -> Unicode -> Qualification-> Html-ppHsContext [] _ _ = noHtml-ppHsContext [p] unicode qual = ppCtxType unicode qual p-ppHsContext cxt unicode qual = parenList (map (ppType unicode qual) cxt)------------------------------------------------------------------------------------- * Class declarations-----------------------------------------------------------------------------------ppClassHdr :: Bool -> Located [LHsType DocName] -> DocName- -> LHsQTyVars DocName -> [Located ([Located DocName], [Located DocName])]- -> Unicode -> Qualification -> Html-ppClassHdr summ lctxt n tvs fds unicode qual =- keyword "class"- <+> (if not . null . unLoc $ lctxt then ppLContext lctxt unicode qual else noHtml)- <+> ppAppDocNameNames summ n (tyvarNames tvs)- <+> ppFds fds unicode qual---ppFds :: [Located ([Located DocName], [Located DocName])] -> Unicode -> Qualification -> Html-ppFds fds unicode qual =- if null fds then noHtml else- char '|' <+> hsep (punctuate comma (map (fundep . unLoc) fds))- where- fundep (vars1,vars2) = ppVars vars1 <+> arrow unicode <+> ppVars vars2- ppVars = hsep . map ((ppDocName qual Prefix True) . unLoc)--ppShortClassDecl :: Bool -> LinksInfo -> TyClDecl DocName -> SrcSpan- -> [(DocName, DocForDecl DocName)]- -> Splice -> Unicode -> Qualification -> Html-ppShortClassDecl summary links (ClassDecl { tcdCtxt = lctxt, tcdLName = lname, tcdTyVars = tvs- , tcdFDs = fds, tcdSigs = sigs, tcdATs = ats }) loc- subdocs splice unicode 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 qual | at <- ats- , let doc = lookupAnySubdoc (unL $ fdLName $ unL at) subdocs ] ++-- -- ToDo: add associated type defaults-- [ ppFunSig summary links loc doc names (hsSigWcType typ)- [] splice unicode qual- | L _ (TypeSig 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 DocName] -> [(DocName, Fixity)]- -> SrcSpan -> Documentation DocName- -> [(DocName, DocForDecl DocName)] -> TyClDecl DocName- -> Splice -> Unicode -> Qualification -> Html-ppClassDecl summary links instances fixities loc d subdocs- decl@(ClassDecl { tcdCtxt = lctxt, tcdLName = lname, tcdTyVars = ltyvars- , tcdFDs = lfds, tcdSigs = lsigs, tcdATs = ats })- splice unicode qual- | summary = ppShortClassDecl summary links decl loc subdocs splice unicode qual- | otherwise = classheader +++ docSection Nothing qual d- +++ minimalBit +++ atBit +++ methodBit +++ instancesBit- where- 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 = tcdName decl-- hdr = ppClassHdr summary lctxt (unLoc lname) ltyvars lfds-- -- ToDo: add assocatied typ defaults- atBit = subAssociatedTypes [ ppAssocType summary links doc at subfixs splice unicode qual- | at <- ats- , let n = unL . fdLName $ unL at- doc = lookupAnySubdoc (unL $ fdLName $ unL at) subdocs- subfixs = [ f | f@(n',_) <- fixities, n == n' ] ]-- methodBit = subMethods [ ppFunSig summary links loc doc names (hsSigType typ)- subfixs splice unicode qual- | L _ (ClassOpSig _ lnames typ) <- lsigs- , let doc = lookupAnySubdoc (head names) subdocs- subfixs = [ f | n <- names- , f@(n',_) <- fixities- , n == n' ]- 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?-- 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 | TypeSig ns _ <- sigs, L _ n <- ns]- -> noHtml-- -- Minimal complete definition = the only shown method- Var (L _ n) : _ | [getName n] ==- [getName n' | L _ (TypeSig ns _) <- lsigs, 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)-- instancesBit = ppInstances links (OriginClass nm) instances- splice unicode qual--ppClassDecl _ _ _ _ _ _ _ _ _ _ _ = error "declaration type not supported by ppShortClassDecl"---ppInstances :: LinksInfo- -> InstOrigin DocName -> [DocInstance DocName]- -> Splice -> Unicode -> Qualification- -> Html-ppInstances links origin instances splice unicode qual- = subInstances qual instName links True (zipWith instDecl [1..] instances)- -- force Splice = True to use line URLs- where- instName = getOccString origin- instDecl :: Int -> DocInstance DocName -> (SubDecl,Located DocName)- instDecl no (inst, mdoc, loc) =- ((ppInstHead links splice unicode qual mdoc origin False no inst), loc)---ppOrphanInstances :: LinksInfo- -> [DocInstance DocName]- -> Splice -> Unicode -> Qualification- -> Html-ppOrphanInstances links instances splice unicode qual- = subOrphanInstances qual links True (zipWith instDecl [1..] instances)- where- instOrigin :: InstHead name -> InstOrigin name- instOrigin inst = OriginClass (ihdClsName inst)-- instDecl :: Int -> DocInstance DocName -> (SubDecl,Located DocName)- instDecl no (inst, mdoc, loc) =- ((ppInstHead links splice unicode qual mdoc (instOrigin inst) True no inst), loc)---ppInstHead :: LinksInfo -> Splice -> Unicode -> Qualification- -> Maybe (MDoc DocName)- -> InstOrigin DocName- -> Bool -- ^ Is instance orphan- -> Int -- ^ Normal- -> InstHead DocName- -> SubDecl-ppInstHead links splice unicode qual mdoc origin orphan no ihd@(InstHead {..}) =- case ihdInstType of- ClassInst { .. } ->- ( subInstHead iid $ ppContextNoLocs clsiCtx unicode qual <+> typ- , mdoc- , [subInstDetails iid ats sigs]- )- where- sigs = ppInstanceSigs links splice unicode qual clsiSigs- ats = ppInstanceAssocTys links splice unicode qual clsiAssocTys- TypeInst rhs ->- ( subInstHead iid ptype- , mdoc- , [subFamInstDetails iid prhs]- )- where- ptype = keyword "type" <+> typ- prhs = ptype <+> maybe noHtml- (\t -> equals <+> ppType unicode qual t) rhs- DataInst dd ->- ( subInstHead iid pdata- , mdoc- , [subFamInstDetails iid pdecl])- where- pdata = keyword "data" <+> typ- pdecl = pdata <+> ppShortDataDecl False True dd unicode qual- where- iid = instanceId origin no orphan ihd- typ = ppAppNameTypes ihdClsName ihdKinds ihdTypes unicode qual---ppInstanceAssocTys :: LinksInfo -> Splice -> Unicode -> Qualification- -> [PseudoFamilyDecl DocName]- -> [Html]-ppInstanceAssocTys links splice unicode qual =- map ppFamilyDecl'- where- ppFamilyDecl' = ppPseudoFamilyDecl links splice unicode qual---ppInstanceSigs :: LinksInfo -> Splice -> Unicode -> Qualification- -> [Sig DocName]- -> [Html]-ppInstanceSigs links splice unicode qual sigs = do- TypeSig lnames typ <- sigs- let names = map unLoc lnames- L loc rtyp = get_type typ- return $ ppSimpleSig links splice unicode qual loc names rtyp- where- get_type = hswc_body . hsib_body---lookupAnySubdoc :: Eq id1 => id1 -> [(id1, DocForDecl id2)] -> DocForDecl id2-lookupAnySubdoc n = fromMaybe noDocForDecl . lookup n---instanceId :: InstOrigin DocName -> Int -> Bool -> InstHead DocName -> String-instanceId origin no orphan ihd = concat $- [ "o:" | orphan ] ++- [ qual origin- , ":" ++ getOccString origin- , ":" ++ (occNameString . getOccName . ihdClsName) ihd- , ":" ++ show no- ]- where- qual (OriginClass _) = "ic"- qual (OriginData _) = "id"- qual (OriginFamily _) = "if"------------------------------------------------------------------------------------- * Data & newtype declarations------------------------------------------------------------------------------------- TODO: print contexts-ppShortDataDecl :: Bool -> Bool -> TyClDecl DocName -> Unicode -> Qualification -> Html-ppShortDataDecl summary dataInst dataDecl unicode qual-- | [] <- cons = dataHeader-- | [lcon] <- cons, isH98,- (cHead,cBody,cFoot) <- ppShortConstrParts summary dataInst (unLoc lcon) unicode qual- = (dataHeader <+> equals <+> cHead) +++ cBody +++ cFoot-- | isH98 = dataHeader- +++ shortSubDecls dataInst (zipWith doConstr ('=':repeat '|') cons)-- | otherwise = (dataHeader <+> keyword "where")- +++ shortSubDecls dataInst (map doGADTConstr cons)-- where- dataHeader- | 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 = case unLoc (head cons) of- ConDeclH98 {} -> True- ConDeclGADT{} -> False---ppDataDecl :: Bool -> LinksInfo -> [DocInstance DocName] -> [(DocName, Fixity)] ->- [(DocName, DocForDecl DocName)] ->- SrcSpan -> Documentation DocName -> TyClDecl DocName ->- Splice -> Unicode -> Qualification -> Html-ppDataDecl summary links instances fixities subdocs loc doc dataDecl- splice unicode qual-- | summary = ppShortDataDecl summary False dataDecl unicode qual- | otherwise = header_ +++ docSection Nothing qual doc +++ constrBit +++ instancesBit-- where- docname = tcdName dataDecl- cons = dd_cons (tcdDataDefn dataDecl)- isH98 = case unLoc (head cons) of- 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 = noHtml- | otherwise = if isH98 then noHtml else keyword "where"-- constrBit = subConstructors qual- [ ppSideBySideConstr subdocs subfixs unicode qual c- | c <- cons- , let subfixs = filter (\(n,_) -> any (\cn -> cn == n)- (map unLoc (getConNames (unLoc c)))) fixities- ]-- instancesBit = ppInstances links (OriginData docname) instances- splice unicode qual----ppShortConstr :: Bool -> ConDecl DocName -> Unicode -> Qualification -> Html-ppShortConstr summary con unicode qual = cHead <+> cBody <+> cFoot- where- (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 DocName -> Unicode -> Qualification -> (Html, Html, Html)-ppShortConstrParts summary dataInst con unicode qual = case con of- ConDeclH98{} -> case con_details con of- PrefixCon args ->- (header_ unicode qual +++ hsep (ppOcc- : map (ppLParendType unicode qual) args), noHtml, noHtml)- RecCon (L _ fields) ->- (header_ unicode qual +++ ppOcc <+> char '{',- doRecordFields fields,- char '}')- InfixCon arg1 arg2 ->- (header_ unicode qual +++ hsep [ppLParendType unicode qual arg1,- ppOccInfix, ppLParendType unicode qual arg2],- noHtml, noHtml)-- ConDeclGADT {} -> (ppOcc <+> dcolon unicode <+> ppLType unicode qual resTy,noHtml,noHtml)-- where- resTy = hsib_body (con_type con)-- 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))-- ppOccInfix = case occ of- [one] -> ppBinderInfix summary one- _ -> hsep (punctuate comma (map (ppBinderInfix summary) occ))-- ltvs = fromMaybe (HsQTvs PlaceHolder [] PlaceHolder) (con_qvars con)- tyVars = tyvarNames ltvs- lcontext = fromMaybe (noLoc []) (con_cxt con)- context = unLoc lcontext- forall_ = False----- ppConstrHdr is for (non-GADT) existentials constructors' syntax-ppConstrHdr :: Bool -> [Name] -> HsContext DocName -> 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- <+> darrow unicode +++ toHtml " ")- where- ppForall | forall_ = forallSymbol unicode <+> hsep (map (ppName Prefix) tvs)- <+> toHtml ". "- | otherwise = noHtml--ppSideBySideConstr :: [(DocName, DocForDecl DocName)] -> [(DocName, Fixity)]- -> Unicode -> Qualification -> LConDecl DocName -> SubDecl-ppSideBySideConstr subdocs fixities unicode qual (L _ con)- = (decl, mbDoc, fieldPart)- where- decl = case con of- ConDeclH98{} -> case con_details con of- PrefixCon args ->- hsep ((header_ +++ ppOcc)- : map (ppLParendType unicode qual) args)- <+> fixity-- RecCon _ -> header_ +++ ppOcc <+> fixity-- InfixCon arg1 arg2 ->- hsep [header_ +++ ppLParendType unicode qual arg1,- ppOccInfix,- ppLParendType unicode qual arg2]- <+> fixity-- ConDeclGADT{} -> doGADTCon resTy-- resTy = hsib_body (con_type con)-- fieldPart = case getConDetails con of- RecCon (L _ fields) -> [doRecordFields fields]- _ -> []-- doRecordFields fields = subFields qual- (map (ppSideBySideField subdocs unicode qual) (map unLoc fields))-- doGADTCon :: Located (HsType DocName) -> Html- doGADTCon ty = ppOcc <+> dcolon unicode- -- ++AZ++ make this prepend "{..}" when it is a record style GADT- <+> ppLType unicode qual ty- <+> fixity-- 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))-- tyVars = tyvarNames (fromMaybe (HsQTvs PlaceHolder [] PlaceHolder) (con_qvars con))- context = unLoc (fromMaybe (noLoc []) (con_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---ppSideBySideField :: [(DocName, DocForDecl DocName)] -> Unicode -> Qualification- -> ConDeclField DocName -> SubDecl-ppSideBySideField subdocs unicode qual (ConDeclField names ltype _) =- (hsep (punctuate comma (map ((ppBinder False) . rdrNameOcc . unLoc . rdrNameFieldOcc . unLoc) names)) <+> dcolon unicode <+> ppLType unicode qual ltype,- 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 (selectorFieldOcc $ unLoc $ head names) subdocs >>= combineDocumentation . fst---ppShortField :: Bool -> Unicode -> Qualification -> ConDeclField DocName -> Html-ppShortField summary unicode qual (ConDeclField names ltype _)- = hsep (punctuate comma (map ((ppBinder summary) . rdrNameOcc . unLoc . rdrNameFieldOcc . unLoc) names))- <+> dcolon unicode <+> ppLType unicode qual ltype----- | Print the LHS of a data\/newtype declaration.--- Currently doesn't handle 'data instance' decls or kind signatures-ppDataHeader :: Bool -> TyClDecl DocName -> Unicode -> Qualification -> Html-ppDataHeader summary decl@(DataDecl { tcdDataDefn =- HsDataDefn { dd_ND = nd- , dd_ctxt = ctxt- , dd_kindSig = ks } })- unicode qual- = -- newtype or data- (case nd of { NewType -> keyword "newtype"; DataType -> keyword "data" })- <+>- -- context- ppLContext ctxt unicode qual <+>- -- T a b c ..., or a :+: b- ppDataBinderWithVars summary decl- <+> 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---tupleParens :: HsTupleSort -> [Html] -> Html-tupleParens HsUnboxedTuple = ubxParenList-tupleParens _ = parenList-------------------------------------------------------------------------------------- * Rendering of HsType------------------------------------------------------------------------------------pREC_TOP, pREC_CTX, pREC_FUN, pREC_OP, pREC_CON :: Int--pREC_TOP = 0 :: Int -- type in ParseIface.y in GHC-pREC_CTX = 1 :: Int -- Used for single contexts, eg. ctx => type- -- (as opposed to (ctx1, ctx2) => type)-pREC_FUN = 2 :: Int -- btype in ParseIface.y in GHC- -- Used for LH arg of (->)-pREC_OP = 3 :: Int -- Used for arg of any infix operator- -- (we don't keep their fixities around)-pREC_CON = 4 :: Int -- Used for arg of type applicn:- -- always parenthesise unless atomic--maybeParen :: Int -- Precedence of context- -> Int -- Precedence of top-level operator- -> Html -> Html -- Wrap in parens if (ctxt >= op)-maybeParen ctxt_prec op_prec p | ctxt_prec >= op_prec = parens p- | otherwise = p---ppLType, ppLParendType, ppLFunLhType :: Unicode -> Qualification- -> Located (HsType DocName) -> Html-ppLType unicode qual y = ppType unicode qual (unLoc y)-ppLParendType unicode qual y = ppParendType unicode qual (unLoc y)-ppLFunLhType unicode qual y = ppFunLhType unicode qual (unLoc y)---ppType, ppCtxType, ppParendType, ppFunLhType :: Unicode -> Qualification- -> HsType DocName -> Html-ppType unicode qual ty = ppr_mono_ty pREC_TOP ty unicode qual-ppCtxType unicode qual ty = ppr_mono_ty pREC_CTX ty unicode qual-ppParendType unicode qual ty = ppr_mono_ty pREC_CON ty unicode qual-ppFunLhType unicode qual ty = ppr_mono_ty pREC_FUN ty unicode qual--ppHsTyVarBndr :: Unicode -> Qualification -> HsTyVarBndr DocName -> Html-ppHsTyVarBndr _ qual (UserTyVar (L _ name)) =- ppDocName qual Raw False name-ppHsTyVarBndr unicode qual (KindedTyVar name kind) =- parens (ppDocName qual Raw False (unLoc name) <+> dcolon unicode <+>- ppLKind unicode qual kind)--ppLKind :: Unicode -> Qualification -> LHsKind DocName -> Html-ppLKind unicode qual y = ppKind unicode qual (unLoc y)--ppKind :: Unicode -> Qualification -> HsKind DocName -> Html-ppKind unicode qual ki = ppr_mono_ty pREC_TOP ki unicode qual--ppForAllPart :: [LHsTyVarBndr DocName] -> Unicode -> Html-ppForAllPart tvs unicode = hsep (forallSymbol unicode : ppTyVars tvs) +++ dot--ppr_mono_lty :: Int -> LHsType DocName -> Unicode -> Qualification -> Html-ppr_mono_lty ctxt_prec ty = ppr_mono_ty ctxt_prec (unLoc ty)---ppr_mono_ty :: Int -> HsType DocName -> Unicode -> Qualification -> Html-ppr_mono_ty ctxt_prec (HsForAllTy tvs ty) unicode qual- = maybeParen ctxt_prec pREC_FUN $- ppForAllPart tvs unicode <+> ppr_mono_lty pREC_TOP ty unicode qual--ppr_mono_ty ctxt_prec (HsQualTy ctxt ty) unicode qual- = maybeParen ctxt_prec pREC_FUN $- ppLContext ctxt unicode qual <+> ppr_mono_lty pREC_TOP ty unicode qual---- UnicodeSyntax alternatives-ppr_mono_ty _ (HsTyVar (L _ name)) True _- | getOccString (getName name) == "*" = toHtml "★"- | getOccString (getName name) == "(->)" = toHtml "(→)"--ppr_mono_ty _ (HsBangTy b ty) u q = ppBang b +++ ppLParendType u q ty-ppr_mono_ty _ (HsTyVar (L _ name)) _ q = ppDocName q Prefix True name-ppr_mono_ty ctxt_prec (HsFunTy ty1 ty2) u q = ppr_fun_ty ctxt_prec ty1 ty2 u q-ppr_mono_ty _ (HsTupleTy con tys) u q = tupleParens con (map (ppLType u q) tys)-ppr_mono_ty _ (HsKindSig ty kind) u q =- parens (ppr_mono_lty pREC_TOP ty u q <+> dcolon u <+> ppLKind u q kind)-ppr_mono_ty _ (HsListTy ty) u q = brackets (ppr_mono_lty pREC_TOP ty u q)-ppr_mono_ty _ (HsPArrTy ty) u q = pabrackets (ppr_mono_lty pREC_TOP ty u q)-ppr_mono_ty ctxt_prec (HsIParamTy n ty) u q =- maybeParen ctxt_prec pREC_CTX $ ppIPName n <+> dcolon u <+> ppr_mono_lty pREC_TOP ty u q-ppr_mono_ty _ (HsSpliceTy {}) _ _ = error "ppr_mono_ty HsSpliceTy"-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 _ (HsCoreTy {}) _ _ = error "ppr_mono_ty HsCoreTy"-ppr_mono_ty _ (HsExplicitListTy _ tys) u q = promoQuote $ brackets $ hsep $ punctuate comma $ map (ppLType u q) tys-ppr_mono_ty _ (HsExplicitTupleTy _ tys) u q = promoQuote $ parenList $ map (ppLType u q) tys-ppr_mono_ty _ (HsAppsTy {}) _ _ = error "ppr_mono_ty HsAppsTy"--ppr_mono_ty ctxt_prec (HsEqTy ty1 ty2) unicode qual- = maybeParen ctxt_prec pREC_CTX $- ppr_mono_lty pREC_OP ty1 unicode qual <+> char '~' <+> ppr_mono_lty pREC_OP ty2 unicode qual--ppr_mono_ty ctxt_prec (HsAppTy fun_ty arg_ty) unicode qual- = maybeParen ctxt_prec pREC_CON $- hsep [ppr_mono_lty pREC_FUN fun_ty unicode qual, ppr_mono_lty pREC_CON arg_ty unicode qual]--ppr_mono_ty ctxt_prec (HsOpTy ty1 op ty2) unicode qual- = maybeParen ctxt_prec pREC_FUN $- ppr_mono_lty pREC_OP ty1 unicode qual <+> ppr_op <+> ppr_mono_lty pREC_OP ty2 unicode qual- where- -- `(:)` is valid in type signature only as constructor to promoted list- -- and needs to be quoted in code so we explicitly quote it here too.- ppr_op- | (getOccString . getName . unLoc) op == ":" = promoQuote ppr_op'- | otherwise = ppr_op'- ppr_op' = ppLDocName qual Infix op--ppr_mono_ty ctxt_prec (HsParTy ty) unicode qual--- = parens (ppr_mono_lty pREC_TOP ty)- = ppr_mono_lty ctxt_prec ty unicode qual--ppr_mono_ty ctxt_prec (HsDocTy ty _) unicode qual- = ppr_mono_lty ctxt_prec ty unicode qual--ppr_mono_ty _ (HsWildCardTy (AnonWildCard _)) _ _ = char '_'-ppr_mono_ty _ (HsTyLit n) _ _ = ppr_tylit n--ppr_tylit :: HsTyLit -> Html-ppr_tylit (HsNumTy _ n) = toHtml (show n)-ppr_tylit (HsStrTy _ s) = toHtml (show s)---ppr_fun_ty :: Int -> LHsType DocName -> LHsType DocName -> Unicode -> Qualification -> Html-ppr_fun_ty ctxt_prec ty1 ty2 unicode qual- = let p1 = ppr_mono_lty pREC_FUN ty1 unicode qual- p2 = ppr_mono_lty pREC_TOP ty2 unicode qual- in- maybeParen ctxt_prec pREC_FUN $- hsep [p1, arrow unicode <+> p2]+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE LambdaCase #-}++-----------------------------------------------------------------------------+-- |+-- Module : Haddock.Backends.Html.Decl+-- Copyright : (c) Simon Marlow 2003-2006,+-- David Waern 2006-2009,+-- Mark Lentczner 2010+-- License : BSD-like+--+-- Maintainer : haddock@projects.haskell.org+-- Stability : experimental+-- Portability : portable+-----------------------------------------------------------------------------+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.GhcUtils+import Haddock.Types+import Haddock.Doc (combineDocumentation)++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 GHC.Core.Type ( Specificity(..) )+import GHC hiding (LexicalFixity(..), fromMaybeContext)+import GHC.Exts hiding (toList)+import GHC.Types.Name+import GHC.Data.BooleanFormula+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 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+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 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+ 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 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)+ 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+++-- | 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 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 }) =+ case outer_bndrs of+ HsOuterExplicit{hso_bndrs = bndrs} -> do_largs n (leader' bndrs) ltype+ HsOuterImplicit{} -> do_largs n leader ltype+ where+ leader' bndrs = leader <+> ppForAllPart unicode qual (mkHsForAllInvisTeleI bndrs)++ argDoc n = Map.lookup n argDocs++ do_largs :: Int -> Html -> LHsType DocNameI -> [SubDecl]+ 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+ 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, [])]+++ -- 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 "{"+++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)++ 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 ]++ rightEdge = thespan ! [theclass "rightedge"] << noHtml+++-- | Pretty-print type variables.+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 _ _ _ _ _ _ _ _ _ _ = 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 _ _ _ _ _ _ _ _ _ _ = 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 links splice unicode qual emptyCtxts loc names typ =+ 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 summary associated links instances fixities loc doc decl splice unicode pkg 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++ 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++ -- 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)+ , Nothing+ , []+ )+++-- | Print a pseudo family declaration+ppPseudoFamDecl :: LinksInfo -> Splice+ -> PseudoFamilyDecl DocNameI -- ^ this decl+ -> Unicode -> Qualification -> Html+ppPseudoFamDecl links splice+ (PseudoFamilyDecl { pfdInfo = info+ , pfdKindSig = L _ kindSig+ , pfdTyVars = tvs+ , pfdLName = L loc name })+ unicode qual =+ topDeclElem links (locA loc) splice [name] leader+ where+ leader = hsep [ ppFamilyLeader True info+ , ppAppNameTypes name (map unLoc tvs) unicode qual+ , ppResultSig kindSig unicode qual+ ]++-- | 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"++-- | 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"++-- | 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+++--------------------------------------------------------------------------------+-- * Associated Types+--------------------------------------------------------------------------------+++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+++--------------------------------------------------------------------------------+-- * Type applications+--------------------------------------------------------------------------------++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)+ where+ ppDN notation = ppBinderFixity notation summ . nameOccName . getName+ ppBinderFixity Infix = ppBinderInfix+ ppBinderFixity _ = ppBinder++-- | 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)++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)++-- | General printing of type applications+ppTypeApp :: DocName -> [a] -> (Notation -> DocName -> Html) -> (a -> Html) -> Html+ppTypeApp n (t1:t2:rest) ppDN ppT+ | operator, not . null $ rest = parens opApp <+> hsep (map ppT rest)+ | 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+-------------------------------------------------------------------------------+++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+++ppContextNoLocs :: [HsType DocNameI] -> Unicode -> Qualification -> HideEmptyContexts -> Html+ppContextNoLocs cxt unicode qual emptyCtxts = maybe noHtml (<+> darrow unicode) $+ ppContextNoLocsMaybe cxt unicode qual emptyCtxts+++ppContextNoLocsMaybe :: [HsType DocNameI] -> Unicode -> Qualification -> HideEmptyContexts -> Maybe Html+ppContextNoLocsMaybe [] _ _ emptyCtxts =+ case emptyCtxts of+ HideEmptyContexts -> Nothing+ ShowEmptyToplevelContexts -> Just (toHtml "()")+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 [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 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+++ppFds :: [LHsFunDep DocNameI] -> Unicode -> Qualification -> Html+ppFds fds unicode qual =+ 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 ] ++++ -- 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+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+ ]+ -- 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 (getOccString name) defaultMethods+ defaultMethods = Map.fromList+ [ (nameStr, (typ, doc))+ | ClassOpSig _ True lnames typ <- sigs+ , name <- map unLoc lnames+ , let doc = noDocForDecl -- TODO: get docs for method defaults+ 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' | L _ (ClassOpSig _ _ ns _) <- lsigs, 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+ where+ 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)+ 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 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+ -> [PseudoFamilyDecl DocNameI]+ -> [Html]+ppInstanceAssocTys links splice unicode qual =+ map (\pseudo -> ppPseudoFamDecl links splice pseudo unicode qual)+++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+++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+ ]+ 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 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)++ where+ dataHeader+ | 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+ ]++ 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+++-- 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+ )++ where+ 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+ -- 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++ 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 = 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+ ]++ 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))++ doConstrArgsWithDocs args = subFields pkg qual $ case con of+ ConDeclH98{} ->+ [ (ppLParendType unicode qual HideEmptyContexts arg, mdoc, [])+ | (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++ -- 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+++-- ppConstrHdr is for (non-GADT) existentials constructors' syntax+ppConstrHdr+ :: Bool -- ^ print explicit foralls+ -> [LHsTyVarBndr Specificity DocNameI] -- ^ type variables+ -> HsContext DocNameI -- ^ context+ -> Unicode -> Qualification+ -> Html+ppConstrHdr forall_ tvs ctxt unicode qual = ppForall +++ ppCtxt+ where+ ppForall+ | null tvs || not forall_ = noHtml+ | otherwise = ppForAllPart unicode qual (HsForAllInvis noExtField tvs)++ 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 [ ppBinder False (rdrNameOcc field)+ | L _ name <- names+ , let field = (unLoc . foLabel) name+ ])+ <+> dcolon unicode+ <+> ppLType unicode qual HideEmptyContexts ltype+ , 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 >>= 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+++-- | 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 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 typ+ , fixity+ ]++ fieldPart+ | not hasArgDocs = []+ | 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 _ _ _ _ = error "ppDataHeader: illegal argument"++--------------------------------------------------------------------------------+-- * Types and contexts+--------------------------------------------------------------------------------+++ppBang :: HsSrcBang -> Html+ppBang (HsSrcBang _ _ SrcStrict) = toHtml "!"+ppBang (HsSrcBang _ _ SrcLazy) = toHtml "~"+ppBang _ = noHtml+++tupleParens :: HsTupleSort -> [Html] -> Html+tupleParens HsUnboxedTuple = ubxParenList+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)+ppLParendType unicode qual emptyCtxts y = ppParendType 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 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+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++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+ppLHsTypeArg unicode qual emptyCtxts (HsValArg ty) = ppLParendType unicode qual emptyCtxts ty+ppLHsTypeArg unicode qual emptyCtxts (HsTypeArg _ ki) = atSign unicode <>+ ppLParendType unicode qual emptyCtxts ki+ppLHsTypeArg _ _ _ (HsArgPar _) = toHtml ""++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 unicode qual (KindedTyVar _ _ name 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 unicode qual (KindedTyVar _ SpecifiedSpec name 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)++ppLKind :: Unicode -> Qualification -> LHsKind DocNameI -> Html+ppLKind unicode qual y = ppKind unicode qual (unLoc y)++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+ where+ typ = sig_body (unLoc sig_typ)++ hasNonEmptyContext t =+ case unLoc t of+ HsForAllTy _ _ s -> hasNonEmptyContext s+ HsQualTy _ cxt s -> if null (unLoc cxt) then hasNonEmptyContext s else True+ HsFunTy _ _ _ s -> hasNonEmptyContext s+ _ -> False+ isFirstContextEmpty t =+ case unLoc t of+ HsForAllTy _ _ s -> isFirstContextEmpty s+ HsQualTy _ cxt _ -> null (unLoc cxt)+ 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 unicode qual outer_bndrs = case outer_bndrs of+ HsOuterImplicit{} -> noHtml+ HsOuterExplicit{hso_bndrs = bndrs} ->+ hsep (forallSymbol unicode : ppTyVars unicode qual bndrs) +++ dot++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 } ->+ 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_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++-- 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 _+ | isPromoted prom = promoQuote (ppDocName q Prefix True name)+ | otherwise = ppDocName q Prefix True name+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++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 (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 (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 unicode <> 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+ ppr_op = ppLDocName qual Infix op++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 (HsWildCardTy _) _ _ _ = char '_'+ppr_mono_ty (HsTyLit _ n) _ _ _ = ppr_tylit n++ppr_tylit :: HsTyLit DocNameI -> Html+ppr_tylit (HsNumTy _ n) = toHtml (show n)+ppr_tylit (HsStrTy _ s) = toHtml (show s)+ppr_tylit (HsCharTy _ c) = toHtml (show c)
src/Haddock/Backends/Xhtml/DocMarkup.hs view
@@ -19,7 +19,8 @@ docElement, docSection, docSection_, ) where -import Data.List+import Data.List (intersperse)+import Documentation.Haddock.Markup import Haddock.Backends.Xhtml.Names import Haddock.Backends.Xhtml.Utils import Haddock.Types@@ -30,8 +31,8 @@ import Text.XHtml hiding ( name, p, quote ) import Data.Maybe (fromMaybe) -import GHC-import Name+import GHC hiding (anchor)+import GHC.Types.Name parHtmlMarkup :: Qualification -> Bool@@ -43,36 +44,38 @@ markupAppend = (+++), markupIdentifier = thecode . ppId insertAnchors, markupIdentifierUnchecked = thecode . ppUncheckedLink qual,- markupModule = \m -> let (mdl,ref) = break (=='#') m- -- Accomodate for old style- -- foo\#bar anchors- mdl' = case reverse mdl of- '\\':_ -> init mdl- _ -> mdl- in ppModuleRef (mkModuleName mdl') ref,+ 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 = ordList,+ markupOrderedList = makeOrdList, markupDefList = defList, markupCodeBlock = pre, markupHyperlink = \(Hyperlink url mLabel) -> if insertAnchors then anchor ! [href url]- << fromMaybe url mLabel- else toHtml $ fromMaybe url mLabel,+ << 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 -> toHtml ("\\(" ++ mathjax ++ "\\)"),- markupMathDisplay = \mathjax -> toHtml ("\\[" ++ mathjax ++ "\\]"),+ 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+ markupHeader = \(Header l t) -> makeHeader l t,+ markupTable = \(Table h r) -> makeTable h r } where makeHeader :: Int -> Html -> Html@@ -84,7 +87,23 @@ makeHeader 6 mkup = h6 mkup makeHeader l _ = error $ "Somehow got a header level `" ++ show l ++ "' in DocMarkup!" + makeTable :: [TableRow Html] -> [TableRow Html] -> Html+ makeTable hs bs = table (concatHtml (hs' ++ bs'))+ where+ hs' | null hs = []+ | otherwise = [thead (concatHtml (map (makeTableRow th) hs))] + bs' = [tbody (concatHtml (map (makeTableRow td) bs))]++ makeTableRow :: (Html -> Html) -> TableRow Html -> Html+ makeTableRow thr (TableRow cs) = tr (concatHtml (map (makeTableCell thr) cs))++ 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 ]+ examplesToHtml l = pre (concatHtml $ map exampleToHtml l) ! [theclass "screen"] exampleToHtml (Example expression result) = htmlExample@@ -93,9 +112,12 @@ htmlPrompt = (thecode . toHtml $ ">>> ") ! [theclass "prompt"] htmlExpression = (strong . thecode . toHtml $ expression ++ "\n") ! [theclass "userinput"] + makeOrdList :: HTML a => [(Int, a)] -> Html+ makeOrdList items = olist << map (\(index, a) -> li ! [intAttr "value" index] << a) items+ -- | We use this intermediate type to transform the input 'Doc' tree -- in an arbitrary way before rendering, such as grouping some--- elements. This is effectivelly a hack to prevent the 'Doc' type+-- 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 =@@ -153,20 +175,20 @@ -- extract/append the underlying 'Doc' and convert it to 'Html'. For -- 'CollapsingHeader', we attach extra info to the generated 'Html' -- that allows us to expand/collapse the content.-hackMarkup :: DocMarkup id Html -> Hack (ModuleName, OccName) id -> Html-hackMarkup fmt' h' =+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' (metaConcat ms)+ in html +++ renderMeta fmt' currPkg (metaConcat ms) where- hackMarkup' :: DocMarkup id Html -> Hack (ModuleName, OccName) id+ 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- expanded = False- col' = collapseControl id_ expanded "caption"- instTable = (thediv ! collapseSection id_ expanded [] <<)+ col' = collapseControl id_ "subheading"+ summary = thesummary ! [ theclass "hide-when-js-enabled" ] << "Expand"+ instTable contents = collapseDetails id_ DetailsClosed (summary +++ contents) lvs = zip [1 .. ] [h1, h2, h3, h4, h5, h6] getHeader = fromMaybe caption (lookup lvl lvs) subCaption = getHeader ! col' << markup fmt titl@@ -175,46 +197,51 @@ (y, m') = hackMarkup' fmt d' in (markupAppend fmt x y, m ++ m') -renderMeta :: DocMarkup id Html -> Meta -> Html-renderMeta fmt (Meta { _version = Just x }) =+renderMeta :: DocMarkup id Html -> Maybe Package -> Meta -> Html+renderMeta fmt currPkg (Meta { _version = Just x, _package = pkg }) = markupParagraph fmt . markupEmphasis fmt . toHtml $- "Since: " ++ formatVersion x+ "Since: " ++ formatPkgMaybe pkg ++ formatVersion x where formatVersion v = concat . intersperse "." $ map show v-renderMeta _ _ = noHtml+ formatPkgMaybe (Just p) | Just p /= currPkg = p ++ "-"+ formatPkgMaybe _ = ""+renderMeta _ _ _ = noHtml -- | 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 id Html+markupHacked :: DocMarkup (Wrap id) Html+ -> Maybe Package -- this package -> Maybe String -> MDoc id -> Html-markupHacked fmt n = hackMarkup fmt . toHack 0 n . flatten+markupHacked fmt currPkg n = hackMarkup fmt currPkg . toHack 0 n . flatten -- If the doc is a single paragraph, don't surround it with <P> (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.+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 qual = markupHacked fmt n . cleanup- where fmt = parHtmlMarkup qual True (ppDocName qual Raw)+docToHtml n pkg qual = markupHacked fmt pkg n . cleanup+ 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'+docToHtmlNoAnchors :: Maybe String -- ^ See 'toHack'+ -> Maybe Package -- ^ Current package -> Qualification -> MDoc DocName -> Html-docToHtmlNoAnchors n qual = markupHacked fmt n . cleanup- where fmt = parHtmlMarkup qual False (ppDocName qual Raw)+docToHtmlNoAnchors n pkg qual = markupHacked fmt pkg n . cleanup+ where fmt = parHtmlMarkup qual False (ppWrappedDocName qual Raw) -origDocToHtml :: Qualification -> MDoc Name -> Html-origDocToHtml qual = markupHacked fmt Nothing . cleanup- where fmt = parHtmlMarkup qual True (const $ ppName Raw)+origDocToHtml :: Maybe Package -> Qualification -> MDoc Name -> Html+origDocToHtml pkg qual = markupHacked fmt pkg Nothing . cleanup+ where fmt = parHtmlMarkup qual True (const (ppWrappedName Raw)) -rdrDocToHtml :: Qualification -> MDoc RdrName -> Html-rdrDocToHtml qual = markupHacked fmt Nothing . cleanup- where fmt = parHtmlMarkup qual True (const ppRdrName)+rdrDocToHtml :: Maybe Package -> Qualification -> MDoc RdrName -> Html+rdrDocToHtml pkg qual = markupHacked fmt pkg Nothing . cleanup+ where fmt = parHtmlMarkup qual True (const (ppRdrName . unwrap)) docElement :: (Html -> Html) -> Html -> Html@@ -225,14 +252,17 @@ docSection :: Maybe Name -- ^ Name of the thing this doc is for+ -> Maybe Package -- ^ Current package -> Qualification -> Documentation DocName -> Html-docSection n qual = maybe noHtml (docSection_ n qual) . combineDocumentation+docSection n pkg qual =+ maybe noHtml (docSection_ n pkg qual) . combineDocumentation -docSection_ :: Maybe Name -- ^ Name of the thing this doc is for+docSection_ :: Maybe Name -- ^ Name of the thing this doc is for+ -> Maybe Package -- ^ Current package -> Qualification -> MDoc DocName -> Html-docSection_ n qual =- (docElement thediv <<) . docToHtml (getOccString <$> n) qual+docSection_ n pkg qual =+ (docElement thediv <<) . docToHtml (getOccString <$> n) pkg qual cleanup :: MDoc a -> MDoc a@@ -247,8 +277,8 @@ unParagraph (DocParagraph d) = d unParagraph doc = doc - fmtUnParagraphLists :: DocMarkup a (Doc a)+ fmtUnParagraphLists :: DocMarkup (Wrap a) (Doc a) fmtUnParagraphLists = idMarkup { markupUnorderedList = DocUnorderedList . map unParagraph,- markupOrderedList = DocOrderedList . map unParagraph+ markupOrderedList = DocOrderedList . map (\(index, a) -> (index, unParagraph a)) }
src/Haddock/Backends/Xhtml/Layout.hs view
@@ -15,7 +15,7 @@ divPackageHeader, divContent, divModuleHeader, divFooter, divTableOfContents, divDescription, divSynopsis, divInterface,- divIndex, divAlphabet, divModuleList,+ divIndex, divAlphabet, divPackageList, divModuleList, divContentsList, sectionName, nonEmptySectionName,@@ -29,28 +29,30 @@ subArguments, subAssociatedTypes, subConstructors,+ subPatterns, subEquations, subFields, subInstances, subOrphanInstances, subInstHead, subInstDetails, subFamInstDetails, subMethods,+ subDefaults, subMinimal, topDeclElem, declElem, ) where - 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, p, quote )+import Text.XHtml hiding ( name, title, quote )+import Data.Maybe (fromMaybe) -import FastString ( unpackFS )-import GHC-import Name (nameOccName)+import GHC.Data.FastString ( unpackFS )+import GHC hiding (anchor)+import GHC.Types.Name (nameOccName) -------------------------------------------------------------------------------- -- * Sections of the document@@ -73,13 +75,13 @@ -- If it would have otherwise been empty, then give it the class ".empty". nonEmptySectionName :: Html -> Html nonEmptySectionName c- | isNoHtml c = paragraph ! [theclass "caption empty"] $ spaceHtml- | otherwise = paragraph ! [theclass "caption"] $ c+ | isNoHtml c = thespan ! [theclass "caption empty"] $ spaceHtml+ | otherwise = thespan ! [theclass "caption"] $ c divPackageHeader, divContent, divModuleHeader, divFooter, divTableOfContents, divDescription, divSynopsis, divInterface,- divIndex, divAlphabet, divModuleList+ divIndex, divAlphabet, divPackageList, divModuleList, divContentsList :: Html -> Html divPackageHeader = sectionDiv "package-header"@@ -87,12 +89,14 @@ 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" --------------------------------------------------------------------------------@@ -127,89 +131,96 @@ subCaption = paragraph ! [theclass "caption"] << captionName -subDlist :: Qualification -> [SubDecl] -> Maybe Html-subDlist _ [] = Nothing-subDlist qual decls = Just $ ulist << map subEntry decls+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 qual) mdoc +++ subs))+ docElement thediv << (fmap (docToHtml Nothing pkg qual) mdoc +++ subs)) -subTable :: Qualification -> [SubDecl] -> Maybe Html-subTable _ [] = Nothing-subTable qual decls = Just $ table << aboves (concatMap subRow decls)+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 qual) mdoc)+ docElement td << fmap (docToHtml Nothing pkg qual) mdoc) : map (cell . (td <<)) subs -- | Sub table with source information (optional).-subTableSrc :: Qualification -> LinksInfo -> Bool -> [(SubDecl,Located DocName)] -> Maybe Html-subTableSrc _ _ _ [] = Nothing-subTableSrc qual lnks splice decls = Just $ table << aboves (concatMap subRow decls)+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),L loc dn) =+ subRow ((decl, mdoc, subs), mdl, L loc dn) = (td ! [theclass "src clearfix"] << (thespan ! [theclass "inst-left"] << decl)- <+> linkHtml loc dn+ <+> linkHtml loc mdl dn <->- docElement td << fmap (docToHtml Nothing qual) mdoc+ docElement td << fmap (docToHtml Nothing pkg qual) mdoc ) : map (cell . (td <<)) subs- linkHtml loc@(RealSrcSpan _) dn = links lnks loc splice dn- linkHtml _ _ = noHtml + linkHtml :: SrcSpan -> Maybe Module -> DocName -> Html+ linkHtml loc@(RealSrcSpan _ _) mdl dn = links lnks loc splice mdl dn+ linkHtml _ _ _ = noHtml+ subBlock :: [Html] -> Maybe Html subBlock [] = Nothing subBlock hs = Just $ toHtml hs -subArguments :: Qualification -> [SubDecl] -> Html-subArguments qual = divSubDecls "arguments" "Arguments" . subTable qual+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 :: Qualification -> [SubDecl] -> Html-subConstructors qual = divSubDecls "constructors" "Constructors" . subTable qual+subConstructors :: Maybe Package -> Qualification -> [SubDecl] -> Html+subConstructors pkg qual = divSubDecls "constructors" "Constructors" . subTable pkg qual -subFields :: Qualification -> [SubDecl] -> Html-subFields qual = divSubDecls "fields" "Fields" . subDlist qual+subPatterns :: Maybe Package -> Qualification -> [SubDecl] -> Html+subPatterns pkg qual = divSubDecls "bundled-patterns" "Bundled Patterns" . subTable pkg qual +subFields :: Maybe Package -> Qualification -> [SubDecl] -> Html+subFields pkg qual = divSubDecls "fields" "Fields" . subDlist pkg qual -subEquations :: Qualification -> [SubDecl] -> Html-subEquations qual = divSubDecls "equations" "Equations" . subTable qual +subEquations :: Maybe Package -> Qualification -> [SubDecl] -> Html+subEquations pkg qual = divSubDecls "equations" "Equations" . subTable pkg qual --- | Generate sub table for instance declarations, with source-subInstances :: Qualification++-- | Generate collapsible sub table for instance declarations, with source+subInstances :: Maybe Package -> Qualification -> String -- ^ Class name, used for anchor generation -> LinksInfo -> Bool- -> [(SubDecl,Located DocName)] -> Html-subInstances qual nm lnks splice = maybe noHtml wrap . instTable+ -> [(SubDecl, Maybe Module, Located DocName)] -> Html+subInstances pkg qual nm lnks splice = maybe noHtml wrap . instTable where- wrap = (subSection <<) . (subCaption +++)- instTable = fmap (thediv ! collapseSection id_ True [] <<) . subTableSrc qual lnks splice+ wrap contents = subSection (hdr +++ collapseDetails id_ DetailsOpen (summary +++ contents))+ instTable = subTableSrc pkg qual lnks splice subSection = thediv ! [theclass "subs instances"]- subCaption = paragraph ! collapseControl id_ True "caption" << "Instances"+ hdr = h4 ! collapseControl id_ "instances" << "Instances"+ summary = thesummary ! [ theclass "hide-when-js-enabled" ] << "Instances details" id_ = makeAnchorId $ "i:" ++ nm -subOrphanInstances :: Qualification+subOrphanInstances :: Maybe Package -> Qualification -> LinksInfo -> Bool- -> [(SubDecl,Located DocName)] -> Html-subOrphanInstances qual lnks splice = maybe noHtml wrap . instTable+ -> [(SubDecl, Maybe Module, Located DocName)] -> Html+subOrphanInstances pkg qual lnks splice = maybe noHtml wrap . instTable where wrap = ((h1 << "Orphan instances") +++)- instTable = fmap (thediv ! collapseSection id_ True [] <<) . subTableSrc qual lnks splice- id_ = makeAnchorId $ "orphans"+ instTable = fmap (thediv ! [ identifier ("section." ++ id_) ] <<) . subTableSrc pkg qual lnks splice+ id_ = makeAnchorId "orphans" subInstHead :: String -- ^ Instance unique id (for anchor generation)@@ -218,26 +229,30 @@ subInstHead iid hdr = expander noHtml <+> hdr where- expander = thespan ! collapseControl (instAnchorId iid) False "instance"+ 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 iid ats mets =- subInstSection iid << (subAssociatedTypes ats <+> subMethods mets)+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-subFamInstDetails iid fi =- subInstSection iid << thediv ! [theclass "src"] << fi+subFamInstDetails iid fi mdl =+ subInstSection iid << (p mdl <+> (thediv ! [theclass "src"] << fi)) subInstSection :: String -- ^ Instance unique id (for anchor generation) -> Html -> Html-subInstSection iid = thediv ! collapseSection (instAnchorId iid) False "inst-details"+subInstSection iid contents = collapseDetails (instAnchorId iid) DetailsClosed (summary +++ contents)+ where+ summary = thesummary ! [ theclass "hide-when-js-enabled" ] << "Instance details" instAnchorId :: String -> String instAnchorId iid = makeAnchorId $ "i:" ++ iid@@ -246,6 +261,9 @@ subMethods :: [Html] -> Html subMethods = divSubDecls "methods" "Methods" . subBlock +subDefaults :: [Html] -> Html+subDefaults = divSubDecls "default" "" . subBlock+ subMinimal :: Html -> Html subMinimal = divSubDecls "minimal" "Minimal complete definition" . Just . declElem @@ -259,13 +277,13 @@ -- 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 $ head names))+ 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 -> DocName -> Html-links ((_,_,sourceMap,lineMap), (_,_,maybe_wiki_url)) loc splice docName@(Documented n mdl) =+links :: LinksInfo -> SrcSpan -> Bool -> Maybe Module -> DocName -> Html+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))) @@ -289,12 +307,13 @@ -- For source links, we want to point to the original module, -- because only that will have the source.- -- TODO: do something about type instances. They will point to- -- the module defining the type family, which is wrong.- origMod = nameModule n- origPkg = moduleUnitId origMod+ --+ -- '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 fname = case loc of- RealSrcSpan l -> unpackFS (srcSpanFile l)+ RealSrcSpan l _ -> unpackFS (srcSpanFile l) UnhelpfulSpan _ -> error "links: UnhelpfulSpan"-links _ _ _ _ = noHtml+links _ _ _ _ _ = noHtml
+ src/Haddock/Backends/Xhtml/Meta.hs view
@@ -0,0 +1,28 @@+module Haddock.Backends.Xhtml.Meta where++import Haddock.Utils.Json+import Haddock.Version++import Data.ByteString.Builder (hPutBuilder)+import System.FilePath ((</>))+import System.IO (withFile, IOMode (WriteMode))++-- | Everytime breaking changes to the Quckjump api+-- happen this needs to be modified.+quickjumpVersion :: Int+quickjumpVersion = 1++-- | Writes a json encoded file containing additional+-- information about the generated documentation. This+-- is useful for external tools (e.g., Hackage).+writeHaddockMeta :: FilePath -> Bool -> IO ()+writeHaddockMeta odir withQuickjump = do+ let+ meta_json :: Value+ meta_json = object (concat [+ [ "haddock_version" .= String projectVersion ]+ , [ "quickjump_version" .= quickjumpVersion | withQuickjump ]+ ])++ withFile (odir </> "meta.json") WriteMode $ \h ->+ hPutBuilder h (encodeToBuilder meta_json)
src/Haddock/Backends/Xhtml/Names.hs view
@@ -13,7 +13,8 @@ module Haddock.Backends.Xhtml.Names ( ppName, ppDocName, ppLDocName, ppRdrName, ppUncheckedLink, ppBinder, ppBinderInfix, ppBinder',- ppModule, ppModuleRef, ppIPName, linkId, Notation(..)+ ppModule, ppModuleRef, ppIPName, linkId, Notation(..),+ ppWrappedDocName, ppWrappedName, ) where @@ -22,14 +23,14 @@ import Haddock.Types import Haddock.Utils -import Text.XHtml hiding ( name, title, p, quote )+import Text.XHtml hiding ( name, p, quote ) import qualified Data.Map as M-import qualified Data.List as List+import Data.List ( stripPrefix ) -import GHC-import Name-import RdrName-import FastString (unpackFS)+import GHC hiding (LexicalFixity(..), anchor)+import GHC.Types.Name+import GHC.Types.Name.Reader+import GHC.Data.FastString (unpackFS) -- | Indicator of how to render a 'DocName' into 'Html'@@ -49,14 +50,17 @@ ppIPName = toHtml . ('?':) . unpackFS . hsIPNameFS -ppUncheckedLink :: Qualification -> (ModuleName, OccName) -> Html-ppUncheckedLink _ (mdl, occ) = linkIdOcc' mdl (Just occ) << ppOccName occ -- TODO: apply ppQualifyName-+ppUncheckedLink :: Qualification -> Wrap (ModuleName, OccName) -> Html+ppUncheckedLink _ x = linkIdOcc' mdl (Just occ) << occHtml+ where+ (mdl, occ) = unwrap x+ occHtml = toHtml (showWrapped (occNameString . snd) x) -- TODO: apply ppQualifyName -- The Bool indicates if it is to be rendered in infix notation-ppLDocName :: Qualification -> Notation -> Located DocName -> Html+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@@ -68,6 +72,19 @@ 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+ Parenthesized n -> ppDocName qual Prefix insertAnchors n+ Backticked n -> ppDocName qual Infix insertAnchors n++ppWrappedName :: Notation -> Wrap Name -> Html+ppWrappedName notation docName = case docName of+ Unadorned n -> ppName notation n+ Parenthesized n -> ppName Prefix n+ Backticked n -> ppName Infix n+ -- | Render a name depending on the selected qualification mode ppQualifyName :: Qualification -> Notation -> Name -> Module -> Html ppQualifyName qual notation name mdl =@@ -79,7 +96,7 @@ then ppName notation name else ppFullQualName notation mdl name RelativeQual localmdl ->- case List.stripPrefix (moduleString localmdl) (moduleString mdl) of+ case stripPrefix (moduleString localmdl) (moduleString mdl) of -- local, A.x -> x Just [] -> ppName notation name -- sub-module, A.B.x -> B.x@@ -147,17 +164,19 @@ linkIdOcc :: Module -> Maybe OccName -> Bool -> Html -> Html linkIdOcc mdl mbName insertAnchors = if insertAnchors- then anchor ! [href url]+ then anchor ! [href url, title ttl] else id where+ ttl = moduleNameString (moduleName mdl) url = case mbName of Nothing -> moduleUrl mdl Just name -> moduleNameUrl mdl name linkIdOcc' :: ModuleName -> Maybe OccName -> Html -> Html-linkIdOcc' mdl mbName = anchor ! [href url]+linkIdOcc' mdl mbName = anchor ! [href url, title ttl] where+ ttl = moduleNameString mdl url = case mbName of Nothing -> moduleHtmlFile' mdl Just name -> moduleNameUrl' mdl name@@ -168,9 +187,12 @@ << toHtml (moduleString mdl) -ppModuleRef :: ModuleName -> String -> Html-ppModuleRef mdl ref = anchor ! [href (moduleHtmlFile' mdl ++ ref)]- << toHtml (moduleNameString 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.
src/Haddock/Backends/Xhtml/Themes.hs view
@@ -17,6 +17,7 @@ where import Haddock.Options+import Haddock.Backends.Xhtml.Types ( BaseURL, withBaseURL ) import Control.Monad (liftM) import Data.Char (toLower)@@ -58,7 +59,7 @@ standardTheme libDir = liftM (liftEither (take 1)) (defaultThemes libDir) --- | Default themes that are part of Haddock; added with --default-themes+-- | 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, -- and looking for directories with the extension .theme or .std-theme.@@ -176,13 +177,13 @@ cssFiles ts = nub $ concatMap themeFiles ts -styleSheet :: Themes -> Html-styleSheet ts = toHtml $ zipWith mkLink rels 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 (themeHref t), rel aRel, thetype "text/css",+ ! [ href (withBaseURL base_url (themeHref t)), rel aRel, thetype "text/css", XHtml.title (themeName t) ] << noHtml
src/Haddock/Backends/Xhtml/Types.hs view
@@ -12,6 +12,8 @@ ----------------------------------------------------------------------------- module Haddock.Backends.Xhtml.Types ( SourceURLs, WikiURLs,+ BaseURL,+ withBaseURL, LinksInfo, Splice, Unicode,@@ -20,12 +22,21 @@ 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 UnitId FilePath, Map UnitId FilePath)+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 (Just baseUrl) uri = baseUrl FilePath.</> uri -- The URL for source and wiki links type LinksInfo = (SourceURLs, WikiURLs)
src/Haddock/Backends/Xhtml/Utils.hs view
@@ -20,12 +20,15 @@ (<+>), (<=>), char, keyword, punctuate, - braces, brackets, pabrackets, parens, parenList, ubxParenList,- arrow, comma, dcolon, dot, darrow, equals, forallSymbol, quote, promoQuote,+ braces, brackets, pabrackets, parens, parenList, ubxParenList, ubxSumList,+ arrow, lollipop, comma, dcolon, dot, darrow, equals, forallSymbol, quote, promoQuote,+ multAnnotation,+ atSign, hsep, vcat, - collapseSection, collapseToggle, collapseControl,+ DetailsState(..), collapseDetails, thesummary,+ collapseToggle, collapseControl, ) where @@ -36,9 +39,9 @@ import Text.XHtml hiding ( name, title, p, quote ) import qualified Text.XHtml as XHtml -import GHC ( SrcSpan(..), srcSpanStartLine, Name )-import Module ( Module, ModuleName, moduleName, moduleNameString )-import Name ( getOccString, nameOccName, isValOcc )+import GHC ( SrcSpan(..), srcSpanStartLine, Name )+import GHC.Unit.Module ( Module, ModuleName, moduleName, moduleNameString )+import GHC.Types.Name ( getOccString, nameOccName, isValOcc ) -- | Replace placeholder string elements with provided values.@@ -73,7 +76,7 @@ Nothing -> "" Just span_ -> case span_ of- RealSrcSpan span__ ->+ RealSrcSpan span__ _ -> show $ srcSpanStartLine span__ UnhelpfulSpan _ -> "" @@ -109,7 +112,7 @@ 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@@ -177,16 +180,24 @@ ubxParenList = ubxparens . hsep . punctuate comma +ubxSumList :: [Html] -> Html+ubxSumList = ubxparens . hsep . punctuate (toHtml " | ")++ ubxparens :: Html -> Html-ubxparens h = toHtml "(#" +++ h +++ toHtml "#)"+ubxparens h = toHtml "(#" <+> h <+> toHtml "#)" -dcolon, arrow, darrow, forallSymbol :: Bool -> Html+dcolon, arrow, lollipop, darrow, forallSymbol, atSign :: Bool -> Html dcolon 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"+atSign unicode = toHtml (if unicode then "@" else "@") +multAnnotation :: Html+multAnnotation = toHtml "%" dot :: Html dot = toHtml "."@@ -209,26 +220,22 @@ -- A section of HTML which is collapsible. -- --- | Attributes for an area that can be collapsed-collapseSection :: String -> Bool -> String -> [HtmlAttr]-collapseSection id_ state classes = [ identifier sid, theclass cs ]- where cs = unwords (words classes ++ [pick state "show" "hide"])- sid = "section." ++ id_+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 -> [] }++thesummary :: Html -> Html+thesummary = tag "summary"+ -- | Attributes for an area that toggles a collapsed area-collapseToggle :: String -> [HtmlAttr]-collapseToggle id_ = [ strAttr "onclick" js ]- where js = "toggleSection('" ++ id_ ++ "')";+collapseToggle :: String -> String -> [HtmlAttr]+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 -> Bool -> String -> [HtmlAttr]-collapseControl id_ state classes =- [ identifier cid, theclass cs ] ++ collapseToggle id_- where cs = unwords (words classes ++ [pick state "collapser" "expander"])- cid = "control." ++ id_---pick :: Bool -> a -> a -> a-pick True t _ = t-pick False _ f = f+collapseControl :: String -> String -> [HtmlAttr]+collapseControl id_ classes = collapseToggle id_ cs+ where cs = unwords (words classes ++ ["details-toggle-control"])
src/Haddock/Convert.hs view
@@ -1,488 +1,986 @@--{-# LANGUAGE CPP, PatternGuards #-}--------------------------------------------------------------------------------- |--- Module : Haddock.Convert--- Copyright : (c) Isaac Dupree 2009,--- License : BSD-like------ Maintainer : haddock@projects.haskell.org--- Stability : experimental--- Portability : portable------ Conversion between TyThing and HsDecl. This functionality may be moved into--- GHC at some point.-------------------------------------------------------------------------------module Haddock.Convert where--- Some other functions turned out to be useful for converting--- instance heads, which aren't TyThings, so just export everything.--import Bag ( emptyBag )-import BasicTypes ( TupleSort(..) )-import Class-import CoAxiom-import ConLike-import Data.Either (lefts, rights)-import DataCon-import FamInstEnv-import HsSyn-import Name-import NameSet ( emptyNameSet )-import RdrName ( mkVarUnqual )-import PatSyn-import SrcLoc ( Located, noLoc, unLoc )-import TcType ( tcSplitSigmaTy )-import TyCon-import Type-import TyCoRep-import TysPrim ( alphaTyVars, unliftedTypeKindTyConName )-import TysWiredIn ( listTyConName, starKindTyConName, unitTy )-import PrelNames ( hasKey, eqTyConKey, ipClassKey- , tYPETyConKey, ptrRepLiftedDataConKey, ptrRepUnliftedDataConKey )-import Unique ( getUnique )-import Util ( filterByList, filterOut )-import Var--import Haddock.Types-import Haddock.Interface.Specialize------ the main function here! yay!-tyThingToLHsDecl :: TyThing -> Either ErrMsg ([ErrMsg], (HsDecl Name))-tyThingToLHsDecl t = case t of- -- ids (functions and zero-argument a.k.a. CAFs) get a type signature.- -- Including built-in functions like seq.- -- foreign-imported functions could be represented with ForD- -- instead of SigD if we wanted...- --- -- in a future code version we could turn idVarDetails = foreign-call- -- into a ForD instead of a SigD if we wanted. Haddock doesn't- -- need to care.- AnId i -> allOK $ SigD (synifyIdSig 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 ErrMsg (LFamilyDecl a)- extractFamilyDecl (FamDecl d) = return $ noLoc d- extractFamilyDecl _ =- Left "tyThingToLHsDecl: impossible associated tycon"-- atTyClDecls = [synifyTyCon Nothing at_tc | ATI at_tc _ <- classATItems cl]- atFamDecls = map extractFamilyDecl (rights atTyClDecls)- tyClErrors = lefts atTyClDecls- famDeclErrors = lefts atFamDecls- in withErrs (tyClErrors ++ famDeclErrors) . TyClD $ ClassDecl- { tcdCtxt = synifyCtx (classSCTheta cl)- , tcdLName = synifyName cl- , tcdTyVars = synifyTyVars (classTyVars cl)- , tcdFDs = map (\ (l,r) -> noLoc- (map (noLoc . getName) l, map (noLoc . getName) r) ) $- snd $ classTvsFds cl- , tcdSigs = noLoc (MinimalSig mempty . noLoc . fmap noLoc $ classMinimalDef cl) :- map (noLoc . synifyTcIdSig DeleteTopLevelQuantification)- (classMethods cl)- , tcdMeths = emptyBag --ignore default method definitions, they don't affect signature- -- class associated-types are a subset of TyCon:- , tcdATs = rights atFamDecls- , tcdATDefs = [] --ignore associated type defaults- , tcdDocs = [] --we don't have any docs at this point- , tcdFVs = placeHolderNamesTc }- | otherwise- -> synifyTyCon Nothing tc >>= allOK . TyClD-- -- 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 (TypeSig [synifyName dc]- (synifySigWcType ImplicitizeForAll (dataConUserType dc)))-- AConLike (PatSynCon ps) ->- allOK . SigD $ PatSynSig (synifyName ps) (synifyPatSynSigType ps)- where- withErrs e x = return (e, x)- allOK x = return (mempty, x)--synifyAxBranch :: TyCon -> CoAxBranch -> TyFamInstEqn Name-synifyAxBranch tc (CoAxBranch { cab_tvs = tkvs, cab_lhs = args, cab_rhs = rhs })- = let name = synifyName tc- typats = map (synifyType WithinType) args- hs_rhs = synifyType WithinType rhs- in TyFamEqn { tfe_tycon = name- , tfe_pats = HsIB { hsib_body = typats- , hsib_vars = map tyVarName tkvs }- , tfe_rhs = hs_rhs }--synifyAxiom :: CoAxiom br -> Either ErrMsg (HsDecl Name)-synifyAxiom ax@(CoAxiom { co_ax_tc = tc })- | isOpenTypeFamilyTyCon tc- , Just branch <- coAxiomSingleBranch_maybe ax- = return $ InstD (TyFamInstD- (TyFamInstDecl { tfid_eqn = noLoc $ synifyAxBranch tc branch- , tfid_fvs = placeHolderNamesTc }))-- | Just ax' <- isClosedSynFamilyTyConWithAxiom_maybe tc- , getUnique ax' == getUnique ax -- without the getUniques, type error- = synifyTyCon (Just ax) tc >>= return . TyClD-- | otherwise- = Left "synifyAxiom: closed/open family confusion"---- | Turn type constructors into type class declarations-synifyTyCon :: Maybe (CoAxiom br) -> TyCon -> Either ErrMsg (TyClDecl Name)-synifyTyCon _coax tc- | isFunTyCon tc || isPrimTyCon tc- = return $- DataDecl { tcdLName = synifyName tc- , tcdTyVars = -- tyConTyVars doesn't work on fun/prim, but we can make them up:- let mk_hs_tv realKind fakeTyVar- = noLoc $ KindedTyVar (noLoc (getName fakeTyVar))- (synifyKindSig realKind)- in HsQTvs { hsq_implicit = [] -- No kind polymorphism- , hsq_explicit = zipWith mk_hs_tv (fst (splitFunTys (tyConKind tc)))- alphaTyVars --a, b, c... which are unfortunately all kind *- , hsq_dependent = emptyNameSet }-- , tcdDataDefn = HsDataDefn { dd_ND = DataType -- arbitrary lie, they are neither- -- algebraic data nor newtype:- , dd_ctxt = noLoc []- , dd_cType = Nothing- , dd_kindSig = Just (synifyKindSig (tyConKind tc))- -- we have their kind accurately:- , dd_cons = [] -- No constructors- , dd_derivs = Nothing }- , tcdDataCusk = False- , tcdFVs = placeHolderNamesTc }--synifyTyCon _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 (noLoc . synifyAxBranch tc) (fromBranches branches)- | otherwise- -> mkFamDecl $ ClosedTypeFamily $ Just []- BuiltInSynFamTyCon {}- -> mkFamDecl $ ClosedTypeFamily $ Just []- AbstractClosedSynFamilyTyCon {}- -> mkFamDecl $ ClosedTypeFamily Nothing- DataFamilyTyCon {}- -> mkFamDecl DataFamily- where- resultVar = famTcResVar tc- mkFamDecl i = return $ FamDecl $- FamilyDecl { fdInfo = i- , fdLName = synifyName tc- , fdTyVars = synifyTyVars (tyConTyVars tc)- , fdResultSig =- synifyFamilyResultSig resultVar (tyConResKind tc)- , fdInjectivityAnn =- synifyInjectivityAnn resultVar (tyConTyVars tc)- (familyTyConInjectivityInfo tc)- }--synifyTyCon coax tc- | Just ty <- synTyConRhs_maybe tc- = return $ SynDecl { tcdLName = synifyName tc- , tcdTyVars = synifyTyVars (tyConTyVars tc)- , tcdRhs = synifyType WithinType ty- , tcdFVs = placeHolderNamesTc }- | otherwise =- -- (closed) newtype and data- let- alg_nd = if isNewTyCon tc then NewType else DataType- alg_ctx = synifyCtx (tyConStupidTheta tc)- name = case coax of- Just a -> synifyName a -- Data families are named according to their- -- CoAxioms, not their TyCons- _ -> synifyName tc- tyvars = synifyTyVars (tyConTyVars tc)- kindSig = Just (tyConKind 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 = any (not . isVanillaDataCon) (tyConDataCons tc)- consRaw = map (synifyDataCon use_gadt_syntax) (tyConDataCons tc)- cons = rights consRaw- -- "deriving" doesn't affect the signature, no need to specify any.- alg_deriv = Nothing- defn = HsDataDefn { dd_ND = alg_nd- , dd_ctxt = alg_ctx- , dd_cType = Nothing- , dd_kindSig = fmap synifyKindSig kindSig- , dd_cons = cons- , dd_derivs = alg_deriv }- in case lefts consRaw of- [] -> return $- DataDecl { tcdLName = name, tcdTyVars = tyvars, tcdDataDefn = defn- , tcdDataCusk = False, tcdFVs = placeHolderNamesTc }- dataConErrs -> Left $ unlines dataConErrs--synifyInjectivityAnn :: Maybe Name -> [TyVar] -> Injectivity- -> Maybe (LInjectivityAnn Name)-synifyInjectivityAnn Nothing _ _ = Nothing-synifyInjectivityAnn _ _ NotInjective = Nothing-synifyInjectivityAnn (Just lhs) tvs (Injective inj) =- let rhs = map (noLoc . tyVarName) (filterByList inj tvs)- in Just $ noLoc $ InjectivityAnn (noLoc lhs) rhs--synifyFamilyResultSig :: Maybe Name -> Kind -> LFamilyResultSig Name-synifyFamilyResultSig Nothing kind =- noLoc $ KindSig (synifyKindSig kind)-synifyFamilyResultSig (Just name) kind =- noLoc $ TyVarSig (noLoc $ KindedTyVar (noLoc 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 ErrMsg (LConDecl Name)-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 = synifyName dc- -- con_qvars means a different thing depending on gadt-syntax- (univ_tvs, ex_tvs, _eq_spec, theta, arg_tys, res_ty) = dataConFullSig dc-- qvars = if use_gadt_syntax- then synifyTyVars (univ_tvs ++ ex_tvs)- else synifyTyVars ex_tvs-- -- skip any EqTheta, use 'orig'inal syntax- ctx = synifyCtx theta-- linear_tys =- zipWith (\ty bang ->- let tySyn = synifyType WithinType ty- in case bang of- (HsSrcBang _ NoSrcUnpack NoSrcStrict) -> tySyn- bang' -> noLoc $ HsBangTy bang' tySyn)- arg_tys (dataConSrcBangs dc)-- field_tys = zipWith con_decl_field (dataConFieldLabels dc) linear_tys- con_decl_field fl synTy = noLoc $- ConDeclField [noLoc $ FieldOcc (noLoc $ mkVarUnqual $ flLabel fl) (flSelector fl)] synTy- Nothing- hs_arg_tys = case (use_named_field_syntax, use_infix_syntax) of- (True,True) -> Left "synifyDataCon: contradiction!"- (True,False) -> return $ RecCon (noLoc field_tys)- (False,False) -> return $ PrefixCon linear_tys- (False,True) -> case linear_tys of- [a,b] -> return $ InfixCon a b- _ -> Left "synifyDataCon: infix with non-2 args?"- gadt_ty = HsIB [] (synifyType WithinType res_ty)- -- finally we get synifyDataCon's result!- in hs_arg_tys >>=- \hat ->- if use_gadt_syntax- then return $ noLoc $- ConDeclGADT { con_names = [name]- , con_type = gadt_ty- , con_doc = Nothing }- else return $ noLoc $- ConDeclH98 { con_name = name- , con_qvars = Just qvars- , con_cxt = Just ctx- , con_details = hat- , con_doc = Nothing }--synifyName :: NamedThing n => n -> Located Name-synifyName = noLoc . getName---synifyIdSig :: SynifyTypeState -> Id -> Sig Name-synifyIdSig s i = TypeSig [synifyName i] (synifySigWcType s (varType i))--synifyTcIdSig :: SynifyTypeState -> Id -> Sig Name-synifyTcIdSig s i = ClassOpSig False [synifyName i] (synifySigType s (varType i))--synifyCtx :: [PredType] -> LHsContext Name-synifyCtx = noLoc . map (synifyType WithinType)---synifyTyVars :: [TyVar] -> LHsQTyVars Name-synifyTyVars ktvs = HsQTvs { hsq_implicit = []- , hsq_explicit = map synifyTyVar ktvs- , hsq_dependent = emptyNameSet }--synifyTyVar :: TyVar -> LHsTyVarBndr Name-synifyTyVar tv- | isLiftedTypeKind kind = noLoc (UserTyVar (noLoc name))- | otherwise = noLoc (KindedTyVar (noLoc name) (synifyKindSig kind))- where- kind = tyVarKind tv- name = getName tv----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 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!---synifySigType :: SynifyTypeState -> Type -> LHsSigType Name--- The empty binders is a bit suspicious;--- what if the type has free variables?-synifySigType s ty = mkEmptyImplicitBndrs (synifyType s ty)--synifySigWcType :: SynifyTypeState -> Type -> LHsSigWcType Name--- Ditto (see synifySigType)-synifySigWcType s ty = mkEmptyImplicitBndrs (mkEmptyWildCardBndrs (synifyType s ty))--synifyPatSynSigType :: PatSyn -> LHsSigType Name--- Ditto (see synifySigType)-synifyPatSynSigType ps = mkEmptyImplicitBndrs (synifyPatSynType ps)--synifyType :: SynifyTypeState -> Type -> LHsType Name-synifyType _ (TyVarTy tv) = noLoc $ HsTyVar $ noLoc (getName tv)-synifyType _ (TyConApp tc tys)- -- Use */# instead of TYPE 'Lifted/TYPE 'Unlifted (#473)- | tc `hasKey` tYPETyConKey- , [TyConApp lev []] <- tys- , lev `hasKey` ptrRepLiftedDataConKey- = noLoc (HsTyVar (noLoc starKindTyConName))- | tc `hasKey` tYPETyConKey- , [TyConApp lev []] <- tys- , lev `hasKey` ptrRepUnliftedDataConKey- = noLoc (HsTyVar (noLoc unliftedTypeKindTyConName))- -- Use non-prefix tuple syntax where possible, because it looks nicer.- | Just sort <- tyConTuple_maybe tc- , tyConArity tc == length tys- = noLoc $ HsTupleTy (case sort of- BoxedTuple -> HsBoxedTuple- ConstraintTuple -> HsConstraintTuple- UnboxedTuple -> HsUnboxedTuple)- (map (synifyType WithinType) tys)- -- ditto for lists- | getName tc == listTyConName, [ty] <- tys =- noLoc $ HsListTy (synifyType WithinType ty)- -- ditto for implicit parameter tycons- | tc `hasKey` ipClassKey- , [name, ty] <- tys- , Just x <- isStrLitTy name- = noLoc $ HsIParamTy (HsIPName x) (synifyType WithinType ty)- -- and equalities- | tc `hasKey` eqTyConKey- , [ty1, ty2] <- tys- = noLoc $ HsEqTy (synifyType WithinType ty1) (synifyType WithinType ty2)- -- Most TyCons:- | otherwise =- foldl (\t1 t2 -> noLoc (HsAppTy t1 t2))- (noLoc $ HsTyVar $ noLoc (getName tc))- (map (synifyType WithinType) $- filterOut isCoercionTy tys)-synifyType s (AppTy t1 (CoercionTy {})) = synifyType s t1-synifyType _ (AppTy t1 t2) = let- s1 = synifyType WithinType t1- s2 = synifyType WithinType t2- in noLoc $ HsAppTy s1 s2-synifyType _ (ForAllTy (Anon t1) t2) = let- s1 = synifyType WithinType t1- s2 = synifyType WithinType t2- in noLoc $ HsFunTy s1 s2-synifyType s forallty@(ForAllTy _tv _ty) =- let (tvs, ctx, tau) = tcSplitSigmaTy forallty- sPhi = HsQualTy { hst_ctxt = synifyCtx ctx- , hst_body = synifyType WithinType tau }- in case s of- DeleteTopLevelQuantification -> synifyType ImplicitizeForAll tau- WithinType -> noLoc $ HsForAllTy { hst_bndrs = map synifyTyVar tvs- , hst_body = noLoc sPhi }- ImplicitizeForAll -> noLoc sPhi--synifyType _ (LitTy t) = noLoc $ HsTyLit $ synifyTyLit t-synifyType s (CastTy t _) = synifyType s t-synifyType _ (CoercionTy {}) = error "synifyType:Coercion"--synifyPatSynType :: PatSyn -> LHsType Name-synifyPatSynType ps = let- (univ_tvs, req_theta, ex_tvs, prov_theta, arg_tys, res_ty) = patSynSig ps- req_theta' | null req_theta && not (null prov_theta && null ex_tvs) = [unitTy]- -- 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- | otherwise = req_theta- sForAll [] s = s- sForAll tvs s = HsForAllTy { hst_bndrs = map synifyTyVar tvs- , hst_body = noLoc s }- sQual theta s = HsQualTy { hst_ctxt = synifyCtx theta- , hst_body = noLoc s }- sTau = unLoc $ synifyType WithinType $ mkFunTys arg_tys res_ty- in noLoc $ sForAll univ_tvs $ sQual req_theta' $ sForAll ex_tvs $ sQual prov_theta sTau--synifyTyLit :: TyLit -> HsTyLit-synifyTyLit (NumTyLit n) = HsNumTy mempty n-synifyTyLit (StrTyLit s) = HsStrTy mempty s--synifyKindSig :: Kind -> LHsKind Name-synifyKindSig k = synifyType WithinType k--synifyInstHead :: ([TyVar], [PredType], Class, [Type]) -> InstHead Name-synifyInstHead (_, preds, cls, types) = specializeInstHead $ InstHead- { ihdClsName = getName cls- , ihdKinds = map (unLoc . synifyType WithinType) ks- , ihdTypes = map (unLoc . synifyType WithinType) ts- , ihdInstType = ClassInst- { clsiCtx = map (unLoc . synifyType WithinType) preds- , clsiTyVars = synifyTyVars $ classTyVars cls- , clsiSigs = map synifyClsIdSig $ classMethods cls- , clsiAssocTys = do- (Right (FamDecl fam)) <- map (synifyTyCon Nothing) $ classATs cls- pure $ mkPseudoFamilyDecl fam- }- }- where- (ks,ts) = partitionInvisibles (classTyCon cls) id types- synifyClsIdSig = synifyIdSig DeleteTopLevelQuantification---- Convert a family instance, this could be a type family or data family-synifyFamInst :: FamInst -> Bool -> Either ErrMsg (InstHead Name)-synifyFamInst fi opaque = do- ityp' <- ityp $ fi_flavor fi- return InstHead- { ihdClsName = fi_fam fi- , ihdKinds = synifyTypes ks- , ihdTypes = synifyTypes ts- , ihdInstType = ityp'- }- where- ityp SynFamilyInst | opaque = return $ TypeInst Nothing- ityp SynFamilyInst =- return . TypeInst . Just . unLoc . synifyType WithinType $ fi_rhs fi- ityp (DataFamilyInst c) =- DataInst <$> synifyTyCon (Just $ famInstAxiom fi) c- (ks,ts) = partitionInvisibles (famInstTyCon fi) id $ fi_tys fi- synifyTypes = map (unLoc. synifyType WithinType)+{-# LANGUAGE CPP #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE BangPatterns #-}++-----------------------------------------------------------------------------+-- |+-- Module : Haddock.Convert+-- Copyright : (c) Isaac Dupree 2009,+-- License : BSD-like+--+-- Maintainer : haddock@projects.haskell.org+-- Stability : experimental+-- Portability : portable+--+-- Conversion between TyThing and HsDecl. This functionality may be moved into+-- GHC at some point.+-----------------------------------------------------------------------------+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.TyCon+import GHC.Core.Type+import GHC.Core.TyCo.Rep+import GHC.Core.TyCo.Compare( eqTypes )++import GHC.Hs+import GHC.Types.TyThing+import GHC.Types.Name+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.Var+import GHC.Types.Var.Set+import GHC.Types.SrcLoc++import Language.Haskell.Syntax.Basic (FieldLabelString(..))++import Haddock.Types+import Haddock.Interface.Specialize+import Haddock.GhcUtils ( orderedFVs, defaultRuntimeRepVars, mkEmptySigType )++import Data.Either (lefts, rights)+import Data.Maybe ( catMaybes, mapMaybe, maybeToList )+import Data.Either ( partitionEithers )+++-- | 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++-- the main function here! yay!+tyThingToLHsDecl+ :: PrintRuntimeReps+ -> TyThing+ -> Either String ([String], (HsDecl GhcRn))+tyThingToLHsDecl prr t = case t of+ -- ids (functions and zero-argument a.k.a. CAFs) get a type signature.+ -- Including built-in functions like seq.+ -- foreign-imported functions could be represented with ForD+ -- instead of SigD if we wanted...+ --+ -- in a future code version we could turn idVarDetails = foreign-call+ -- 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 (na2la 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 . 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+ { tcdCtxt = Just $ synifyCtx (classSCTheta cl)+ , tcdLayout = NoLayoutInfo+ , 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++ -- 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 (PatSynCon ps) ->+ allOK . SigD noExtField $ PatSynSig noAnn [synifyNameN ps] (synifyPatSynSigType ps)+ where+ withErrs e x = return (e, x)+ 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 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 })+ | isOpenTypeFamilyTyCon tc+ , 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"++-- | 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+ -> 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 }+ where+ -- tyConTyVars doesn't work on fun/prim, but we can make them up:+ mk_hs_tv realKind fakeTyVar+ | isLiftedTypeKind realKind = noLocA $ UserTyVar noAnn () (noLocA (getName fakeTyVar))+ | otherwise = noLocA $ KindedTyVar noAnn () (noLocA (getName fakeTyVar)) (synifyKindSig realKind)++ 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+ 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)+ }++synifyTyCon _prr coax tc+ | Just ty <- synTyConRhs_maybe tc+ = return $ SynDecl { tcdSExt = emptyNameSet+ , tcdLName = synifyNameN tc+ , tcdTyVars = synifyTyVars (tyConVisibleTyVars tc)+ , tcdFixity = synifyFixity tc+ , tcdRhs = synifyType WithinType [] ty }+ | otherwise = do+ -- (closed) newtype and data+ let alg_ctx = synifyCtx (tyConStupidTheta tc)+ name = case coax of+ Just a -> synifyNameN a -- Data families are named according to their+ -- CoAxioms, not their TyCons+ _ -> synifyNameN tc+ 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+ ([], consRaw) -> Right consRaw+ (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 = Just 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:+--+-- > data Foo (w :: *) (m :: * -> *) (a :: *)+--+-- Then its tyConKind will be (* -> (* -> *) -> * -> *). But beware! We are+-- also rendering the type variables of Foo, so if we synify the tyConKind of+-- Foo in full, we will end up displaying this in Haddock:+--+-- > data Foo (w :: *) (m :: * -> *) (a :: *)+-- > :: * -> (* -> *) -> * -> *+--+-- Which is entirely wrong (#548). We only want to display the /return/ kind,+-- which this function obtains.+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++synifyInjectivityAnn :: Maybe Name -> [TyVar] -> Injectivity+ -> Maybe (LInjectivityAnn GhcRn)+synifyInjectivityAnn Nothing _ _ = Nothing+synifyInjectivityAnn _ _ NotInjective = Nothing+synifyInjectivityAnn (Just lhs) tvs (Injective inj) =+ let rhs = map (noLocA . tyVarName) (filterByList inj tvs)+ in Just $ noLocA $ InjectivityAnn noAnn (noLocA lhs) rhs++synifyFamilyResultSig :: Maybe Name -> Kind -> LFamilyResultSig GhcRn+synifyFamilyResultSig Nothing 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))++-- 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+ | 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 (noLocA field_tys) noHsUniTok+ | otherwise = PrefixConGADT (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 = noAnn+ , con_names = pure name+ , con_dcolon = noHsUniTok+ , 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 = noAnn+ , 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)++-- synifyName :: NamedThing n => n -> LocatedA Name+-- synifyName n = L (noAnnSrcSpan $ srcLocSpan (getSrcLoc n)) (getName n)++-- | Guess the fixity of a something with a name. This isn't quite right, since+-- 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++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+ -> Sig GhcRn+synifyIdSig prr s vs i = TypeSig noAnn [n] (synifySigWcType s vs t)+ where+ !n = force $ synifyNameN i+ t = defaultType prr (varType i)++-- | Turn a 'ClassOpItem' into a list of signatures. The list returned is going+-- to contain the synified 'ClassOpSig' as well (when appropriate) a default+-- '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] ]+ where+ mainSig t = synifySigType DeleteTopLevelQuantification vs t+ defSig t = synifySigType ImplicitizeForAll vs t++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 }++synifyTyVar :: TyVar -> LHsTyVarBndr () GhcRn+synifyTyVar = synify_ty_var emptyVarSet ()++synifyTyVarBndr :: VarBndr TyVar flag -> LHsTyVarBndr flag GhcRn+synifyTyVarBndr = synifyTyVarBndr' emptyVarSet++synifyTyVarBndr' :: VarSet -> VarBndr TyVar flag -> LHsTyVarBndr flag GhcRn+synifyTyVarBndr' no_kinds (Bndr tv spec) = synify_ty_var no_kinds spec tv++-- | Like 'synifyTyVarBndr', but accepts a set of variables for which to omit kind+-- 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))+ where+ kind = tyVarKind tv+ name = getName tv++-- | Annotate (with HsKingSig) a type if the first parameter is True+-- 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 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++-- | 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+ where+ is_poly_ty :: Type -> Bool+ is_poly_ty ty = not $+ isEmptyVarSet $+ filterVarSet isTyVar $+ tyCoVarsOfType ty++ tc_vis_tvs :: [TyVar]+ tc_vis_tvs = tyConVisibleTyVars 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:+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!+++synifySigType :: SynifyTypeState -> [TyVar] -> Type -> LHsSigType GhcRn+-- The use of mkEmptySigType (which uses empty binders in OuterImplicit)+-- is a bit suspicious; what if the type has free variables?+synifySigType s vs ty = mkEmptySigType (synifyType s vs ty)++synifySigWcType :: SynifyTypeState -> [TyVar] -> Type -> LHsSigWcType GhcRn+-- Ditto (see synifySigType)+synifySigWcType s vs ty = mkEmptyWildCardBndrs (mkEmptySigType (synifyType s vs ty))++synifyPatSynSigType :: PatSyn -> LHsSigType GhcRn+-- Ditto (see synifySigType)+synifyPatSynSigType ps = mkEmptySigType (synifyPatSynType ps)++-- | Depending on the first argument, try to default all type variables of kind+-- 'RuntimeRep' to 'LiftedType'.+defaultType :: PrintRuntimeReps -> Type -> Type+defaultType ShowRuntimeRep = id+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+ -> LHsType GhcRn+synifyType _ _ (TyVarTy tv) = noLocA $ HsTyVar noAnn NotPromoted $ noLocA (getName tv)+synifyType _ vs (TyConApp tc tys)+ = maybe_sig res_ty+ where+ res_ty :: LHsType GhcRn+ res_ty+ -- Use */# instead of TYPE 'Lifted/TYPE 'Unlifted (#473)+ | tc `hasKey` tYPETyConKey+ , [TyConApp rep [TyConApp lev []]] <- tys+ , rep `hasKey` boxedRepDataConKey+ , 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)+ | Just dc <- isPromotedDataCon_maybe tc+ , isTupleDataCon dc+ , 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 []+ | 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+ -- 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)+ -- and equalities+ | tc `hasKey` eqTyConKey+ , [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+ -- Most TyCons:+ | 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)++ 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'+ | 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 s vs funty@(FunTy af w t1 t2)+ | isInvisibleFunArg af = synifySigmaType s vs funty+ | otherwise = noLocA $ HsFunTy noAnn 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+ 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"++-- | 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+ -> LHsType GhcRn+synifyVisForAllType vs ty =+ let (tvs, rho) = tcSplitForAllTysReqPreserveSynonyms ty++ 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) [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+ -> 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 }++ 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++-- | 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+ -> LHsType GhcRn+implicitForAll tycons vs tvs ctx synInner tau+ | any (isHsKindedTyVar . unLoc) sTvs = noLocA sTy+ | 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])++++-- | 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+-- variable to has at least one fully applied use @f x1 x2 ... xn@ where:+--+-- * @f@ has a function kind where the arguments have the same kinds+-- 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+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)+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 (CastTy t _) = noKindTyVars ts t+noKindTyVars _ _ = emptyVarSet++synifyMult :: [TyVar] -> Mult -> HsArrow GhcRn+synifyMult vs t = case t of+ OneTy -> HsLinearArrow (HsPct1 noHsTok noHsUniTok)+ ManyTy -> HsUnrestrictedArrow noHsUniTok+ ty -> HsExplicitMult noHsTok (synifyType WithinType vs ty) noHsUniTok++++synifyPatSynType :: PatSyn -> LHsType GhcRn+synifyPatSynType ps =+ let (univ_tvs, req_theta, ex_tvs, prov_theta, arg_tys, res_ty) = patSynSigBndr ps+ ts = maybeToList (tyConAppTyCon_maybe res_ty)++ -- 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)++synifyTyLit :: TyLit -> HsTyLit GhcRn+synifyTyLit (NumTyLit n) = HsNumTy NoSourceText n+synifyTyLit (StrTyLit s) = HsStrTy NoSourceText s+synifyTyLit (CharTyLit c) = HsCharTy NoSourceText c++synifyKindSig :: Kind -> LHsKind GhcRn+synifyKindSig k = synifyType WithinType [] k++stripKindSig :: LHsType GhcRn -> LHsType GhcRn+stripKindSig (L _ (HsKindSig _ t _)) = t+stripKindSig t = t++synifyInstHead :: ([TyVar], [PredType], Class, [Type]) -> InstHead GhcRn+synifyInstHead (vs, preds, cls, types) = specializeInstHead $ 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 $ classMethods cls+ , clsiAssocTys = do+ (Right (FamDecl _ fam)) <- map (synifyTyCon HideRuntimeRep Nothing)+ (classATs cls)+ pure $ mkPseudoFamilyDecl fam+ }+ }+ where+ cls_tycon = classTyCon cls+ 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++-- 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'+ }+ where+ ityp SynFamilyInst | opaque = return $ TypeInst Nothing+ ityp SynFamilyInst =+ return . TypeInst . Just . unLoc $ synifyType WithinType [] fam_rhs+ ityp (DataFamilyInst c) =+ 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++ 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++ ts = filterOutInvisibleTypes fam_tc eta_expanded_lhs+ synifyTypes = map (synifyType WithinType [])+ ts' = synifyTypes ts+ annot_ts = zipWith3 annotHsType args_poly ts ts'+ args_poly = tyConArgsPolyKinded fam_tc++{-+Note [Invariant: Never expand type synonyms]++In haddock, we never want to expand a type synonym that may be presented to the+user, as we want to keep the link to the abstraction captured in the synonym.++All code in Haddock.Convert must make sure that this invariant holds.++See https://github.com/haskell/haddock/issues/879 for a bug where this+invariant didn't hold.+-}++-- | A version of 'TcType.tcSplitSigmaTy' that:+--+-- 1. Preserves type synonyms.+-- 2. Returns 'InvisTVBinder's instead of 'TyVar's.+--+-- 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)++-- | See Note [Invariant: Never expand type synonyms]+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)+ 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)+ where+ mk_req_bndr_maybe :: ForAllTyBinder -> Maybe ReqTVBinder+ mk_req_bndr_maybe (Bndr tv argf) = case argf of+ 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)+ 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++-- | See Note [Invariant: Never expand type synonyms]++-- | See Note [Invariant: Never expand type synonyms]+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)++-- | See Note [Invariant: Never expand type synonyms]+tcSplitPredFunTyPreserveSynonyms_maybe :: Type -> Maybe (PredType, Type)+tcSplitPredFunTyPreserveSynonyms_maybe (FunTy af _ arg res)+ | isInvisibleFunArg af = Just (arg, res)+tcSplitPredFunTyPreserveSynonyms_maybe _ = Nothing
src/Haddock/GhcUtils.hs view
@@ -1,5 +1,14 @@-{-# LANGUAGE FlexibleInstances, ViewPatterns #-}+{-# LANGUAGE BangPatterns, FlexibleInstances #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MonadComprehensions #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# OPTIONS_GHC -Wno-incomplete-record-updates #-} {-# OPTIONS_HADDOCK hide #-} ----------------------------------------------------------------------------- -- |@@ -17,141 +26,432 @@ import Control.Arrow-import Data.Function+import Data.Char ( isSpace )+import Data.Foldable ( toList, foldl' )+import Data.List.NonEmpty ( NonEmpty )+import Data.Maybe ( mapMaybe, fromMaybe )+import qualified Data.Set as Set -import Exception-import Outputable-import Name-import Lexeme-import Module-import RdrName (GlobalRdrEnv)-import GhcMonad (withSession)-import HscTypes-import UniqFM+import Haddock.Types( DocName, DocNameI, XRecCond )++import GHC.Utils.FV as FV+import GHC.Utils.Outputable ( Outputable )+import GHC.Utils.Panic ( panic )+import GHC.Driver.Ppr (showPpr )+import GHC.Types.Name+import GHC.Unit.Module import GHC-import Class+import GHC.Driver.Session+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 qualified Data.ByteString.Internal as BS++import GHC.HsToCore.Docs+ moduleString :: Module -> String moduleString = moduleNameString . moduleName isNameSym :: Name -> Bool isNameSym = isSymOcc . nameOccName --isVarSym :: OccName -> Bool-isVarSym = isLexVarSym . occNameFS--isConSym :: OccName -> Bool-isConSym = isLexConSym . occNameFS---getMainDeclBinder :: HsDecl name -> [name]-getMainDeclBinder (TyClD d) = [tcdName d]-getMainDeclBinder (ValD d) =- case collectHsBindBinders d of- [] -> []- (name:_) -> [name]-getMainDeclBinder (SigD d) = sigNameNoLoc d-getMainDeclBinder (ForD (ForeignImport name _ _ _)) = [unLoc name]-getMainDeclBinder (ForD (ForeignExport _ _ _ _)) = []-getMainDeclBinder _ = []---- Extract the source location where an instance is defined. This is used--- to correlate InstDecls with their Instance/CoAxiom Names, via the--- instanceMap.-getInstLoc :: InstDecl name -> SrcSpan-getInstLoc (ClsInstD (ClsInstDecl { cid_poly_ty = ty })) = getLoc (hsSigType ty)-getInstLoc (DataFamInstD (DataFamInstDecl { dfid_tycon = L l _ })) = l-getInstLoc (TyFamInstD (TyFamInstDecl- -- Since CoAxioms' Names refer to the whole line for type family instances- -- in particular, we need to dig a bit deeper to pull out the entire- -- equation. This does not happen for data family instances, for some reason.- { tfid_eqn = L _ (TyFamEqn { tfe_rhs = L l _ })})) = l- -- Useful when there is a signature with multiple names, e.g. -- foo, bar :: Types.. -- but only one of the names is exported and we have to change the -- type signature to only include the exported names.-filterLSigNames :: (name -> Bool) -> LSig name -> Maybe (LSig name)+filterLSigNames :: (IdP (GhcPass p) -> Bool) -> LSig (GhcPass p) -> Maybe (LSig (GhcPass p)) filterLSigNames p (L loc sig) = L loc <$> (filterSigNames p sig) -filterSigNames :: (name -> Bool) -> Sig name -> Maybe (Sig name)-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 ty)) =+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 (FixSig _ (FixitySig _ ns ty)) = case filter (p . unLoc) ns of [] -> Nothing- filtered -> Just (FixSig (FixitySig filtered ty))+ filtered -> Just (FixSig noAnn (FixitySig noExtField filtered ty)) filterSigNames _ orig@(MinimalSig _ _) = Just orig-filterSigNames p (TypeSig ns ty) =+filterSigNames p (TypeSig _ ns ty) = case filter (p . unLoc) ns of [] -> Nothing- filtered -> Just (TypeSig filtered ty)-filterSigNames p (ClassOpSig is_default ns ty) =+ filtered -> Just (TypeSig noAnn filtered ty)+filterSigNames p (ClassOpSig _ is_default ns ty) = case filter (p . unLoc) ns of [] -> Nothing- filtered -> Just (ClassOpSig is_default filtered ty)-filterSigNames _ _ = Nothing+ filtered -> Just (ClassOpSig noAnn is_default filtered ty)+filterSigNames p (PatSynSig _ ns ty) =+ case filter (p . unLoc) ns of+ [] -> Nothing+ filtered -> Just (PatSynSig noAnn filtered ty)+filterSigNames _ _ = Nothing ifTrueJust :: Bool -> name -> Maybe name ifTrueJust True = Just ifTrueJust False = const Nothing -sigName :: LSig name -> [name]-sigName (L _ sig) = sigNameNoLoc sig--sigNameNoLoc :: Sig name -> [name]-sigNameNoLoc (TypeSig ns _) = map unLoc ns-sigNameNoLoc (ClassOpSig _ ns _) = map unLoc ns-sigNameNoLoc (PatSynSig n _) = [unLoc n]-sigNameNoLoc (SpecSig n _ _) = [unLoc n]-sigNameNoLoc (InlineSig n _) = [unLoc n]-sigNameNoLoc (FixSig (FixitySig ns _)) = map unLoc ns-sigNameNoLoc _ = []+sigName :: LSig GhcRn -> [IdP GhcRn]+sigName (L _ sig) = sigNameNoLoc emptyOccEnv sig -- | Was this signature given by the user?-isUserLSig :: LSig name -> Bool-isUserLSig (L _(TypeSig {})) = True-isUserLSig (L _(ClassOpSig {})) = True-isUserLSig _ = False-+isUserLSig :: forall p. UnXRec p => LSig p -> Bool+isUserLSig = isUserSig . unXRec @p isClassD :: HsDecl a -> Bool-isClassD (TyClD d) = isClassDecl d+isClassD (TyClD _ d) = isClassDecl d isClassD _ = False -isValD :: HsDecl a -> Bool-isValD (ValD _) = True-isValD _ = False+pretty :: Outputable a => DynFlags -> a -> String+pretty = showPpr +-- --------------------------------------------------------------------- -declATs :: HsDecl a -> [a]-declATs (TyClD d) | isClassDecl d = map (unL . fdLName . unL) $ tcdATs d-declATs _ = []+-- These functions are duplicated from the GHC API, as they must be+-- 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 (UserTyVar _ _ name) = unXRec @n name+hsTyVarBndrName (KindedTyVar _ _ name _) = unXRec @n name -pretty :: Outputable a => DynFlags -> a -> String-pretty = showPpr+hsTyVarNameI :: HsTyVarBndr flag DocNameI -> DocName+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++hsSigTypeI :: LHsSigType DocNameI -> LHsType DocNameI+hsSigTypeI = sig_body . unLoc++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+mkHsForAllInvisTeleI 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 }++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 noHsUniTok) 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]+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++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++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)))+ 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 })++ 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++lHsQTyVarsToTypes :: LHsQTyVars GhcRn -> [LHsTypeArg GhcRn]+lHsQTyVarsToTypes tvs+ = [ HsValArg $ 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) })+ _ -> decl++restrictDataDefn :: [Name] -> HsDataDefn GhcRn -> HsDataDefn GhcRn+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)++restrictCons :: MonadFail m => [Name] -> m (LConDecl GhcRn) -> m (LConDecl GhcRn)+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) })+ -- 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 (field_types $ unLoc fields) })+ -- see above+ where+ 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 ]++ -------------------------------------------------------------------------------+-- * 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+ deriving (Eq, Ord)++-- | Add in extra 'HsParTy' where needed to ensure that what would be printed+-- out using 'ppr' has enough parentheses to be re-parsed properly.+--+-- 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 = 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...+ 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+++-- | 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 = mapXRec @a reparenType++-- | Add parentheses around the types in an 'HsSigType' (see 'reparenTypePrec')+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 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 (HsForAllVis x bndrs) =+ HsForAllVis x (map (mapXRec @a reparenTyVar) bndrs)+reparenHsForAllTelescope (HsForAllInvis x bndrs) =+ HsForAllInvis x (map (mapXRec @a reparenTyVar) 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 (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 (ConDeclField x n t d) = ConDeclField x n (reparenLType t) d+reparenConDeclField c@XConDeclField{} = c+++------------------------------------------------------------------------------- -- * Located ------------------------------------------------------------------------------- -unL :: Located a -> a+unL :: GenLocated l a -> a unL (L _ x) = x --reL :: a -> Located a+reL :: a -> GenLocated l a reL = L undefined +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 Name) where+instance NamedThing (TyClDecl GhcRn) where getName = tcdName -------------------------------------------------------------------------------@@ -163,20 +463,19 @@ children :: a -> [Name] -instance Parent (ConDecl Name) where+instance Parent (ConDecl GhcRn) where children con =- case getConDetails con of- RecCon fields -> map (selectorFieldOcc . unL) $- concatMap (cd_fld_names . unL) (unL fields)- _ -> []+ case getRecConArgs_maybe con of+ Nothing -> []+ Just flds -> map (foExt . unLoc) $ concatMap (cd_fld_names . unLoc) (unLoc flds) -instance Parent (TyClDecl Name) where+instance Parent (TyClDecl GhcRn) where children d- | isDataDecl d = map unL $ concatMap (getConNames . unL)- $ (dd_cons . tcdDataDefn) $ d+ | isDataDecl d = map unLoc $ concatMap (toList . getConNames . unLoc)+ $ (dd_cons . tcdDataDefn) d | isClassDecl d =- map (unL . fdLName . unL) (tcdATs d) ++- [ unL n | L _ (TypeSig ns _) <- tcdSigs d, n <- ns ]+ map (unLoc . fdLName . unLoc) (tcdATs d) +++ [ unLoc n | L _ (TypeSig _ ns _) <- tcdSigs d, n <- ns ] | otherwise = [] @@ -185,26 +484,26 @@ family = getName &&& children -familyConDecl :: ConDecl Name -> [(Name, [Name])]-familyConDecl d = zip (map unL (getConNames d)) (repeat $ children d)+familyConDecl :: ConDecl GHC.GhcRn -> [(Name, [Name])]+familyConDecl d = zip (toList $ unLoc <$> getConNames d) (repeat $ children d) -- | A mapping from the parent (main-binder) to its children and from each -- child to its grand-children, recursively.-families :: TyClDecl Name -> [(Name, [Name])]+families :: TyClDecl GhcRn -> [(Name, [Name])] families d- | isDataDecl d = family d : concatMap (familyConDecl . unL) (dd_cons (tcdDataDefn d))+ | isDataDecl d = family d : concatMap (familyConDecl . unLoc) (dd_cons (tcdDataDefn d)) | isClassDecl d = [family d] | otherwise = [] -- | A mapping from child to parent-parentMap :: TyClDecl Name -> [(Name, Name)]+parentMap :: TyClDecl GhcRn -> [(Name, Name)] parentMap d = [ (c, p) | (p, cs) <- families d, c <- cs ] -- | The parents of a subordinate in a declaration-parents :: Name -> HsDecl Name -> [Name]-parents n (TyClD d) = [ p | (c, p) <- parentMap d, c == n ]+parents :: Name -> HsDecl GhcRn -> [Name]+parents n (TyClD _ d) = [ p | (c, p) <- parentMap d, c == n ] parents _ _ = [] @@ -220,28 +519,259 @@ return () --- | A variant of 'gbracket' where the return value from the first computation--- is not required.-gbracket_ :: ExceptionMonad m => m a -> m b -> m c -> m c-gbracket_ before_ after thing = gbracket before_ (const after) (const thing)+-------------------------------------------------------------------------------+-- * DynFlags+------------------------------------------------------------------------------- --- Extract the minimal complete definition of a Name, if one exists-minimalDef :: GhcMonad m => Name -> m (Maybe ClassMinimalDef)-minimalDef n = do- mty <- lookupGlobalName n- case mty of- Just (ATyCon (tyConClass_maybe -> Just c)) -> return . Just $ classMinimalDef c- _ -> return Nothing+-- 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+-- * 'StringBuffer' and 'ByteString' -------------------------------------------------------------------------------+-- We get away with a bunch of these functions because 'StringBuffer' and+-- 'ByteString' have almost exactly the same structure. +-- | Convert a UTF-8 encoded 'ByteString' into a 'StringBuffer. This really+-- relies on the internals of both 'ByteString' and 'StringBuffer'.+--+-- /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 } -setObjectDir, setHiDir, setStubDir, setOutputDir :: String -> DynFlags -> DynFlags-setObjectDir f d = d{ objectDir = Just f}-setHiDir f d = d{ hiDir = Just f}-setStubDir f d = d{ stubDir = Just f, includePaths = f : includePaths d }- -- -stubdir D adds an implicit -I D, so that gcc can find the _stub.h file- -- \#included from the .hc file when compiling with -fvia-C.-setOutputDir f = setObjectDir f . setHiDir f . setStubDir f+-- | Take the first @n@ /bytes/ of the 'StringBuffer' and put them in a+-- 'ByteString'.+--+-- /O(1)/+takeStringBuffer :: Int -> StringBuffer -> ByteString+takeStringBuffer !n (S.StringBuffer fp _ cur) = BS.PS fp cur n++-- | Return the prefix of the first 'StringBuffer' that /isn't/ in the second+-- 'StringBuffer'. **The behavior is undefined if the 'StringBuffers' use+-- separate buffers.**+--+-- /O(1)/+splitStringBuffer :: StringBuffer -> StringBuffer -> ByteString+splitStringBuffer buf1 buf2 = takeStringBuffer n buf1+ 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.+--+-- /O(n)/ (but /O(1)/ space)+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)++-- | 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 !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)++-- | Try to parse a line of CPP from the from of the buffer. A \"line\" of CPP+-- consists of+--+-- * at most 10 whitespace characters, including at least one newline+-- * a @#@ character+-- * keep parsing lines until you find a line not ending in @\\@.+--+-- This is chock full of heuristics about what a line of CPP is.+--+-- /O(n)/ (but /O(1)/ space)+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'++-------------------------------------------------------------------------------+-- * Names in a 'Type'+-------------------------------------------------------------------------------++-- | Given a 'Type', return a set of 'Name's coming from the 'TyCon's within+-- the type.+typeNames :: Type -> Set.Set Name+typeNames ty = go ty Set.empty+ where+ go :: Type -> Set.Set Name -> Set.Set Name+ go t acc =+ case t of+ 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++-------------------------------------------------------------------------------+-- * 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+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'.+--+-- For example, 'tyCoVarsOfTypeList' reports an incorrect order for the type+-- of 'const :: a -> b -> a':+--+-- >>> import GHC.Types.Name+-- >>> import TyCoRep+-- >>> import GHC.Builtin.Types.Prim+-- >>> import GHC.Types.Var+-- >>> a = TyVarTy alphaTyVar+-- >>> b = TyVarTy betaTyVar+-- >>> constTy = mkFunTys [a, b] a+-- >>> map (getOccString . tyVarName) (tyCoVarsOfTypeList constTy)+-- ["b","a"]+--+-- However, we want to reuse the very optimized traversal machinery there, so+-- so we make our own `tyCoFVsOfType'`, `tyCoFVsBndr'`, and `tyCoVarsOfTypes'`.+-- All these do differently is traverse in a different order and ignore+-- coercion variables.++-- | 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++-- | 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++-- | 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+-- 'LiftedType'. See 'defaultRuntimeRepVars' in GHC.Iface.Type the original such+-- function working over `IfaceType`'s.+defaultRuntimeRepVars :: Type -> Type+defaultRuntimeRepVars = go emptyVarEnv+ where+ 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)++ 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++fromMaybeContext :: Maybe (LHsContext DocNameI) -> HsContext DocNameI+fromMaybeContext mctxt = unLoc $ fromMaybe (noLocA []) mctxt
src/Haddock/Interface.hs view
@@ -1,3 +1,8 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE TupleSections #-} ----------------------------------------------------------------------------- -- | -- Module : Haddock.Interface@@ -28,35 +33,48 @@ -- using this environment. ----------------------------------------------------------------------------- module Haddock.Interface (- processModules+ plugin+ , processModules ) where -import Haddock.GhcUtils-import Haddock.InterfaceFile-import Haddock.Interface.Create-import Haddock.Interface.AttachInstances-import Haddock.Interface.Rename+import Haddock.GhcUtils (moduleString, pretty)+import Haddock.Interface.AttachInstances (attachInstances)+import Haddock.Interface.Create (createInterface1)+import Haddock.Interface.Rename (renameInterface)+import Haddock.InterfaceFile (InterfaceFile, ifInstalledIfaces, ifLinkEnv) import Haddock.Options hiding (verbosity) import Haddock.Types-import Haddock.Utils+import Haddock.Utils (Verbosity (..), normal, out, verbose) -import Control.Monad-import Data.List-import qualified Data.Map as Map+import Control.Monad (unless, when)+import Data.IORef (atomicModifyIORef', newIORef, readIORef, IORef)+import Data.List (foldl', isPrefixOf)+import Data.Maybe (mapMaybe)+import Data.Traversable (for)+import Text.Printf (printf)+import qualified Data.Map.Strict as Map import qualified Data.Set as Set-import Distribution.Verbosity-import System.Directory-import System.FilePath-import Text.Printf -import Digraph-import DynFlags hiding (verbosity)-import Exception import GHC hiding (verbosity)-import HscTypes-import FastString (unpackFS)+import GHC.Data.Graph.Directed+import GHC.Driver.Env+import GHC.Driver.Monad (modifySession, withTimingM)+import GHC.Driver.Session hiding (verbosity)+import GHC.HsToCore.Docs (getMainDeclBinder)+import GHC.Plugins+import GHC.Tc.Types (TcGblEnv (..), TcM)+import GHC.Tc.Utils.Env (tcLookupGlobal)+import GHC.Tc.Utils.Monad (getTopEnv)+import GHC.Unit.Module.Graph+import GHC.Utils.Error (withTiming) +#if defined(mingw32_HOST_OS)+import System.IO+import GHC.IO.Encoding.CodePage (mkLocaleEncoding)+import GHC.IO.Encoding.Failure (CodingFailureMode(TransliterateCodingFailure))+#endif+ -- | Create 'Interface's and a link environment by typechecking the list of -- modules using the GHC API and processing the resulting syntax trees. processModules@@ -68,144 +86,324 @@ -> Ghc ([Interface], LinkEnv) -- ^ Resulting list of interfaces and renaming -- environment processModules verbosity modules flags extIfaces = do+#if defined(mingw32_HOST_OS)+ -- Avoid internal error: <stderr>: hPutChar: invalid argument (invalid character)' non UTF-8 Windows+ liftIO $ hSetEncoding stdout $ mkLocaleEncoding TransliterateCodingFailure+ liftIO $ hSetEncoding stderr $ mkLocaleEncoding TransliterateCodingFailure+#endif + dflags <- getDynFlags+ out verbosity verbose "Creating interfaces..."- let instIfaceMap = Map.fromList [ (instMod iface, iface) | ext <- extIfaces- , iface <- ifInstalledIfaces ext ]- interfaces <- createIfaces0 verbosity modules flags instIfaceMap ++ -- Map from a module to a corresponding installed interface+ let instIfaceMap :: InstIfaceMap+ instIfaceMap = Map.fromList+ [ (instMod iface, iface)+ | ext <- extIfaces+ , iface <- ifInstalledIfaces ext+ ]++ (interfaces, ms) <- createIfaces verbosity modules flags instIfaceMap+ let exportedNames = Set.unions $ map (Set.fromList . ifaceExports) $ filter (\i -> not $ OptHide `elem` ifaceOptions i) interfaces mods = Set.fromList $ map ifaceMod interfaces+ out verbosity verbose "Attaching instances..."- interfaces' <- attachInstances (exportedNames, mods) interfaces instIfaceMap+ interfaces' <- {-# SCC attachInstances #-}+ withTimingM "attachInstances" (const ()) $ do+ attachInstances (exportedNames, mods) interfaces instIfaceMap ms out verbosity verbose "Building cross-linking environment..." -- Combine the link envs of the external packages into one let extLinks = Map.unions (map ifLinkEnv extIfaces)- homeLinks = buildHomeLinks interfaces -- Build the environment for the home- -- package+ homeLinks = buildHomeLinks interfaces' -- Build the environment for the home+ -- package links = homeLinks `Map.union` extLinks out verbosity verbose "Renaming interfaces..."+ let warnings = Flag_NoWarnings `notElem` flags- dflags <- getDynFlags- let (interfaces'', msgs) =- runWriter $ mapM (renameInterface dflags links warnings) interfaces'- liftIO $ mapM_ putStrLn msgs+ ignoredSymbolSet = ignoredSymbols flags - return (interfaces'', homeLinks)+ interfaces'' <-+ withTimingM "renameAllInterfaces" (const ()) $+ for interfaces' $ \i -> do+ withTimingM ("renameInterface: " <+> pprModuleName (moduleName (ifaceMod i))) (const ()) $+ renameInterface dflags ignoredSymbolSet links warnings (Flag_Hoogle `elem` flags) i + return (interfaces'', homeLinks) -------------------------------------------------------------------------------- -- * Module typechecking and Interface creation -------------------------------------------------------------------------------- +createIfaces+ :: Verbosity+ -- ^ Verbosity requested by the caller+ -> [String]+ -- ^ List of modules provided as arguments to Haddock (still in FilePath+ -- format)+ -> [Flag]+ -- ^ Command line flags which Hadddock was invoked with+ -> InstIfaceMap+ -- ^ Map from module to corresponding installed interface file+ -> Ghc ([Interface], ModuleSet)+ -- ^ Resulting interfaces+createIfaces verbosity modules flags instIfaceMap = do+ -- Initialize the IORefs for the interface map and the module set+ (ifaceMapRef, moduleSetRef) <- liftIO $ do+ m <- newIORef Map.empty+ s <- newIORef emptyModuleSet+ return (m, s) -createIfaces0 :: Verbosity -> [String] -> [Flag] -> InstIfaceMap -> Ghc [Interface]-createIfaces0 verbosity modules flags instIfaceMap =- -- Output dir needs to be set before calling depanal since depanal uses it to- -- compute output file names that are stored in the DynFlags of the- -- resulting ModSummaries.- (if useTempDir then withTempOutputDir else id) $ do- modGraph <- depAnalysis- if needsTemplateHaskell modGraph then do- modGraph' <- enableCompilation modGraph- createIfaces verbosity flags instIfaceMap modGraph'- else- createIfaces verbosity flags instIfaceMap modGraph+ let+ haddockPlugin = plugin verbosity flags instIfaceMap ifaceMapRef moduleSetRef - where- useTempDir :: Bool- useTempDir = Flag_NoTmpCompDir `notElem` flags+ installHaddockPlugin :: HscEnv -> HscEnv+ installHaddockPlugin hsc_env =+ let+ old_plugins = hsc_plugins hsc_env+ new_plugins = old_plugins { staticPlugins = haddockPlugin : staticPlugins old_plugins }+ hsc_env' = hsc_env { hsc_plugins = new_plugins }+ in hscUpdateFlags (flip gopt_set Opt_PluginTrustworthy) hsc_env' + -- Note that we would rather use withTempSession but as long as we+ -- have the separate attachInstances step we need to keep the session+ -- alive to be able to find all the instances.+ modifySession installHaddockPlugin - withTempOutputDir :: Ghc a -> Ghc a- withTempOutputDir action = do- tmp <- liftIO getTemporaryDirectory- x <- liftIO getProcessID- let dir = tmp </> ".haddock-" ++ show x- modifySessionDynFlags (setOutputDir dir)- withTempDir dir action+ targets <- mapM (\filePath -> guessTarget filePath Nothing Nothing) modules+ setTargets targets + loadOk <- withTimingM "load" (const ()) $+ {-# SCC load #-} GHC.load LoadAllTargets - depAnalysis :: Ghc ModuleGraph- depAnalysis = do- targets <- mapM (\f -> guessTarget f Nothing) modules- setTargets targets- depanal [] False+ case loadOk of+ Failed ->+ throwE "Cannot typecheck modules"+ Succeeded -> do+ modGraph <- GHC.getModuleGraph + (ifaceMap, moduleSet) <- liftIO $ do+ m <- atomicModifyIORef' ifaceMapRef (Map.empty,)+ s <- atomicModifyIORef' moduleSetRef (Set.empty,)+ return (m, s) - enableCompilation :: ModuleGraph -> Ghc ModuleGraph- enableCompilation modGraph = do- let enableComp d = let platform = targetPlatform d- in d { hscTarget = defaultObjectTarget platform }- modifySessionDynFlags enableComp- -- We need to update the DynFlags of the ModSummaries as well.- let upd m = m { ms_hspp_opts = enableComp (ms_hspp_opts m) }- let modGraph' = map upd modGraph- return modGraph'+ let+ -- We topologically sort the module graph including boot files,+ -- so it should be acylic (hopefully we failed much earlier if this is not the case)+ -- We then filter out boot modules from the resultant topological sort+ --+ -- We do it this way to make 'buildHomeLinks' a bit more stable+ -- 'buildHomeLinks' depends on the topological order of its input in order+ -- to construct its result. In particular, modules closer to the bottom of+ -- the dependency chain are to be prefered for link destinations.+ --+ -- If there are cycles in the graph, then this order is indeterminate+ -- (the nodes in the cycle can be ordered in any way).+ -- While 'topSortModuleGraph' does guarantee stability for equivalent+ -- module graphs, seemingly small changes in the ModuleGraph can have+ -- big impacts on the `LinkEnv` constructed.+ --+ -- For example, suppose+ -- G1 = A.hs -> B.hs -> C.hs (where '->' denotes an import).+ --+ -- Then suppose C.hs is changed to have a cyclic dependency on A+ --+ -- G2 = A.hs -> B.hs -> C.hs -> A.hs-boot+ --+ -- For G1, `C.hs` is preferred for link destinations. However, for G2,+ -- the topologically sorted order not taking into account boot files (so+ -- C -> A) is completely indeterminate.+ -- Using boot files to resolve cycles, we end up with the original order+ -- [C, B, A] (in decreasing order of preference for links)+ --+ -- This exact case came up in testing for the 'base' package, where there+ -- is a big module cycle involving 'Prelude' on windows, but the cycle doesn't+ -- include 'Prelude' on non-windows platforms. This lead to drastically different+ -- LinkEnv's (and failing haddockHtmlTests) across the platforms+ --+ -- In effect, for haddock users this behaviour (using boot files to eliminate cycles)+ -- means that {-# SOURCE #-} imports no longer count towards re-ordering+ -- the preference of modules for linking.+ --+ -- i.e. if module A imports B, then B is preferred over A,+ -- but if module A {-# SOURCE #-} imports B, then we can't say the same.+ --+ go :: SCC ModuleGraphNode -> Maybe Module+ go (AcyclicSCC (ModuleNode _ ms))+ | NotBoot <- isBootSummary ms = Just $ ms_mod ms+ | otherwise = Nothing+ go (AcyclicSCC _) = Nothing+ go (CyclicSCC _) = error "haddock: module graph cyclic even with boot files" + ifaces :: [Interface]+ ifaces =+ [ Map.findWithDefault+ (error "haddock:iface")+ m+ ifaceMap+ | m <- mapMaybe go $ topSortModuleGraph False modGraph Nothing+ ] -createIfaces :: Verbosity -> [Flag] -> InstIfaceMap -> ModuleGraph -> Ghc [Interface]-createIfaces verbosity flags instIfaceMap mods = do- let sortedMods = flattenSCCs $ topSortModuleGraph False mods Nothing- out verbosity normal "Haddock coverage:"- (ifaces, _) <- foldM f ([], Map.empty) sortedMods- return (reverse ifaces)- where- f (ifaces, ifaceMap) modSummary = do- x <- processModule verbosity modSummary flags ifaceMap instIfaceMap- return $ case x of- Just iface -> (iface:ifaces, Map.insert (ifaceMod iface) iface ifaceMap)- Nothing -> (ifaces, ifaceMap) -- Boot modules don't generate ifaces.+ return (ifaces, moduleSet) -processModule :: Verbosity -> ModSummary -> [Flag] -> IfaceMap -> InstIfaceMap -> Ghc (Maybe Interface)-processModule verbosity modsum flags modMap instIfaceMap = do- out verbosity verbose $ "Checking module " ++ moduleString (ms_mod modsum) ++ "..."- tm <- loadModule =<< typecheckModule =<< parseModule modsum- if not $ isBootSummary modsum then do- out verbosity verbose "Creating interface..."- (interface, msg) <- runWriterGhc $ createInterface tm flags modMap instIfaceMap- liftIO $ mapM_ putStrLn msg- dflags <- getDynFlags- let (haddockable, haddocked) = ifaceHaddockCoverage interface- percentage = round (fromIntegral haddocked * 100 / fromIntegral haddockable :: Double) :: Int- modString = moduleString (ifaceMod interface)- coverageMsg = printf " %3d%% (%3d /%3d) in '%s'" percentage haddocked haddockable modString- header = case ifaceDoc interface of- Documentation Nothing _ -> False- _ -> True- undocumentedExports = [ formatName s n | ExportDecl { expItemDecl = L s n- , expItemMbDoc = (Documentation Nothing _, _)- } <- ifaceExportItems interface ]- where- formatName :: SrcSpan -> HsDecl Name -> String- formatName loc n = p (getMainDeclBinder n) ++ case loc of- RealSrcSpan rss -> " (" ++ unpackFS (srcSpanFile rss) ++ ":" ++ show (srcSpanStartLine rss) ++ ")"- _ -> ""+-- | A `Plugin` that hooks into GHC's compilation pipeline to generate Haddock+-- interfaces. Due to the plugin nature we benefit from GHC's capabilities to+-- parallelize the compilation process.+plugin+ :: Verbosity+ -- ^ Verbosity requested by the Haddock caller+ -> [Flag]+ -- ^ Command line flags which Hadddock was invoked with+ -> InstIfaceMap+ -- ^ Map from module to corresponding installed interface file+ -> IORef IfaceMap+ -- ^ The 'IORef' to write the interface map to+ -> IORef ModuleSet+ -- ^ The 'IORef' to write the module set to+ -> StaticPlugin -- the plugin to install with GHC+plugin verbosity flags instIfaceMap ifaceMapRef moduleSetRef =+ let+ processTypeCheckedResult :: ModSummary -> TcGblEnv -> TcM ()+ processTypeCheckedResult mod_summary tc_gbl_env+ -- Don't do anything for hs-boot modules+ | IsBoot <- isBootSummary mod_summary =+ pure ()+ | otherwise = do+ hsc_env <- getTopEnv+ ifaces <- liftIO $ readIORef ifaceMapRef - p [] = ""- p (x:_) = let n = pretty dflags x- ms = modString ++ "."- in if ms `isPrefixOf` n- then drop (length ms) n- else n+ (iface, modules) <-+ withTiming (hsc_logger hsc_env) "processModule1" (const ()) $+ processModule1 verbosity flags ifaces instIfaceMap hsc_env mod_summary tc_gbl_env + liftIO $ do+ atomicModifyIORef' ifaceMapRef $ \xs ->+ (Map.insert (ms_mod mod_summary) iface xs, ())++ atomicModifyIORef' moduleSetRef $ \xs ->+ (modules `unionModuleSet` xs, ())+ in+ StaticPlugin+ {+ spPlugin = PluginWithArgs+ {+ paPlugin = defaultPlugin+ {+ renamedResultAction = keepRenamedSource+ , typeCheckResultAction = \_ mod_summary tc_gbl_env -> do+ processTypeCheckedResult mod_summary tc_gbl_env+ pure tc_gbl_env+ }+ , paArguments = []+ }+ }++processModule1+ :: Verbosity+ -- ^ Verbosity requested by the Haddock caller+ -> [Flag]+ -- ^ Command line flags which Hadddock was invoked with+ -> IfaceMap+ -- ^ Map from module to corresponding interface, for the modules we have+ -- already processed+ -> InstIfaceMap+ -- ^ Map from module to corresponding installed interface file+ -> HscEnv+ -> ModSummary+ -> TcGblEnv+ -> TcM (Interface, ModuleSet)+processModule1 verbosity flags ifaces inst_ifaces hsc_env mod_summary tc_gbl_env = do+ out verbosity verbose "Creating interface..."++ let+ TcGblEnv { tcg_rdr_env } = tc_gbl_env++ unit_state = hsc_units hsc_env++ !interface <- do+ logger <- getLogger+ {-# SCC createInterface #-}+ withTiming logger "createInterface" (const ()) $+ runIfM (fmap Just . tcLookupGlobal) $+ createInterface1 flags unit_state mod_summary tc_gbl_env ifaces inst_ifaces++ -- We need to keep track of which modules were somehow in scope so that when+ -- Haddock later looks for instances, it also looks in these modules too.+ --+ -- See https://github.com/haskell/haddock/issues/469.+ let+ mods :: ModuleSet+ !mods = mkModuleSet+ [ nameModule name+ | gre <- globalRdrEnvElts tcg_rdr_env+ , let name = greMangledName gre+ , nameIsFromExternalPackage (hsc_home_unit hsc_env) name+ , isTcOcc (nameOccName name) -- Types and classes only+ , unQualOK gre -- In scope unqualified+ ]++ dflags <- getDynFlags++ let+ (haddockable, haddocked) =+ ifaceHaddockCoverage interface++ percentage :: Int+ percentage = div (haddocked * 100) haddockable++ modString :: String+ modString = moduleString (ifaceMod interface)++ coverageMsg :: String+ coverageMsg =+ printf " %3d%% (%3d /%3d) in '%s'" percentage haddocked haddockable modString++ header :: Bool+ header = case ifaceDoc interface of+ Documentation Nothing _ -> False+ _ -> True++ undocumentedExports :: [String]+ undocumentedExports =+ [ formatName (locA s) n+ | ExportDecl ExportD+ { expDDecl = L s n+ , expDMbDoc = (Documentation Nothing _, _)+ } <- ifaceExportItems interface+ ]+ where+ formatName :: SrcSpan -> HsDecl GhcRn -> String+ formatName loc n = p (getMainDeclBinder emptyOccEnv n) ++ case loc of+ RealSrcSpan rss _ -> " (" ++ unpackFS (srcSpanFile rss) ++ ":" +++ show (srcSpanStartLine rss) ++ ")"+ _ -> ""++ p :: Outputable a => [a] -> String+ p [] = ""+ p (x:_) = let n = pretty dflags x+ ms = modString ++ "."+ in if ms `isPrefixOf` n+ then drop (length ms) n+ else n++ when (OptHide `notElem` ifaceOptions interface) $ do out verbosity normal coverageMsg when (Flag_NoPrintMissingDocs `notElem` flags && not (null undocumentedExports && header)) $ do out verbosity normal " Missing documentation for:" unless header $ out verbosity normal " Module header" mapM_ (out verbosity normal . (" " ++)) undocumentedExports- interface' <- liftIO $ evaluate interface- return (Just interface')- else- return Nothing + pure (interface, mods) + -------------------------------------------------------------------------------- -- * Building of cross-linking environment --------------------------------------------------------------------------------@@ -220,25 +418,17 @@ -- The interfaces are passed in in topologically sorted order, but we start -- by reversing the list so we can do a foldl. buildHomeLinks :: [Interface] -> LinkEnv-buildHomeLinks ifaces = foldl upd Map.empty (reverse ifaces)+buildHomeLinks ifaces = foldl' upd Map.empty (reverse ifaces) where upd old_env iface- | OptHide `elem` ifaceOptions iface = old_env+ | OptHide `elem` ifaceOptions iface =+ old_env | OptNotHome `elem` ifaceOptions iface =- foldl' keep_old old_env exported_names- | otherwise = foldl' keep_new old_env exported_names+ foldl' keep_old old_env exported_names+ | otherwise =+ foldl' keep_new old_env exported_names where- exported_names = ifaceVisibleExports iface ++ map getName (ifaceInstances iface)+ exported_names = ifaceVisibleExports iface ++ map haddockClsInstName (ifaceInstances iface) mdl = ifaceMod iface keep_old env n = Map.insertWith (\_ old -> old) n mdl env keep_new env n = Map.insert n mdl env-------------------------------------------------------------------------------------- * Utils------------------------------------------------------------------------------------withTempDir :: (ExceptionMonad m) => FilePath -> m a -> m a-withTempDir dir = gbracket_ (liftIO $ createDirectory dir)- (liftIO $ removeDirectoryRecursive dir)
src/Haddock/Interface/AttachInstances.hs view
@@ -1,4 +1,7 @@-{-# LANGUAGE CPP, MagicHash #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE BangPatterns #-}+{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}+{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} ----------------------------------------------------------------------------- -- | -- Module : Haddock.Interface.AttachInstances@@ -11,113 +14,168 @@ -- Stability : experimental -- Portability : portable ------------------------------------------------------------------------------module Haddock.Interface.AttachInstances (attachInstances) where+module Haddock.Interface.AttachInstances (attachInstances, instHead) where -import Haddock.Types import Haddock.Convert-import Haddock.GhcUtils+import Haddock.GhcUtils (typeNames)+import Haddock.Types +import Control.Applicative ((<|>)) import Control.Arrow hiding ((<+>))-import Data.List+import Control.DeepSeq (force)+import Data.Foldable (foldl')+import Data.List (sortBy) import Data.Ord (comparing)-import Data.Function (on)-import Data.Maybe ( maybeToList, mapMaybe )-import qualified Data.Map as Map+import Data.Maybe ( maybeToList, mapMaybe, fromMaybe )+import qualified Data.Map.Strict as Map import qualified Data.Set as Set -import Class-import DynFlags-import CoreSyn (isOrphan)-import ErrUtils-import FamInstEnv-import FastString+import GHC.Data.FastString (unpackFS)+import GHC.Core.Class+import GHC.Core.FamInstEnv import GHC-import GhcMonad (withSession)-import InstEnv-import MonadUtils (liftIO)-import Name-import Outputable (text, sep, (<+>))-import PrelNames-import SrcLoc-import TcRnDriver (tcRnGetInfo)-import TyCon-import TyCoRep-import TysPrim( funTyCon )-import Var hiding (varName)-#define FSLIT(x) (mkFastString# (x#))+import GHC.Core.InstEnv+import GHC.Unit.Module.Env ( ModuleSet, moduleSetElts )+import GHC.Types.Name+import GHC.Types.Name.Env+import GHC.Utils.Outputable (text, sep, (<+>))+import GHC.Types.SrcLoc+import GHC.Core.TyCon+import GHC.Core.TyCo.Rep+import GHC.Builtin.Types( unrestrictedFunTyConName )+import GHC.Types.Var hiding (varName)+import GHC.HsToCore.Docs type ExportedNames = Set.Set Name type Modules = Set.Set Module type ExportInfo = (ExportedNames, Modules) -- Also attaches fixities-attachInstances :: ExportInfo -> [Interface] -> InstIfaceMap -> Ghc [Interface]-attachInstances expInfo ifaces instIfaceMap = mapM attach ifaces+attachInstances :: ExportInfo -> [Interface] -> InstIfaceMap -> ModuleSet -> Ghc [Interface]+attachInstances expInfo ifaces instIfaceMap mods = do+ (_msgs, mb_index) <- getNameToInstancesIndex (map ifaceMod ifaces) mods'+ mapM (attach $ fromMaybe emptyNameEnv mb_index) ifaces where+ mods' = Just (moduleSetElts mods)+ -- TODO: take an IfaceMap as input ifaceMap = Map.fromList [ (ifaceMod i, i) | i <- ifaces ] - attach iface = do- newItems <- mapM (attachToExportItem expInfo iface ifaceMap instIfaceMap)+ attach index iface = do++ let getInstDoc = findInstDoc iface ifaceMap instIfaceMap+ getFixity = findFixity iface ifaceMap instIfaceMap++ newItems <- mapM (attachToExportItem index expInfo getInstDoc getFixity) (ifaceExportItems iface)- let orphanInstances = attachOrphanInstances expInfo iface ifaceMap instIfaceMap (ifaceInstances iface)+ let orphanInstances = attachOrphanInstances expInfo getInstDoc (ifaceInstances iface) return $ iface { ifaceExportItems = newItems , ifaceOrphanInstances = orphanInstances } -attachOrphanInstances :: ExportInfo -> Interface -> IfaceMap -> InstIfaceMap -> [ClsInst] -> [DocInstance Name]-attachOrphanInstances expInfo iface ifaceMap instIfaceMap cls_instances =- [ (synifyInstHead i, instLookup instDocMap n iface ifaceMap instIfaceMap, (L (getSrcSpan n) n))- | 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 cls tys+attachOrphanInstances+ :: ExportInfo+ -> (Name -> Maybe (MDoc Name)) -- ^ how to lookup the doc of an instance+ -> [HaddockClsInst] -- ^ a list of instances+ -> [DocInstance GhcRn]+attachOrphanInstances expInfo getInstDoc cls_instances =+ [ (synified, getInstDoc instName, (L (getSrcSpan instName) instName), Nothing)+ | let is =+ [ ( haddockClsInstHead i+ , haddockClsInstSynified i+ , haddockClsInstName i+ , haddockClsInstClsName i+ , haddockClsInstTyNames i+ )+ | i <- cls_instances, haddockClsInstIsOrphan i+ ]+ , (_, synified, instName, cls, tyNames) <- sortBy (comparing $ (\(ih,_,_,_,_) -> ih)) is+ , not $ isInstanceHidden expInfo cls tyNames ] -attachToExportItem :: ExportInfo -> Interface -> IfaceMap -> InstIfaceMap- -> ExportItem Name- -> Ghc (ExportItem Name)-attachToExportItem expInfo iface ifaceMap instIfaceMap export =+attachToExportItem+ :: NameEnv ([ClsInst], [FamInst]) -- ^ all instances (that we know of)+ -> ExportInfo+ -> (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 index expInfo getInstDoc getFixity export = case attachFixities export of- e@ExportDecl { expItemDecl = L eSpan (TyClD d) } -> do- mb_info <- getAllInfo (tcdName d)- insts <- case mb_info of- Just (_, _, cls_instances, fam_instances) ->- let fam_insts = [ (synifyFamInst i opaque, doc,spanNameE n (synifyFamInst i opaque) (L eSpan (tcdName d)) )- | i <- sortBy (comparing instFam) fam_instances- , let n = getName i- , let doc = instLookup instDocMap n iface ifaceMap instIfaceMap- , not $ isNameHidden expInfo (fi_fam i)- , not $ any (isTypeHidden expInfo) (fi_tys i)- , let opaque = isTypeHidden expInfo (fi_rhs i)- ]- cls_insts = [ (synifyInstHead i, instLookup instDocMap n iface ifaceMap instIfaceMap, spanName n (synifyInstHead i) (L eSpan (tcdName d)))- | let is = [ (instanceSig i, getName i) | i <- cls_instances ]- , (i@(_,_,cls,tys), n) <- sortBy (comparing $ first instHead) is- , not $ isInstanceHidden expInfo cls tys- ]+ ExportDecl e@(ExportD { expDDecl = L eSpan (TyClD _ d) }) -> do+ insts <-+ let mb_instances = lookupNameEnv index (tcdName d)+ cls_instances = maybeToList mb_instances >>= fst+ fam_instances = maybeToList mb_instances >>= snd+ 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)+ , let synFamInst = synifyFamInst i opaque+ , let !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)+ (foldl' (\acc t -> acc `Set.union` typeNames t) Set.empty tys)+ , let synClsInst = synifyInstHead i+ , let !mb_mdl = force $ nameModule_maybe n+ ] -- fam_insts but with failing type fams filtered out- cleanFamInsts = [ (fi, n, L l r) | (Right fi, n, L l (Right r)) <- fam_insts ]- famInstErrs = [ errm | (Left errm, _, _) <- fam_insts ]- in do- dfs <- getDynFlags- let mkBug = (text "haddock-bug:" <+>) . text- liftIO $ putMsg dfs (sep $ map mkBug famInstErrs)- return $ cls_insts ++ cleanFamInsts- Nothing -> return []- return $ e { expItemInstances = insts }+ 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 e@ExportDecl{ expItemDecl = L _ d } = e { expItemFixities =- nubBy ((==) `on` fst) $ expItemFixities e ++- [ (n',f) | n <- getMainDeclBinder d- , Just subs <- [instLookup instSubMap n iface ifaceMap instIfaceMap]- , n' <- n : subs- , Just f <- [instLookup instFixMap n' iface ifaceMap instIfaceMap]- ] }+ attachFixities+ ( 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+ 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@@ -131,60 +189,48 @@ let L l r = spanName s ok linst in L l (Right r) --instLookup :: (InstalledInterface -> Map.Map Name a) -> Name- -> Interface -> IfaceMap -> InstIfaceMap -> Maybe a-instLookup f name iface ifaceMap instIfaceMap =- case Map.lookup name (f $ toInstalledIface iface) of- res@(Just _) -> res- Nothing -> do- let ifaceMaps = Map.union (fmap toInstalledIface ifaceMap) instIfaceMap- iface' <- Map.lookup (nameModule name) ifaceMaps- Map.lookup name (f iface')+-- | 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) --- | Like GHC's getInfo but doesn't cut things out depending on the--- interative context, which we don't set sufficiently anyway.-getAllInfo :: GhcMonad m => Name -> m (Maybe (TyThing,Fixity,[ClsInst],[FamInst]))-getAllInfo name = withSession $ \hsc_env -> do- (_msgs, r) <- liftIO $ tcRnGetInfo hsc_env name- return r+-- | 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) -------------------------------------------------------------------------------- -- Collecting and sorting instances -------------------------------------------------------------------------------- ---- | Simplified type for sorting types, ignoring qualification (not visible--- 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 Name [SimpleType]- | SimpleTyLit TyLit- deriving (Eq,Ord)---instHead :: ([TyVar], [PredType], Class, [Type]) -> ([Int], Name, [SimpleType])+instHead :: ([TyVar], [PredType], Class, [Type]) -> ([Int], SName, [SimpleType]) instHead (_, _, cls, args)- = (map argCount args, className cls, map simplify 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 (ForAllTy (Anon _) _ ) = 2-argCount (ForAllTy _ t) = argCount t-argCount (CastTy t _) = argCount t+argCount (FunTy _ _ _ _) = 2+argCount (ForAllTy _ t) = argCount t+argCount (CastTy t _) = argCount t argCount _ = 0 simplify :: Type -> SimpleType-simplify (ForAllTy (Anon t1) t2) = SimpleType funTyConName [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-simplify (TyVarTy v) = SimpleType (tyVarName v) []-simplify (TyConApp tc ts) = SimpleType (tyConName tc)+simplify (TyVarTy v) = SimpleType (SName (tyVarName v)) []+simplify (TyConApp tc ts) = SimpleType (SName (tyConName tc)) (mapMaybe simplify_maybe ts)-simplify (LitTy l) = SimpleTyLit l+simplify (LitTy (NumTyLit n)) = SimpleIntTyLit n+simplify (LitTy (StrTyLit s)) = SimpleStringTyLit (unpackFS s)+simplify (LitTy (CharTyLit c)) = SimpleCharTyLit c simplify (CastTy ty _) = simplify ty simplify (CoercionTy _) = error "simplify:Coercion" @@ -193,18 +239,11 @@ simplify_maybe ty = Just (simplify ty) -- Used for sorting-instFam :: FamInst -> ([Int], Name, [SimpleType], Int, SimpleType)+instFam :: FamInst -> ([Int], SName, [SimpleType], Int, SimpleType) instFam FamInst { fi_fam = n, fi_tys = ts, fi_rhs = t }- = (map argCount ts, n, map simplify ts, argCount t, simplify t)+ = (map argCount ts, SName n, map simplify ts, argCount t, simplify t) -funTyConName :: Name-funTyConName = mkWiredInName gHC_PRIM- (mkOccNameFS tcName FSLIT("(->)"))- funTyConKey- (ATyCon funTyCon) -- Relevant TyCon- BuiltInSyntax- -------------------------------------------------------------------------------- -- Filtering hidden instances --------------------------------------------------------------------------------@@ -221,29 +260,21 @@ -- | We say that an instance is «hidden» iff its class or any (part) -- of its type(s) is hidden.-isInstanceHidden :: ExportInfo -> Class -> [Type] -> Bool-isInstanceHidden expInfo cls tys =+isInstanceHidden :: ExportInfo -> Name -> Set.Set Name -> Bool+isInstanceHidden expInfo cls tyNames = instClassHidden || instTypeHidden where instClassHidden :: Bool- instClassHidden = isNameHidden expInfo $ getName cls+ instClassHidden = isNameHidden expInfo cls instTypeHidden :: Bool- instTypeHidden = any (isTypeHidden expInfo) tys+ instTypeHidden = any (isNameHidden expInfo) tyNames isTypeHidden :: ExportInfo -> Type -> Bool isTypeHidden expInfo = typeHidden where typeHidden :: Type -> Bool- typeHidden t =- case t of- TyVarTy {} -> False- AppTy t1 t2 -> typeHidden t1 || typeHidden t2- TyConApp tcon args -> nameHidden (getName tcon) || any typeHidden args- ForAllTy bndr ty -> typeHidden (binderType bndr) || typeHidden ty- LitTy _ -> False- CastTy ty _ -> typeHidden ty- CoercionTy {} -> False+ typeHidden t = any nameHidden $ typeNames t nameHidden :: Name -> Bool nameHidden = isNameHidden expInfo
src/Haddock/Interface/Create.hs view
@@ -1,900 +1,1276 @@-{-# LANGUAGE CPP, TupleSections, BangPatterns, LambdaCase #-}-{-# OPTIONS_GHC -Wwarn #-}--------------------------------------------------------------------------------- |--- Module : Haddock.Interface.Create--- Copyright : (c) Simon Marlow 2003-2006,--- David Waern 2006-2009,--- Mateusz Kowalczyk 2013--- License : BSD-like------ Maintainer : haddock@projects.haskell.org--- Stability : experimental--- Portability : portable-------------------------------------------------------------------------------module Haddock.Interface.Create (createInterface) where--import Documentation.Haddock.Doc (metaDocAppend)-import Haddock.Types-import Haddock.Options-import Haddock.GhcUtils-import Haddock.Utils-import Haddock.Convert-import Haddock.Interface.LexParseRn-import Haddock.Backends.Hyperlinker.Types-import Haddock.Backends.Hyperlinker.Ast as Hyperlinker-import Haddock.Backends.Hyperlinker.Parser as Hyperlinker--import qualified Data.Map as M-import Data.Map (Map)-import Data.List-import Data.Maybe-import Data.Monoid-import Data.Ord-import Control.Applicative-import Control.Arrow (second)-import Control.DeepSeq-import Control.Monad-import Data.Function (on)--import qualified Packages-import qualified Module-import qualified SrcLoc-import GHC-import HscTypes-import Name-import Bag-import RdrName-import TcRnTypes-import FastString (concatFS)-import BasicTypes ( StringLiteral(..) )-import qualified Outputable as O-import HsDecls ( getConDetails )---- | Use a 'TypecheckedModule' to produce an 'Interface'.--- To do this, we need access to already processed modules in the topological--- sort. That's what's in the 'IfaceMap'.-createInterface :: TypecheckedModule -> [Flag] -> IfaceMap -> InstIfaceMap -> ErrMsgGhc Interface-createInterface tm flags modMap instIfaceMap = do-- let ms = pm_mod_summary . tm_parsed_module $ tm- mi = moduleInfo tm- L _ hsm = parsedSource tm- !safety = modInfoSafe mi- mdl = ms_mod ms- dflags = ms_hspp_opts ms- !instances = modInfoInstances mi- !fam_instances = md_fam_insts md- !exportedNames = modInfoExports mi-- (TcGblEnv {tcg_rdr_env = gre, tcg_warns = warnings}, md) = tm_internals_ tm-- -- The renamed source should always be available to us, but it's best- -- to be on the safe side.- (group_, mayExports, mayDocHeader) <-- case renamedSource tm of- Nothing -> do- liftErrMsg $ tell [ "Warning: Renamed source is not available." ]- return (emptyRnGroup, Nothing, Nothing)- Just (x, _, y, z) -> return (x, y, z)-- opts0 <- liftErrMsg $ mkDocOpts (haddockOptions dflags) flags mdl- let opts- | Flag_IgnoreAllExports `elem` flags = OptIgnoreExports : opts0- | otherwise = opts0-- (!info, mbDoc) <- liftErrMsg $ processModuleHeader dflags gre safety mayDocHeader-- let declsWithDocs = topDecls group_- fixMap = mkFixMap group_- (decls, _) = unzip declsWithDocs- localInsts = filter (nameIsLocalOrFrom mdl) $ map getName instances- ++ map getName fam_instances- -- Locations of all TH splices- splices = [ l | L l (SpliceD _) <- hsmodDecls hsm ]-- maps@(!docMap, !argMap, !subMap, !declMap, _) =- mkMaps dflags gre localInsts declsWithDocs-- let exports0 = fmap (reverse . map unLoc) mayExports- exports- | OptIgnoreExports `elem` opts = Nothing- | otherwise = exports0- warningMap = mkWarningMap dflags warnings gre exportedNames-- let allWarnings = M.unions (warningMap : map ifaceWarningMap (M.elems modMap))-- exportItems <- mkExportItems modMap mdl allWarnings gre exportedNames decls- maps fixMap splices exports instIfaceMap dflags-- let !visibleNames = mkVisibleNames maps exportItems opts-- -- Measure haddock documentation coverage.- let prunedExportItems0 = pruneExportItems exportItems- !haddockable = 1 + length exportItems -- module + exports- !haddocked = (if isJust mbDoc then 1 else 0) + length prunedExportItems0- !coverage = (haddockable, haddocked)-- -- Prune the export list to just those declarations that have- -- documentation, if the 'prune' option is on.- let prunedExportItems'- | OptPrune `elem` opts = prunedExportItems0- | otherwise = exportItems- !prunedExportItems = seqList prunedExportItems' `seq` prunedExportItems'-- let !aliases =- mkAliasMap dflags $ tm_renamed_source tm- modWarn = moduleWarning dflags gre warnings-- tokenizedSrc <- mkMaybeTokenizedSrc flags tm-- return $! Interface {- ifaceMod = mdl- , ifaceOrigFilename = msHsFilePath ms- , ifaceInfo = info- , ifaceDoc = Documentation mbDoc modWarn- , ifaceRnDoc = Documentation Nothing Nothing- , ifaceOptions = opts- , ifaceDocMap = docMap- , ifaceArgMap = argMap- , ifaceRnDocMap = M.empty- , ifaceRnArgMap = M.empty- , ifaceExportItems = prunedExportItems- , ifaceRnExportItems = []- , ifaceExports = exportedNames- , ifaceVisibleExports = visibleNames- , ifaceDeclMap = declMap- , ifaceSubMap = subMap- , ifaceFixMap = fixMap- , ifaceModuleAliases = aliases- , ifaceInstances = instances- , ifaceFamInstances = fam_instances- , ifaceOrphanInstances = [] -- Filled in `attachInstances`- , ifaceRnOrphanInstances = [] -- Filled in `renameInterface`- , ifaceHaddockCoverage = coverage- , ifaceWarningMap = warningMap- , ifaceTokenizedSrc = tokenizedSrc- }--mkAliasMap :: DynFlags -> Maybe RenamedSource -> M.Map Module ModuleName-mkAliasMap dflags mRenamedSource =- case mRenamedSource of- Nothing -> M.empty- Just (_,impDecls,_,_) ->- M.fromList $- mapMaybe (\(SrcLoc.L _ impDecl) -> do- alias <- ideclAs impDecl- return $- (lookupModuleDyn dflags- (fmap Module.fsToUnitId $- fmap sl_fs $ ideclPkgQual impDecl)- (case ideclName impDecl of SrcLoc.L _ name -> name),- alias))- impDecls---- similar to GHC.lookupModule-lookupModuleDyn ::- DynFlags -> Maybe UnitId -> ModuleName -> Module-lookupModuleDyn _ (Just pkgId) mdlName =- Module.mkModule pkgId mdlName-lookupModuleDyn dflags Nothing mdlName =- case Packages.lookupModuleInAllPackages dflags mdlName of- (m,_):_ -> m- [] -> Module.mkModule Module.mainUnitId mdlName------------------------------------------------------------------------------------- Warnings----------------------------------------------------------------------------------mkWarningMap :: DynFlags -> Warnings -> GlobalRdrEnv -> [Name] -> WarningMap-mkWarningMap dflags warnings gre exps = case warnings of- NoWarnings -> M.empty- WarnAll _ -> M.empty- WarnSome ws ->- let ws' = [ (n, w) | (occ, w) <- ws, elt <- lookupGlobalRdrEnv gre occ- , let n = gre_name elt, n `elem` exps ]- in M.fromList $ map (second $ parseWarning dflags gre) ws'--moduleWarning :: DynFlags -> GlobalRdrEnv -> Warnings -> Maybe (Doc Name)-moduleWarning _ _ NoWarnings = Nothing-moduleWarning _ _ (WarnSome _) = Nothing-moduleWarning dflags gre (WarnAll w) = Just $ parseWarning dflags gre w--parseWarning :: DynFlags -> GlobalRdrEnv -> WarningTxt -> Doc Name-parseWarning dflags gre w = force $ case w of- DeprecatedTxt _ msg -> format "Deprecated: " (concatFS $ map (sl_fs . unLoc) msg)- WarningTxt _ msg -> format "Warning: " (concatFS $ map (sl_fs . unLoc) msg)- where- format x xs = DocWarning . DocParagraph . DocAppend (DocString x)- . processDocString dflags gre $ HsDocString xs------------------------------------------------------------------------------------- Doc options------ Haddock options that are embedded in the source file-----------------------------------------------------------------------------------mkDocOpts :: Maybe String -> [Flag] -> Module -> ErrMsgM [DocOption]-mkDocOpts mbOpts flags mdl = do- opts <- case mbOpts of- Just opts -> case words $ replace ',' ' ' opts of- [] -> tell ["No option supplied to DOC_OPTION/doc_option"] >> return []- xs -> liftM catMaybes (mapM parseOption xs)- Nothing -> return []- hm <- if Flag_HideModule (moduleString mdl) `elem` flags- then return $ OptHide : opts- else return opts- if Flag_ShowExtensions (moduleString mdl) `elem` flags- then return $ OptShowExtensions : hm- else return hm---parseOption :: String -> ErrMsgM (Maybe DocOption)-parseOption "hide" = return (Just OptHide)-parseOption "prune" = return (Just OptPrune)-parseOption "ignore-exports" = return (Just OptIgnoreExports)-parseOption "not-home" = return (Just OptNotHome)-parseOption "show-extensions" = return (Just OptShowExtensions)-parseOption other = tell ["Unrecognised option: " ++ other] >> return Nothing-------------------------------------------------------------------------------------- Maps------------------------------------------------------------------------------------type Maps = (DocMap Name, ArgMap Name, SubMap, DeclMap, InstMap)---- | Create 'Maps' by looping through the declarations. For each declaration,--- find its names, its subordinates, and its doc strings. Process doc strings--- into 'Doc's.-mkMaps :: DynFlags- -> GlobalRdrEnv- -> [Name]- -> [(LHsDecl Name, [HsDocString])]- -> Maps-mkMaps dflags gre instances decls =- let (a, b, c, d) = unzip4 $ map mappings decls- in (f' $ map (nubBy ((==) `on` fst)) a , f b, f c, f d, instanceMap)- where- f :: (Ord a, Monoid b) => [[(a, b)]] -> Map a b- f = M.fromListWith (<>) . concat-- f' :: [[(Name, MDoc Name)]] -> Map Name (MDoc Name)- f' = M.fromListWith metaDocAppend . concat-- mappings :: (LHsDecl Name, [HsDocString])- -> ( [(Name, MDoc Name)]- , [(Name, Map Int (MDoc Name))]- , [(Name, [Name])]- , [(Name, [LHsDecl Name])]- )- mappings (ldecl, docStrs) =- let L l decl = ldecl- declDoc :: [HsDocString] -> Map Int HsDocString- -> (Maybe (MDoc Name), Map Int (MDoc Name))- declDoc strs m =- let doc' = processDocStrings dflags gre strs- m' = M.map (processDocStringParas dflags gre) m- in (doc', m')- (doc, args) = declDoc docStrs (typeDocs decl)- subs :: [(Name, [HsDocString], Map Int HsDocString)]- subs = subordinates instanceMap decl- (subDocs, subArgs) = unzip $ map (\(_, strs, m) -> declDoc strs m) subs- ns = names l decl- subNs = [ n | (n, _, _) <- subs ]- dm = [ (n, d) | (n, Just d) <- zip ns (repeat doc) ++ zip subNs subDocs ]- am = [ (n, args) | n <- ns ] ++ zip subNs subArgs- sm = [ (n, subNs) | n <- ns ]- cm = [ (n, [ldecl]) | n <- ns ++ subNs ]- in seqList ns `seq`- seqList subNs `seq`- doc `seq`- seqList subDocs `seq`- seqList subArgs `seq`- (dm, am, sm, cm)-- instanceMap :: Map SrcSpan Name- instanceMap = M.fromList [ (getSrcSpan n, n) | n <- instances ]-- names :: SrcSpan -> HsDecl Name -> [Name]- names l (InstD d) = maybeToList (M.lookup loc instanceMap) -- See note [2].- where loc = case d of- TyFamInstD _ -> l -- The CoAx's loc is the whole line, but only for TFs- _ -> getInstLoc d- names _ decl = getMainDeclBinder decl---- Note [2]:---------------- We relate ClsInsts to InstDecls using the SrcSpans buried inside them.--- That should work for normal user-written instances (from looking at GHC--- sources). We can assume that commented instances are user-written.--- This lets us relate Names (from ClsInsts) to comments (associated--- with InstDecls).-------------------------------------------------------------------------------------- Declarations-------------------------------------------------------------------------------------- | Get all subordinate declarations inside a declaration, and their docs.-subordinates :: InstMap -> HsDecl Name -> [(Name, [HsDocString], Map Int HsDocString)]-subordinates instMap decl = case decl of- InstD (ClsInstD d) -> do- DataFamInstDecl { dfid_tycon = L l _- , dfid_defn = def } <- unLoc <$> cid_datafam_insts d- [ (n, [], M.empty) | Just n <- [M.lookup l instMap] ] ++ dataSubs def-- InstD (DataFamInstD d) -> dataSubs (dfid_defn d)- TyClD d | isClassDecl d -> classSubs d- | isDataDecl d -> dataSubs (tcdDataDefn d)- _ -> []- where- classSubs dd = [ (name, doc, typeDocs d) | (L _ d, doc) <- classDecls dd- , name <- getMainDeclBinder d, not (isValD d)- ]- dataSubs :: HsDataDefn Name -> [(Name, [HsDocString], Map Int HsDocString)]- dataSubs dd = constrs ++ fields- where- cons = map unL $ (dd_cons dd)- constrs = [ (unL cname, maybeToList $ fmap unL $ con_doc c, M.empty)- | c <- cons, cname <- getConNames c ]- fields = [ (selectorFieldOcc n, maybeToList $ fmap unL doc, M.empty)- | RecCon flds <- map getConDetails cons- , L _ (ConDeclField ns _ doc) <- (unLoc flds)- , L _ n <- ns ]---- | Extract function argument docs from inside types.-typeDocs :: HsDecl Name -> Map Int HsDocString-typeDocs d =- let docs = go 0 in- case d of- SigD (TypeSig _ ty) -> docs (unLoc (hsSigWcType ty))- SigD (PatSynSig _ ty) -> docs (unLoc (hsSigType ty))- ForD (ForeignImport _ ty _ _) -> docs (unLoc (hsSigType ty))- TyClD (SynDecl { tcdRhs = ty }) -> docs (unLoc ty)- _ -> M.empty- where- go n (HsForAllTy { hst_body = ty }) = go n (unLoc ty)- go n (HsQualTy { hst_body = ty }) = go n (unLoc ty)- go n (HsFunTy (L _ (HsDocTy _ (L _ x))) (L _ ty)) = M.insert n x $ go (n+1) ty- go n (HsFunTy _ ty) = go (n+1) (unLoc ty)- 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 Name -> [(LHsDecl Name, [HsDocString])]-classDecls class_ = filterDecls . collectDocs . sortByLoc $ decls- where- decls = docs ++ defs ++ sigs ++ ats- docs = mkDecls tcdDocs DocD class_- defs = mkDecls (bagToList . tcdMeths) ValD class_- sigs = mkDecls tcdSigs SigD class_- ats = mkDecls tcdATs (TyClD . FamDecl) class_----- | The top-level declarations of a module that we care about,--- ordered by source location, with documentation attached if it exists.-topDecls :: HsGroup Name -> [(LHsDecl Name, [HsDocString])]-topDecls = filterClasses . filterDecls . collectDocs . sortByLoc . ungroup---- | Extract a map of fixity declarations only-mkFixMap :: HsGroup Name -> FixMap-mkFixMap group_ = M.fromList [ (n,f)- | L _ (FixitySig ns f) <- hs_fixds group_,- L _ n <- ns ]----- | Take all declarations except pragmas, infix decls, rules from an 'HsGroup'.-ungroup :: HsGroup Name -> [LHsDecl Name]-ungroup group_ =- mkDecls (tyClGroupConcat . hs_tyclds) TyClD group_ ++- mkDecls hs_derivds DerivD group_ ++- mkDecls hs_defds DefD group_ ++- mkDecls hs_fords ForD group_ ++- mkDecls hs_docs DocD group_ ++- mkDecls hs_instds InstD group_ ++- mkDecls (typesigs . hs_valds) SigD group_ ++- mkDecls (valbinds . hs_valds) ValD group_- where- typesigs (ValBindsOut _ sigs) = filter isUserLSig sigs- typesigs _ = error "expected ValBindsOut"-- valbinds (ValBindsOut binds _) = concatMap bagToList . snd . unzip $ binds- valbinds _ = error "expected ValBindsOut"----- | Take a field of declarations from a data structure and create HsDecls--- using the given constructor-mkDecls :: (a -> [Located b]) -> (b -> c) -> a -> [Located c]-mkDecls field con struct = [ L loc (con decl) | L loc decl <- field struct ]----- | Sort by source location-sortByLoc :: [Located a] -> [Located a]-sortByLoc = sortBy (comparing getLoc)-------------------------------------------------------------------------------------- Filtering of declarations------ We filter out declarations that we don't intend to handle later.-------------------------------------------------------------------------------------- | Filter out declarations that we don't handle in Haddock-filterDecls :: [(LHsDecl a, doc)] -> [(LHsDecl a, doc)]-filterDecls = filter (isHandled . unL . fst)- where- isHandled (ForD (ForeignImport {})) = True- isHandled (TyClD {}) = True- isHandled (InstD {}) = True- isHandled (SigD d) = isUserLSig (reL d)- isHandled (ValD _) = True- -- we keep doc declarations to be able to get at named docs- isHandled (DocD _) = True- isHandled _ = False----- | Go through all class declarations and filter their sub-declarations-filterClasses :: [(LHsDecl a, doc)] -> [(LHsDecl a, doc)]-filterClasses decls = [ if isClassD d then (L loc (filterClass d), doc) else x- | x@(L loc d, doc) <- decls ]- where- filterClass (TyClD c) =- TyClD $ c { tcdSigs = filter (liftA2 (||) isUserLSig isMinimalLSig) $ tcdSigs c }- filterClass _ = error "expected TyClD"-------------------------------------------------------------------------------------- Collect docs------ To be able to attach the right Haddock comment to the right declaration,--- we sort the declarations by their SrcLoc and "collect" the docs for each--- declaration.-------------------------------------------------------------------------------------- | Collect docs and attach them to the right declarations.-collectDocs :: [LHsDecl a] -> [(LHsDecl a, [HsDocString])]-collectDocs = go Nothing []- where- go Nothing _ [] = []- go (Just prev) docs [] = finished prev docs []- go prev docs (L _ (DocD (DocCommentNext str)) : ds)- | Nothing <- prev = go Nothing (str:docs) ds- | Just decl <- prev = finished decl docs (go Nothing [str] ds)- go prev docs (L _ (DocD (DocCommentPrev str)) : ds) = go prev (str:docs) ds- go Nothing docs (d:ds) = go (Just d) docs ds- go (Just prev) docs (d:ds) = finished prev docs (go (Just d) [] ds)-- finished decl docs rest = (decl, reverse docs) : rest----- | 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--- original names.------ We create the export items even if the module is hidden, since they--- might be useful when creating the export items for other modules.-mkExportItems- :: IfaceMap- -> Module -- this module- -> WarningMap- -> GlobalRdrEnv- -> [Name] -- exported names (orig)- -> [LHsDecl Name]- -> Maps- -> FixMap- -> [SrcSpan] -- splice locations- -> Maybe [IE Name]- -> InstIfaceMap- -> DynFlags- -> ErrMsgGhc [ExportItem Name]-mkExportItems- modMap thisMod warnings gre exportedNames decls- maps@(docMap, argMap, subMap, declMap, instMap) fixMap splices optExports instIfaceMap dflags =- case optExports of- Nothing -> fullModuleContents dflags warnings gre maps fixMap splices decls- Just exports -> liftM concat $ mapM lookupExport exports- where- lookupExport (IEVar (L _ x)) = declWith x- lookupExport (IEThingAbs (L _ t)) = declWith t- lookupExport (IEThingAll (L _ t)) = declWith t- lookupExport (IEThingWith (L _ t) _ _ _) = declWith t- lookupExport (IEModuleContents (L _ m)) =- moduleExports thisMod m dflags warnings gre exportedNames decls modMap instIfaceMap maps fixMap splices- lookupExport (IEGroup lev docStr) = return $- return . ExportGroup lev "" $ processDocString dflags gre docStr-- lookupExport (IEDoc docStr) = return $- return . ExportDoc $ processDocStringParas dflags gre docStr-- lookupExport (IEDocNamed str) = liftErrMsg $- findNamedDoc str [ unL d | d <- decls ] >>= return . \case- Nothing -> []- Just doc -> return . ExportDoc $ processDocStringParas dflags gre doc-- declWith :: Name -> ErrMsgGhc [ ExportItem Name ]- declWith t =- case findDecl t of- ([L l (ValD _)], (doc, _)) -> do- -- Top-level binding without type signature- export <- hiValExportItem dflags t l doc (l `elem` splices) $ M.lookup t fixMap- return [export]- (ds, docs_) | decl : _ <- filter (not . isValD . unLoc) ds ->- let declNames = getMainDeclBinder (unL decl)- in case () of- _- -- TODO: temp hack: we filter out separately exported ATs, since we haven't decided how- -- to handle them yet. We should really give an warning message also, and filter the- -- name out in mkVisibleNames...- | t `elem` declATs (unL decl) -> return []-- -- We should not show a subordinate by itself if any of its- -- parents is also exported. See note [1].- | t `notElem` declNames,- Just p <- find isExported (parents t $ unL decl) ->- do liftErrMsg $ tell [- "Warning: " ++ moduleString thisMod ++ ": " ++- pretty dflags (nameOccName t) ++ " is exported separately but " ++- "will be documented under " ++ pretty dflags (nameOccName p) ++- ". Consider exporting it together with its parent(s)" ++- " for code clarity." ]- return []-- -- normal case- | otherwise -> case decl of- -- A single signature might refer to many names, but we- -- create an export item for a single name only. So we- -- modify the signature to contain only that single name.- L loc (SigD sig) ->- -- fromJust is safe since we already checked in guards- -- that 't' is a name declared in this declaration.- let newDecl = L loc . SigD . fromJust $ filterSigNames (== t) sig- in return [ mkExportDecl t newDecl docs_ ]-- L loc (TyClD cl@ClassDecl{}) -> do- mdef <- liftGhcToErrMsgGhc $ minimalDef t- let sig = maybeToList $ fmap (noLoc . MinimalSig mempty . noLoc . fmap noLoc) mdef- return [ mkExportDecl t- (L loc $ TyClD cl { tcdSigs = sig ++ tcdSigs cl }) docs_ ]-- _ -> return [ mkExportDecl t decl docs_ ]-- -- Declaration from another package- ([], _) -> do- mayDecl <- hiDecl dflags t- case mayDecl of- Nothing -> return [ ExportNoDecl t [] ]- Just decl ->- -- We try to get the subs and docs- -- from the installed .haddock file for that package.- case M.lookup (nameModule t) instIfaceMap of- Nothing -> do- liftErrMsg $ tell- ["Warning: Couldn't find .haddock for export " ++ pretty dflags t]- let subs_ = [ (n, noDocForDecl) | (n, _, _) <- subordinates instMap (unLoc decl) ]- return [ mkExportDecl t decl (noDocForDecl, subs_) ]- Just iface ->- return [ mkExportDecl t decl (lookupDocs t warnings (instDocMap iface) (instArgMap iface) (instSubMap iface)) ]-- _ -> return []--- mkExportDecl :: Name -> LHsDecl Name -> (DocForDecl Name, [(Name, DocForDecl Name)]) -> ExportItem Name- mkExportDecl name decl (doc, subs) = decl'- where- decl' = ExportDecl (restrictTo sub_names (extractDecl name mdl decl)) doc subs' [] fixities False- mdl = nameModule name- subs' = filter (isExported . fst) subs- sub_names = map fst subs'- fixities = [ (n, f) | n <- name:sub_names, Just f <- [M.lookup n fixMap] ]--- isExported = (`elem` exportedNames)--- findDecl :: Name -> ([LHsDecl Name], (DocForDecl Name, [(Name, DocForDecl Name)]))- findDecl n- | m == thisMod, Just ds <- M.lookup n declMap =- (ds, lookupDocs n warnings docMap argMap subMap)- | Just iface <- M.lookup m modMap, Just ds <- M.lookup n (ifaceDeclMap iface) =- (ds, lookupDocs n warnings (ifaceDocMap iface) (ifaceArgMap iface) (ifaceSubMap iface))- | otherwise = ([], (noDocForDecl, []))- where- m = nameModule n---hiDecl :: DynFlags -> Name -> ErrMsgGhc (Maybe (LHsDecl Name))-hiDecl dflags t = do- mayTyThing <- liftGhcToErrMsgGhc $ lookupName t- case mayTyThing of- Nothing -> do- liftErrMsg $ tell ["Warning: Not found in environment: " ++ pretty dflags t]- return Nothing- Just x -> case tyThingToLHsDecl x of- Left m -> liftErrMsg (tell [bugWarn m]) >> return Nothing- Right (m, t') -> liftErrMsg (tell $ map bugWarn m)- >> return (Just $ noLoc 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 = O.showSDoc dflags . warnLine---- | This function is called for top-level bindings without type signatures.--- It gets the type signature from GHC and that means it's not going to--- have a meaningful 'SrcSpan'. So we pass down 'SrcSpan' for the--- declaration and use it instead - 'nLoc' here.-hiValExportItem :: DynFlags -> Name -> SrcSpan -> DocForDecl Name -> Bool- -> Maybe Fixity -> ErrMsgGhc (ExportItem Name)-hiValExportItem dflags name nLoc doc splice fixity = do- mayDecl <- hiDecl dflags name- case mayDecl of- Nothing -> return (ExportNoDecl name [])- Just decl -> return (ExportDecl (fixSpan decl) doc [] [] fixities splice)- where- fixSpan (L l t) = L (SrcLoc.combineSrcSpans l nLoc) t- fixities = case fixity of- Just f -> [(name, f)]- Nothing -> []----- | Lookup docs for a declaration from maps.-lookupDocs :: Name -> WarningMap -> DocMap Name -> ArgMap Name -> SubMap- -> (DocForDecl Name, [(Name, DocForDecl Name)])-lookupDocs n warnings docMap argMap subMap =- let lookupArgDoc x = M.findWithDefault M.empty x argMap in- let doc = (lookupDoc n, lookupArgDoc n) in- let subs = M.findWithDefault [] n subMap in- let subDocs = [ (s, (lookupDoc s, lookupArgDoc s)) | s <- subs ] in- (doc, subDocs)- where- lookupDoc name = Documentation (M.lookup name docMap) (M.lookup name warnings)----- | Return all export items produced by an exported module. That is, we're--- interested in the exports produced by \"module B\" in such a scenario:------ > module A (module B) where--- > import B (...) hiding (...)------ There are three different cases to consider:------ 1) B is hidden, in which case we return all its exports that are in scope in A.--- 2) B is visible, but not all its exports are in scope in A, in which case we--- only return those that are.--- 3) B is visible and all its exports are in scope, in which case we return--- a single 'ExportModule' item.-moduleExports :: Module -- ^ Module A- -> ModuleName -- ^ The real name of B, the exported module- -> DynFlags -- ^ The flags used when typechecking A- -> WarningMap- -> GlobalRdrEnv -- ^ The renaming environment used for A- -> [Name] -- ^ All the exports of A- -> [LHsDecl Name] -- ^ All the declarations in A- -> IfaceMap -- ^ Already created interfaces- -> InstIfaceMap -- ^ Interfaces in other packages- -> Maps- -> FixMap- -> [SrcSpan] -- ^ Locations of all TH splices- -> ErrMsgGhc [ExportItem Name] -- ^ Resulting export items-moduleExports thisMod expMod dflags warnings gre _exports decls ifaceMap instIfaceMap maps fixMap splices- | m == thisMod = fullModuleContents dflags warnings gre maps fixMap splices decls- | otherwise =- case M.lookup m ifaceMap of- Just iface- | OptHide `elem` ifaceOptions iface -> return (ifaceExportItems iface)- | otherwise -> return [ ExportModule m ]-- Nothing -> -- We have to try to find it in the installed interfaces- -- (external packages).- case M.lookup expMod (M.mapKeys moduleName instIfaceMap) of- Just iface -> return [ ExportModule (instMod iface) ]- Nothing -> do- liftErrMsg $- tell ["Warning: " ++ pretty dflags thisMod ++ ": Could not find " ++- "documentation for exported module: " ++ pretty dflags expMod]- return []- where- m = mkModule unitId expMod- unitId = moduleUnitId thisMod----- Note [1]:---------------- It is unnecessary to document a subordinate by itself at the top level if--- any of its parents is also documented. Furthermore, if the subordinate is a--- record field or a class method, documenting it under its parent--- indicates its special status.------ A user might expect that it should show up separately, so we issue a--- warning. It's a fine opportunity to also tell the user she might want to--- export the subordinate through the parent export item for clarity.------ The code removes top-level subordinates also when the parent is exported--- through a 'module' export. I think that is fine.------ (For more information, see Trac #69)---fullModuleContents :: DynFlags -> WarningMap -> GlobalRdrEnv -> Maps -> FixMap -> [SrcSpan]- -> [LHsDecl Name] -> ErrMsgGhc [ExportItem Name]-fullModuleContents dflags warnings gre (docMap, argMap, subMap, declMap, instMap) fixMap splices decls =- liftM catMaybes $ mapM mkExportItem (expandSig decls)- where- -- A type signature can have multiple names, like:- -- foo, bar :: Types..- --- -- We go through the list of declarations and expand type signatures, so- -- that every type signature has exactly one name!- expandSig :: [LHsDecl name] -> [LHsDecl name]- expandSig = foldr f []- where- f :: LHsDecl name -> [LHsDecl name] -> [LHsDecl name]- f (L l (SigD (TypeSig names t))) xs = foldr (\n acc -> L l (SigD (TypeSig [n] t)) : acc) xs names- f (L l (SigD (ClassOpSig b names t))) xs = foldr (\n acc -> L l (SigD (ClassOpSig b [n] t)) : acc) xs names- f x xs = x : xs-- mkExportItem :: LHsDecl Name -> ErrMsgGhc (Maybe (ExportItem Name))- mkExportItem (L _ (DocD (DocGroup lev docStr))) = do- return . Just . ExportGroup lev "" $ processDocString dflags gre docStr- mkExportItem (L _ (DocD (DocCommentNamed _ docStr))) = do- return . Just . ExportDoc $ processDocStringParas dflags gre docStr- mkExportItem (L l (ValD d))- | name:_ <- collectHsBindBinders d, Just [L _ (ValD _)] <- M.lookup name declMap =- -- Top-level binding without type signature.- let (doc, _) = lookupDocs name warnings docMap argMap subMap in- fmap Just (hiValExportItem dflags name l doc (l `elem` splices) $ M.lookup name fixMap)- | otherwise = return Nothing- mkExportItem decl@(L l (InstD d))- | Just name <- M.lookup (getInstLoc d) instMap =- let (doc, subs) = lookupDocs name warnings docMap argMap subMap in- return $ Just (ExportDecl decl doc subs [] (fixities name subs) (l `elem` splices))- mkExportItem (L l (TyClD cl@ClassDecl{ tcdLName = L _ name, tcdSigs = sigs })) = do- mdef <- liftGhcToErrMsgGhc $ minimalDef name- let sig = maybeToList $ fmap (noLoc . MinimalSig mempty . noLoc . fmap noLoc) mdef- expDecl (L l (TyClD cl { tcdSigs = sig ++ sigs })) l name- mkExportItem decl@(L l d)- | name:_ <- getMainDeclBinder d = expDecl decl l name- | otherwise = return Nothing-- fixities name subs = [ (n,f) | n <- name : map fst subs- , Just f <- [M.lookup n fixMap] ]-- expDecl decl l name = return $ Just (ExportDecl decl doc subs [] (fixities name subs) (l `elem` splices))- where (doc, subs) = lookupDocs name warnings docMap argMap subMap----- | 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--- together a type signature for it...).-extractDecl :: Name -> Module -> LHsDecl Name -> LHsDecl Name-extractDecl name mdl decl- | name `elem` getMainDeclBinder (unLoc decl) = decl- | otherwise =- case unLoc decl of- TyClD d@ClassDecl {} ->- let matches = [ lsig- | lsig <- tcdSigs d- , ClassOpSig False _ _ <- pure $ unLoc lsig- -- Note: exclude `default` declarations (see #505)- , name `elem` sigName lsig- ]- -- TODO: document fixity- in case matches of- [s0] -> let (n, tyvar_names) = (tcdName d, tyClDeclTyVars d)- L pos sig = addClassContext n tyvar_names s0- in L pos (SigD sig)- _ -> O.pprPanic "extractDecl" (O.text "Ambiguous decl for" O.<+> O.ppr name O.<+> O.text "in class:"- O.$$ O.nest 4 (O.ppr d)- O.$$ O.text "Matches:"- O.$$ O.nest 4 (O.ppr matches))- TyClD d@DataDecl {} ->- let (n, tyvar_tys) = (tcdName d, lHsQTyVarsToTypes (tyClDeclTyVars d))- in SigD <$> extractRecSel name mdl n tyvar_tys (dd_cons (tcdDataDefn d))- InstD (DataFamInstD DataFamInstDecl { dfid_tycon = L _ n- , dfid_pats = HsIB { hsib_body = tys }- , dfid_defn = defn }) ->- SigD <$> extractRecSel name mdl n tys (dd_cons defn)- InstD (ClsInstD ClsInstDecl { cid_datafam_insts = insts }) ->- let matches = [ d | L _ d <- insts- -- , L _ ConDecl { con_details = RecCon rec } <- dd_cons (dfid_defn d)- , RecCon rec <- map (getConDetails . unLoc) (dd_cons (dfid_defn d))- , ConDeclField { cd_fld_names = ns } <- map unLoc (unLoc rec)- , L _ n <- ns- , selectorFieldOcc n == name- ]- in case matches of- [d0] -> extractDecl name mdl (noLoc . InstD $ DataFamInstD d0)- _ -> error "internal: extractDecl (ClsInstD)"- _ -> error "internal: extractDecl"--extractRecSel :: Name -> Module -> Name -> [LHsType Name] -> [LConDecl Name]- -> LSig Name-extractRecSel _ _ _ _ [] = error "extractRecSel: selector not found"--extractRecSel nm mdl t tvs (L _ con : rest) =- case getConDetails con of- RecCon (L _ fields) | ((l,L _ (ConDeclField _nn ty _)) : _) <- matching_fields fields ->- L l (TypeSig [noLoc nm] (mkEmptySigWcType (noLoc (HsFunTy data_ty (getBangType ty)))))- _ -> extractRecSel nm mdl t tvs rest- where- matching_fields :: [LConDeclField Name] -> [(SrcSpan, LConDeclField Name)]- matching_fields flds = [ (l,f) | f@(L _ (ConDeclField ns _ _)) <- flds- , L l n <- ns, selectorFieldOcc n == nm ]- data_ty- -- ResTyGADT _ ty <- con_res con = ty- | ConDeclGADT{} <- con = hsib_body $ con_type con- | otherwise = foldl' (\x y -> noLoc (HsAppTy x y)) (noLoc (HsTyVar (noLoc t))) tvs---- | Keep export items with docs.-pruneExportItems :: [ExportItem Name] -> [ExportItem Name]-pruneExportItems = filter hasDoc- where- hasDoc (ExportDecl{expItemMbDoc = (Documentation d _, _)}) = isJust d- hasDoc _ = True---mkVisibleNames :: Maps -> [ExportItem Name] -> [DocOption] -> [Name]-mkVisibleNames (_, _, _, _, instMap) exports opts- | OptHide `elem` opts = []- | otherwise = let ns = concatMap exportName exports- in seqList ns `seq` ns- where- exportName e@ExportDecl {} = name ++ subs- where subs = map fst (expItemSubDocs e)- name = case unLoc $ expItemDecl e of- InstD d -> maybeToList $ M.lookup (getInstLoc d) instMap- decl -> getMainDeclBinder decl- exportName ExportNoDecl {} = [] -- we don't count these as visible, since- -- we don't want links to go to them.- exportName _ = []--seqList :: [a] -> ()-seqList [] = ()-seqList (x : xs) = x `seq` seqList xs--mkMaybeTokenizedSrc :: [Flag] -> TypecheckedModule- -> ErrMsgGhc (Maybe [RichToken])-mkMaybeTokenizedSrc flags tm- | Flag_HyperlinkedSource `elem` flags = case renamedSource tm of- Just src -> do- tokens <- liftGhcToErrMsgGhc . liftIO $ mkTokenizedSrc summary src- return $ Just tokens- Nothing -> do- liftErrMsg . tell . pure $ concat- [ "Warning: Cannot hyperlink module \""- , moduleNameString . ms_mod_name $ summary- , "\" because renamed source is not available"- ]- return Nothing- | otherwise = return Nothing- where- summary = pm_mod_summary . tm_parsed_module $ tm--mkTokenizedSrc :: ModSummary -> RenamedSource -> IO [RichToken]-mkTokenizedSrc ms src =- Hyperlinker.enrich src . Hyperlinker.parse <$> rawSrc- where- rawSrc = readFile $ msHsFilePath ms---- | Find a stand-alone documentation comment by its name.-findNamedDoc :: String -> [HsDecl Name] -> ErrMsgM (Maybe HsDocString)-findNamedDoc name = search- where- search [] = do- tell ["Cannot find documentation for: $" ++ name]- return Nothing- search (DocD (DocCommentNamed name' doc) : rest)- | name == name' = return (Just doc)+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ViewPatterns #-}+{-# OPTIONS_GHC -Wwarn #-}+-----------------------------------------------------------------------------+-- |+-- Module : Haddock.Interface.Create+-- Copyright : (c) Simon Marlow 2003-2006,+-- David Waern 2006-2009,+-- Mateusz Kowalczyk 2013+-- License : BSD-like+--+-- Maintainer : haddock@projects.haskell.org+-- Stability : experimental+-- Portability : portable+--+-- 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 (metaDocAppend)+import Haddock.Backends.Hoogle (outWith)+import Haddock.Convert (PrintRuntimeReps (..), tyThingToLHsDecl, synifyInstHead)+import Haddock.GhcUtils (addClassContext, filterSigNames, lHsQTyVarsToTypes, mkEmptySigType, moduleString, parents,+ pretty, restrictTo, sigName, unL, typeNames)+import Haddock.Interface.AttachInstances (instHead)+import Haddock.Interface.LexParseRn+import Haddock.Options (Flag (..), modulePackageInfo)+import Haddock.Types+import Haddock.Utils (replace)++import Control.Applicative ((<|>))+import Control.DeepSeq+import Control.Monad.State.Strict+import Data.Bitraversable (bitraverse)+import Data.Foldable (toList)+import Data.List (find, foldl')+import qualified Data.IntMap as IM+import Data.IntMap (IntMap)+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as M+import Data.Maybe (catMaybes, fromJust, isJust, mapMaybe, maybeToList)+import qualified Data.Set as Set+import Data.Traversable (for)++import GHC hiding (lookupName)+import GHC.Core (isOrphan)+import GHC.Core.Class (ClassMinimalDef, classMinimalDef)+import GHC.Core.ConLike (ConLike (..))+import GHC.Core.InstEnv+import GHC.Data.FastString (unpackFS)+import GHC.Driver.Ppr (showSDoc, showSDocForUser)+import GHC.HsToCore.Docs hiding (mkMaps, unionArgMaps)+import GHC.IORef (readIORef)+import GHC.Stack (HasCallStack)+import GHC.Tc.Types hiding (IfM)+import GHC.Tc.Utils.Monad (finalSafeMode)+import GHC.Types.Avail hiding (avail)+import qualified GHC.Types.Avail as Avail+import GHC.Types.Name (getOccString, getSrcSpan, isDataConName, isValName, nameIsLocalOrFrom, nameOccName, emptyOccEnv)+import GHC.Types.Name.Env (lookupNameEnv)+import GHC.Types.Name.Reader (GlobalRdrEnv, greMangledName, lookupGlobalRdrEnv)+import GHC.Types.Name.Set (elemNameSet, mkNameSet)+import GHC.Types.SourceFile (HscSource (..))+import GHC.Types.SourceText (SourceText (..), sl_fs)+import GHC.Unit.Types+import qualified GHC.Types.SrcLoc as SrcLoc+import qualified GHC.Unit.Module as Module+import GHC.Unit.Module.ModSummary (msHsFilePath)+import GHC.Unit.State (PackageName (..), UnitState, lookupModuleInAllUnits)+import qualified GHC.Utils.Outputable as O+import GHC.Utils.Panic (pprPanic)+import GHC.Unit.Module.Warnings+import GHC.Types.Unique.Map++createInterface1+ :: MonadIO m+ => [Flag]+ -> UnitState+ -> ModSummary+ -> TcGblEnv+ -> IfaceMap+ -> InstIfaceMap+ -> IfM m Interface+createInterface1 flags unit_state mod_sum tc_gbl_env ifaces inst_ifaces = 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+ }+ } = mod_sum++ !ml_hie_file' = force ml_hie_file++ TcGblEnv+ {+ tcg_mod+ , tcg_src+ , tcg_semantic_mod+ , tcg_rdr_env+ , tcg_exports+ , tcg_insts+ , tcg_fam_insts+ , tcg_warns++ -- Renamed source+ , tcg_rn_imports+ , tcg_rn_exports+ , tcg_rn_decls++ , tcg_th_docs+ , tcg_doc_hdr+ } = tc_gbl_env++ dflags = ms_hspp_opts++ is_sig = tcg_src == HsigFile++ (pkg_name_fs, _) =+ modulePackageInfo unit_state flags (Just tcg_mod)++ pkg_name :: Maybe Package+ pkg_name =+ let+ unpack (PackageName name) = unpackFS name+ in+ fmap unpack pkg_name_fs++ fixities :: FixMap+ fixities = case tcg_rn_decls of+ Nothing -> mempty+ Just dx -> mkFixMap dx++ -- Locations of all the TH splices+ loc_splices :: [SrcSpan]+ loc_splices = case tcg_rn_decls of+ Nothing -> []+ Just HsGroup { hs_splcds } -> [ locA loc | L loc _ <- hs_splcds ]++ decls <- case tcg_rn_decls of+ Nothing -> do+ warn "Warning: Renamed source is not available"+ pure []+ Just dx -> pure (topDecls dx)++ -- Derive final options to use for haddocking this module+ doc_opts <- mkDocOpts (haddockOptions ms_hspp_opts) flags tcg_mod++ let+ -- All elements of an explicit export list, if present+ export_list :: Maybe [(IE GhcRn, Avails)]+ export_list+ | OptIgnoreExports `elem` doc_opts =+ Nothing+ | Just rn_exports <- tcg_rn_exports =+ Just [ (ie, avail) | (L _ ie, avail) <- rn_exports ]+ | otherwise =+ Nothing++ -- All the exported Names of this module.+ exported_names :: [Name]+ !exported_names = force $+ concatMap availNamesWithSelectors tcg_exports++ -- Module imports of the form `import X`. Note that there is+ -- a) no qualification and+ -- b) no import list+ imported_modules :: Map ModuleName [ModuleName]+ imported_modules+ | Just{} <- export_list =+ unrestrictedModuleImports (map unLoc tcg_rn_imports)+ | otherwise =+ M.empty++ -- TyThings that have instances defined in this module+ local_instances :: [Name]+ local_instances =+ [ name+ | name <- map getName tcg_insts ++ map getName tcg_fam_insts+ , nameIsLocalOrFrom tcg_semantic_mod name+ ]++ -- Infer module safety+ safety <- liftIO (finalSafeMode ms_hspp_opts tc_gbl_env)++ -- The docs added via Template Haskell's putDoc+ thDocs@ExtractedTHDocs { ethd_mod_header = thMbDocStr } <-+ liftIO $ extractTHDocs <$> readIORef tcg_th_docs++ -- Process the top-level module header documentation.+ (!info, !header_doc) <- force <$> processModuleHeader dflags pkg_name+ tcg_rdr_env safety (fmap hsDocString thMbDocStr <|> (hsDocString . unLoc <$> tcg_doc_hdr))++ -- Warnings on declarations in this module+ decl_warnings <- mkWarningMap dflags tcg_warns tcg_rdr_env exported_names++ -- Warning on the module header+ mod_warning <- moduleWarning dflags tcg_rdr_env tcg_warns++ let+ -- Warnings in this module and transitive warnings from dependent modules+ warnings :: Map Name (Doc Name)+ warnings = M.unions (decl_warnings : map ifaceWarningMap (M.elems ifaces))++ maps@(!docs, !arg_docs, !decl_map, _) <-+ mkMaps dflags pkg_name tcg_rdr_env local_instances decls thDocs++ export_items <- mkExportItems is_sig ifaces pkg_name tcg_mod tcg_semantic_mod+ warnings tcg_rdr_env exported_names (map fst decls) maps fixities+ imported_modules loc_splices export_list tcg_exports inst_ifaces dflags++ let+ visible_names :: [Name]+ !visible_names = force $ mkVisibleNames maps export_items doc_opts++ -- Measure haddock documentation coverage.+ pruned_export_items :: [ExportItem GhcRn]+ pruned_export_items = pruneExportItems export_items++ !haddockable = 1 + length export_items -- module + exports+ !haddocked = (if isJust tcg_doc_hdr then 1 else 0) + length pruned_export_items++ coverage :: (Int, Int)+ !coverage = (haddockable, haddocked)++ aliases :: Map Module ModuleName+ aliases = mkAliasMap unit_state tcg_rn_imports++ insts :: [HaddockClsInst]+ !insts = force $ map (fromClsInst (Flag_Hoogle `elem` flags) dflags unit_state) tcg_insts++ return $! Interface+ {+ ifaceMod = tcg_mod+ , ifaceIsSig = is_sig+ , ifaceOrigFilename = msHsFilePath mod_sum+ , ifaceHieFile = Just ml_hie_file'+ , ifaceInfo = info+ , ifaceDoc = Documentation header_doc mod_warning+ , ifaceRnDoc = Documentation Nothing Nothing+ , ifaceOptions = doc_opts+ , ifaceDocMap = docs+ , ifaceArgMap = arg_docs+ , ifaceExportItems = if OptPrune `elem` doc_opts then+ pruned_export_items else export_items+ , ifaceRnExportItems = [] -- Filled in renameInterfaceRn+ , ifaceExports = exported_names+ , ifaceVisibleExports = visible_names+ , ifaceDeclMap = decl_map+ , ifaceFixMap = fixities+ , ifaceModuleAliases = aliases+ , ifaceInstances = insts+ , ifaceOrphanInstances = [] -- Filled in attachInstances+ , ifaceRnOrphanInstances = [] -- Filled in renameInterfaceRn+ , ifaceHaddockCoverage = coverage+ , ifaceWarningMap = warnings+ , ifaceDynFlags = dflags+ }+++-- | Given all of the @import M as N@ declarations in a package,+-- create a mapping from the module identity of M, to an alias N+-- (if there are multiple aliases, we pick the last one.) This+-- will go in 'ifaceModuleAliases'.+mkAliasMap :: UnitState -> [LImportDecl GhcRn] -> M.Map Module ModuleName+mkAliasMap st impDecls =+ M.fromList $+ mapMaybe (\(SrcLoc.L _ impDecl) -> do+ SrcLoc.L _ alias <- ideclAs impDecl+ return+ (lookupModuleDyn st+ -- TODO: This is supremely dodgy, because in general the+ -- UnitId isn't going to look anything like the package+ -- qualifier (even with old versions of GHC, the+ -- IPID would be p-0.1, but a package qualifier never+ -- has a version number it. (Is it possible that in+ -- Haddock-land, the UnitIds never have version numbers?+ -- I, ezyang, have not quite understand Haddock's package+ -- identifier model.)+ --+ -- Additionally, this is simulating some logic GHC already+ -- has for deciding how to qualify names when it outputs+ -- them to the user. We should reuse that information;+ -- or at least reuse the renamed imports, which know what+ -- they import!+ (ideclPkgQual impDecl)+ (case ideclName impDecl of SrcLoc.L _ name -> name),+ alias))+ impDecls++-- We want to know which modules are imported without any qualification. This+-- way we can display module reexports more compactly. This mapping also looks+-- through aliases:+--+-- module M (module X) where+-- import M1 as X+-- import M2 as X+--+-- With our mapping we know that we can display exported modules M1 and M2.+--+unrestrictedModuleImports :: [ImportDecl GhcRn] -> M.Map ModuleName [ModuleName]+unrestrictedModuleImports idecls =+ M.map (map (unLoc . ideclName))+ $ M.filter (all isInteresting) impModMap+ where+ impModMap =+ M.fromListWith (++) (concatMap moduleMapping idecls)++ moduleMapping idecl =+ concat [ [ (unLoc (ideclName idecl), [idecl]) ]+ , [ (unLoc mod_name, [idecl])+ | Just mod_name <- [ideclAs idecl]+ ]+ ]++ isInteresting idecl =+ case ideclImportList idecl of+ -- i) no subset selected+ Nothing -> True+ -- ii) an import with a hiding clause+ -- without any names+ Just (EverythingBut, L _ []) -> True+ -- iii) any other case of qualification+ _ -> False++-- Similar to GHC.lookupModule+-- ezyang: Not really...+lookupModuleDyn ::+ UnitState -> PkgQual -> ModuleName -> Module+lookupModuleDyn st pkg_qual mdlName = case pkg_qual of+ OtherPkg uid -> Module.mkModule (RealUnit (Definite uid)) mdlName+ ThisPkg uid -> Module.mkModule (RealUnit (Definite uid)) mdlName+ NoPkgQual -> case lookupModuleInAllUnits st mdlName of+ (m,_):_ -> m+ [] -> Module.mkModule Module.mainUnit mdlName++-- | Prune a 'ClsInst' down to a 'HaddockClsInst'. The goal is to remove as much+-- unnecessary information from the 'ClsInst' as possible by precomputing the+-- information we eventually want from it.+fromClsInst+ :: Bool+ -- ^ Was Hoogle output requested?+ -> DynFlags+ -- ^ GHC session dynflags+ -> UnitState+ -- ^ GHC session dynflags+ -> ClsInst+ -- ^ Class instance to convert+ -> HaddockClsInst+ -- ^ Resulting Haddock class instance+fromClsInst doHoogle dflags unitState inst =+ HaddockClsInst+ { haddockClsInstPprHoogle =+ if doHoogle then Just (ppInstance inst) else Nothing+ , haddockClsInstName = getName inst+ , haddockClsInstClsName = getName cls+ , haddockClsInstIsOrphan = isOrphan $ is_orphan inst+ , haddockClsInstSynified = synifyInstHead instSig+ , haddockClsInstHead = instHead instSig+ , haddockClsInstTyNames =+ foldl' (\ns t -> ns `Set.union` typeNames t) Set.empty tys+ }+ where+ instSig :: ([TyVar], [Type], Class, [Type])+ instSig@(_,_,cls,tys) = instanceSig inst++ ppInstance :: ClsInst -> String+ ppInstance i =+ dropComment $ outWith (showSDocForUser dflags unitState alwaysQualify) i'+ where+ -- As per #168, we don't want safety information about the class+ -- in Hoogle output. The easiest way to achieve this is to set the+ -- safety information to a state where the Outputable instance+ -- produces no output which means no overlap and unsafe (or [safe]+ -- is generated).+ i' = i { is_flag = OverlapFlag { overlapMode = NoOverlap NoSourceText+ , isSafeOverlap = False } }++ dropComment :: String -> String+ dropComment (' ':'-':'-':' ':_) = []+ dropComment (x:xs) = x : dropComment xs+ dropComment [] = []+++-------------------------------------------------------------------------------+-- Warnings+-------------------------------------------------------------------------------++mkWarningMap+ :: MonadIO m+ => DynFlags+ -> Warnings a+ -> GlobalRdrEnv+ -> [Name]+ -> IfM m WarningMap+mkWarningMap dflags warnings gre exps = case warnings of+ NoWarnings -> pure M.empty+ WarnAll _ -> pure M.empty+ WarnSome ws ->+ let ws' = [ (n, w)+ | (occ, w) <- ws+ , elt <- lookupGlobalRdrEnv gre occ+ , let n = greMangledName elt, n `elem` exps ]+ in M.fromList <$> traverse (bitraverse pure (parseWarning dflags gre)) ws'++moduleWarning+ :: MonadIO m+ => DynFlags+ -> GlobalRdrEnv+ -> Warnings a+ -> IfM m (Maybe (Doc Name))+moduleWarning _ _ NoWarnings = pure Nothing+moduleWarning _ _ (WarnSome _) = pure Nothing+moduleWarning dflags gre (WarnAll w) = Just <$> parseWarning dflags gre w++parseWarning+ :: MonadIO m+ => DynFlags+ -> GlobalRdrEnv+ -> WarningTxt a+ -> IfM m (Doc Name)+parseWarning dflags gre w = case w of+ DeprecatedTxt _ msg -> format "Deprecated: " (foldMap (unpackFS . sl_fs . hsDocString . unLoc) msg)+ WarningTxt _ msg -> format "Warning: " (foldMap (unpackFS . sl_fs . hsDocString . unLoc) msg)+ where+ format x bs = DocWarning . DocParagraph . DocAppend (DocString x)+ <$> processDocStringFromString dflags gre bs+++-------------------------------------------------------------------------------+-- Doc options+--+-- Haddock options that are embedded in the source file+-------------------------------------------------------------------------------++mkDocOpts :: MonadIO m => Maybe String -> [Flag] -> Module -> IfM m [DocOption]+mkDocOpts mbOpts flags mdl = do+ opts <- case mbOpts of+ Just opts -> case words $ replace ',' ' ' opts of+ [] -> warn "No option supplied to DOC_OPTION/doc_option" >> return []+ xs -> fmap catMaybes (mapM parseOption xs)+ Nothing -> return []+ pure (foldl go opts flags)+ where+ 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_IgnoreAllExports = OptIgnoreExports : os+ | m == Flag_ShowExtensions mdlStr = OptIgnoreExports : os+ | otherwise = os++parseOption :: MonadIO m => String -> IfM m (Maybe DocOption)+parseOption "hide" = return (Just OptHide)+parseOption "prune" = return (Just OptPrune)+parseOption "ignore-exports" = return (Just OptIgnoreExports)+parseOption "not-home" = return (Just OptNotHome)+parseOption "show-extensions" = return (Just OptShowExtensions)+parseOption other = warn ("Unrecognised option: " ++ other) >> return Nothing++--------------------------------------------------------------------------------+-- Maps+--------------------------------------------------------------------------------+++type Maps = (DocMap Name, ArgMap Name, DeclMap, InstMap)++-- | Create 'Maps' by looping through the declarations. For each declaration,+-- find its names, its subordinates, and its doc strings. Process doc strings+-- into 'Doc's.+mkMaps+ :: MonadIO m+ => DynFlags+ -> Maybe Package -- this package+ -> GlobalRdrEnv+ -> [Name]+ -> [(LHsDecl GhcRn, [HsDoc GhcRn])]+ -> ExtractedTHDocs -- ^ Template Haskell putDoc docs+ -> IfM m Maps+mkMaps dflags pkgName gre instances decls thDocs = do+ (a, b, c) <- unzip3 <$> traverse mappings decls+ (th_a, th_b) <- thMappings+ pure ( force $+ th_a `M.union` f' (map (nubByName fst) a)+ , force $+ fmap intmap2mapint $+ th_b `unionArgMaps` (f (filterMapping (not . IM.null) b))+ , f c+ , instanceMap+ )+ where+ f :: (Ord a, Semigroup b) => [[(a, b)]] -> Map a b+ f = M.fromListWith (<>) . concat++ f' :: [[(Name, MDoc Name)]] -> Map Name (MDoc Name)+ f' = M.fromListWith metaDocAppend . concat++ filterMapping :: (b -> Bool) -> [[(a, b)]] -> [[(a, b)]]+ filterMapping p = map (filter (p . snd))++ -- Convert IntMap -> IntMap+ -- TODO: should ArgMap eventually be switched over to IntMap?+ intmap2mapint = M.fromList . IM.toList++ -- | Extract the mappings from template haskell.+ -- No DeclMap/InstMap is needed since we already have access to the+ -- doc strings+ thMappings+ :: MonadIO m+ => IfM m (Map Name (MDoc Name), Map Name (IntMap (MDoc Name)))+ thMappings = do+ let ExtractedTHDocs+ _+ declDocs+ argDocs+ instDocs = thDocs+ ds2mdoc :: MonadIO m => (HsDoc GhcRn) -> IfM m (MDoc Name)+ ds2mdoc = processDocStringParas dflags pkgName gre . hsDocString++ let cvt = M.fromList . nonDetEltsUniqMap++ declDocs' <- mapM ds2mdoc (cvt declDocs)+ argDocs' <- mapM (mapM ds2mdoc) (cvt argDocs)+ instDocs' <- mapM ds2mdoc (cvt instDocs)+ return (declDocs' <> instDocs', argDocs')+++ mappings+ :: MonadIO m+ => (LHsDecl GhcRn, [HsDoc GhcRn])+ -> IfM m+ ( [(Name, MDoc Name)]+ , [(Name, IntMap (MDoc Name))]+ , [(Name, DeclMapEntry)]+ )+ mappings (ldecl@(L (SrcSpanAnn _ (RealSrcSpan l _)) decl), hs_docStrs) = do+ let docStrs = map hsDocString hs_docStrs+ declDoc+ :: MonadIO m+ => [HsDocString]+ -> IntMap HsDocString+ -> IfM m (Maybe (MDoc Name), IntMap (MDoc Name))+ declDoc strs m = do+ doc' <- processDocStrings dflags pkgName gre strs+ m' <- traverse (processDocStringParas dflags pkgName gre) m+ pure (doc', m')++ (!doc, !args) <- force <$> declDoc docStrs (fmap hsDocString (declTypeDocs decl))++ let+ subs :: [(Name, [HsDocString], IntMap HsDocString)]+ subs = map (\(n, ds, im) -> (n, map hsDocString ds, fmap hsDocString im))+ $ subordinates emptyOccEnv instanceMap decl++ (subDocs, subArgs) <- unzip <$> traverse (\(_, strs, m) -> declDoc strs m) subs++ let+ ns = names l decl+ subNs = [ n | (n, _, _) <- subs ]+ dm = [ (n, d) | (n, Just d) <- zip ns (repeat doc) ++ zip subNs subDocs ]+ am = [ (n, args) | n <- ns ] ++ zip subNs subArgs+ cm = [ (n, toDeclMapEntry ldecl) | n <- ns ++ subNs ]++ seqList ns `seq`+ seqList subNs `seq`+ doc `seq`+ seqList subDocs `seq`+ seqList subArgs `seq`+ pure (dm, am, cm)+ mappings (L (SrcSpanAnn _ (UnhelpfulSpan _)) _, _) = pure ([], [], [])++ instanceMap :: Map RealSrcSpan Name+ instanceMap = M.fromList [(l, n) | n <- instances, RealSrcSpan l _ <- [getSrcSpan n] ]++ names :: RealSrcSpan -> HsDecl GhcRn -> [Name]+ names _ (InstD _ d) = maybeToList (SrcLoc.lookupSrcSpan loc instanceMap) -- See note [2].+ where loc = case d of+ -- The CoAx's loc is the whole line, but only for TFs. The+ -- workaround is to dig into the family instance declaration and+ -- get the identifier with the right location.+ TyFamInstD _ (TyFamInstDecl _ d') -> getLocA (feqn_tycon d')+ _ -> getInstLoc d+ names l (DerivD {}) = maybeToList (M.lookup l instanceMap) -- See note [2].+ names _ decl = getMainDeclBinder emptyOccEnv decl++-- | Unions together two 'ArgDocMaps' (or ArgMaps in haddock-api), such that two+-- maps with values for the same key merge the inner map as well.+-- Left biased so @unionArgMaps a b@ prefers @a@ over @b@.++unionArgMaps :: forall b . Map Name (IntMap b)+ -> Map Name (IntMap b)+ -> Map Name (IntMap b)+unionArgMaps a b = M.foldrWithKey go b a+ where+ go :: Name -> IntMap b+ -> Map Name (IntMap b) -> Map Name (IntMap b)+ go n newArgMap acc+ | Just oldArgMap <- M.lookup n acc =+ M.insert n (newArgMap `IM.union` oldArgMap) acc+ | otherwise = M.insert n newArgMap acc++-- Note [2]:+------------+-- We relate ClsInsts to InstDecls and DerivDecls using the SrcSpans buried+-- inside them. That should work for normal user-written instances (from+-- looking at GHC sources). We can assume that commented instances are+-- user-written. This lets us relate Names (from ClsInsts) to comments+-- (associated with InstDecls and DerivDecls).++--------------------------------------------------------------------------------+-- Declarations+--------------------------------------------------------------------------------++-- | Extract a map of fixity declarations only+mkFixMap :: HsGroup GhcRn -> FixMap+mkFixMap group_ =+ M.fromList [ (n,f)+ | L _ (FixitySig _ ns f) <- hsGroupTopLevelFixitySigs group_,+ L _ n <- ns ]+++-- | 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+-- original names.+--+-- We create the export items even if the module is hidden, since they+-- might be useful when creating the export items for other modules.+mkExportItems+ :: MonadIO m+ => Bool -- is it a signature+ -> IfaceMap+ -> Maybe Package -- this package+ -> Module -- this module+ -> Module -- semantic module+ -> WarningMap+ -> GlobalRdrEnv+ -> [Name] -- exported names (orig)+ -> [LHsDecl GhcRn] -- renamed source declarations+ -> Maps+ -> FixMap+ -> M.Map ModuleName [ModuleName]+ -> [SrcSpan] -- splice locations+ -> Maybe [(IE GhcRn, Avails)]+ -> Avails -- exported stuff from this module+ -> InstIfaceMap+ -> DynFlags+ -> IfM m [ExportItem GhcRn]+mkExportItems+ is_sig modMap pkgName thisMod semMod warnings gre exportedNames decls+ maps fixMap unrestricted_imp_mods splices exportList allExports+ instIfaceMap dflags =+ case exportList of+ Nothing -> do+ fullModuleContents is_sig modMap pkgName thisMod semMod warnings gre+ exportedNames decls maps fixMap splices instIfaceMap dflags+ allExports+ Just exports -> fmap concat $ mapM lookupExport exports+ where+ lookupExport (IEGroup _ lev docStr, _) = do+ !doc <- force <$> processDocString dflags gre (hsDocString . unLoc $ docStr)+ return [ExportGroup lev "" doc]++ lookupExport (IEDoc _ docStr, _) = do+ !doc <- force <$> processDocStringParas dflags pkgName gre (hsDocString . unLoc $ docStr)+ return [ExportDoc doc]++ lookupExport (IEDocNamed _ str, _) =+ findNamedDoc str [ unL d | d <- decls ] >>= \case+ Nothing -> return []+ Just docStr -> do+ !doc <- force <$> processDocStringParas dflags pkgName gre docStr+ return [ExportDoc doc]++ lookupExport (IEModuleContents _ (L _ mod_name), _)+ -- only consider exporting a module if we are sure we+ -- are really exporting the whole module and not some+ -- subset. We also look through module aliases here.+ | Just mods <- M.lookup mod_name unrestricted_imp_mods+ , not (null mods)+ = concat <$> traverse (moduleExport thisMod dflags modMap instIfaceMap) mods++ lookupExport (_, avails) = concat <$> traverse availExport (nubAvails avails)++ availExport avail =+ availExportItem is_sig modMap thisMod semMod warnings exportedNames+ maps fixMap splices instIfaceMap dflags avail+++-- Extract the minimal complete definition of a Name, if one exists+minimalDef :: Monad m => Name -> IfM m (Maybe ClassMinimalDef)+minimalDef n = do+ mty <- lookupName n+ case mty of+ Just (ATyCon (tyConClass_maybe -> Just c)) ->+ return . Just $ classMinimalDef c+ _ ->+ return Nothing+++availExportItem+ :: forall m+ . MonadIO m+ => Bool -- is it a signature+ -> IfaceMap+ -> Module -- this module+ -> Module -- semantic module+ -> WarningMap+ -> [Name] -- exported names (orig)+ -> Maps+ -> FixMap+ -> [SrcSpan] -- splice locations+ -> InstIfaceMap+ -> DynFlags+ -> AvailInfo+ -> IfM m [ExportItem GhcRn]+availExportItem is_sig modMap thisMod semMod warnings exportedNames+ (docMap, argMap, declMap, _) fixMap splices instIfaceMap+ dflags availInfo = declWith availInfo+ where+ declWith :: AvailInfo -> IfM m [ ExportItem GhcRn ]+ declWith avail = do+ let t = availName avail+ r <- findDecl avail+ case r of+ (Just (EValD srcSpan), (doc, _)) -> do+ -- Since the DeclMapEntry is an 'EValD', we know the declaration is a+ -- top-level binding without a type signature. We get type information+ -- for the binding from the GHC interface file using the+ -- 'hiValExportItem' function+ export <- hiValExportItem dflags t srcSpan doc (srcSpan `elem` splices) $ M.lookup t fixMap+ return [export]++ (Just (EOther d), docs_) ->+ let declNames = getMainDeclBinder emptyOccEnv (unL d)+ in case () of+ _+ -- If 't' is not the main declaration binder, then it is a+ -- subordinate name in the declaration. If any of its parents are+ -- also exported, we do not want to show its documentation by+ -- itself. See note [1].+ | t `notElem` declNames,+ Just p <- find isExported (parents t $ unL d) -> do+ warn $+ "Warning: " ++ moduleString thisMod ++ ": " +++ pretty dflags (nameOccName t) ++ " is exported separately but " +++ "will be documented under " ++ pretty dflags (nameOccName p) +++ ". Consider exporting it together with its parent(s)" +++ " for code clarity."+ return []++ -- normal case+ | otherwise -> case d of+ -- A single signature might refer to many names, but we+ -- create an export item for a single name only. So we+ -- modify the signature to contain only that single name.+ L loc (SigD _ sig) ->+ -- fromJust is safe since we already checked in guards+ -- that 't' is a name declared in this declaration.+ let newDecl = L loc . SigD noExtField . fromJust $ filterSigNames (== t) sig+ in availExportDecl avail newDecl docs_++ L loc (TyClD _ ClassDecl {..}) -> do+ mdef <- minimalDef t+ let sig = maybeToList $ fmap (noLocA . MinimalSig (noAnn, NoSourceText) . noLocA . fmap noLocA) mdef+ availExportDecl avail+ (L loc $ TyClD noExtField ClassDecl { tcdSigs = sig ++ tcdSigs, .. }) docs_++ _ -> availExportDecl avail d docs_++ -- Declaration from another package+ (Nothing, _) -> do+ mayDecl <- hiDecl dflags t+ case mayDecl of+ Nothing -> return [ ExportNoDecl t [] ]+ Just decl ->+ -- 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 M.lookup (nameModule t) instIfaceMap of+ Nothing -> do+ warn $ "Warning: Couldn't find .haddock for export " ++ pretty dflags t+ let subs_ = availNoDocs avail+ availExportDecl avail decl (noDocForDecl, subs_)+ Just iface ->+ availExportDecl avail decl (lookupDocs avail warnings (instDocMap iface) (instArgMap iface))++ -- Tries 'extractDecl' first then falls back to 'hiDecl' if that fails+ availDecl :: Name -> LHsDecl GhcRn -> IfM m (LHsDecl GhcRn)+ availDecl declName parentDecl =+ case extractDecl declMap declName parentDecl of+ Right d -> pure d+ Left err -> do+ synifiedDeclOpt <- hiDecl dflags 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 <- [M.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 <- [M.lookup sub fixMap] ]+ !subDoc = force sub_doc++ return $+ ExportDecl ExportD+ { expDDecl = extractedDecl+ , expDPats = []+ , expDMbDoc = subDoc+ , expDSubDocs = []+ , expDInstances = []+ , expDFixities = fixities+ , expDSpliced = False+ }++ exportedNameSet = mkNameSet exportedNames+ isExported n = elemNameSet n exportedNameSet++ findDecl :: AvailInfo -> IfM m (Maybe DeclMapEntry, (DocForDecl Name, [(Name, DocForDecl Name)]))+ findDecl avail+ | m == semMod =+ case M.lookup n declMap of+ Just d -> return (Just d, lookupDocs avail warnings docMap argMap)+ Nothing+ | is_sig -> do+ -- OK, so it wasn't in the local declaration map. It could+ -- have been inherited from a signature. Reconstitute it+ -- from the type.+ mb_r <- hiDecl dflags n+ case mb_r of+ Nothing -> return (Nothing, (noDocForDecl, availNoDocs avail))+ -- TODO: If we try harder, we might be able to find+ -- a Haddock! Look in the Haddocks for each thing in+ -- requirementContext (unitState)+ Just decl -> return (Just $ toDeclMapEntry decl, (noDocForDecl, availNoDocs avail))+ | otherwise ->+ return (Nothing, (noDocForDecl, availNoDocs avail))+ | Just iface <- M.lookup (semToIdMod (moduleUnit thisMod) m) modMap+ , Just d <- M.lookup n (ifaceDeclMap iface) =+ return (Just d, lookupDocs avail warnings+ (ifaceDocMap iface)+ (ifaceArgMap iface))+ | otherwise = return (Nothing, (noDocForDecl, availNoDocs avail))+ where+ n = availName avail+ m = nameModule n++ 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.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)++availSubordinates :: AvailInfo -> [Name]+availSubordinates = map greNameMangledName . availSubordinateGreNames++availNoDocs :: AvailInfo -> [(Name, DocForDecl Name)]+availNoDocs avail =+ zip (availSubordinates avail) (repeat noDocForDecl)++-- | Given a 'Module' from a 'Name', convert it into a 'Module' that+-- we can actually find in the 'IfaceMap'.+semToIdMod :: Unit -> Module -> Module+semToIdMod this_uid m+ | Module.isHoleModule m = mkModule this_uid (moduleName m)+ | otherwise = m++hiDecl :: MonadIO m => DynFlags -> Name -> IfM m (Maybe (LHsDecl GhcRn))+hiDecl dflags t = do+ mayTyThing <- lookupName t+ case mayTyThing of+ Nothing -> do+ warn $ "Warning: Not found in environment: " ++ pretty dflags t+ return Nothing+ Just x -> case tyThingToLHsDecl ShowRuntimeRep x of+ Left m -> (warn $ bugWarn m) >> return Nothing+ Right (m, t') -> mapM (warn . bugWarn) m >> return (Just $ noLocA 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++-- | This function is called for top-level bindings without type signatures.+-- It gets the type signature from GHC and that means it's not going to+-- have a meaningful 'SrcSpan'. So we pass down 'SrcSpan' for the+-- declaration and use it instead - 'nLoc' here.+hiValExportItem+ :: MonadIO m => DynFlags -> Name -> SrcSpan -> DocForDecl Name -> Bool+ -> Maybe Fixity -> IfM m (ExportItem GhcRn)+hiValExportItem dflags name nLoc doc splice fixity = do+ mayDecl <- hiDecl dflags name+ case mayDecl of+ Nothing -> return (ExportNoDecl name [])+ Just decl -> return (ExportDecl $ ExportD (fixSpan decl) [] doc [] [] fixities splice)+ where+ fixSpan (L (SrcSpanAnn a l) t) = L (SrcSpanAnn a (SrcLoc.combineSrcSpans l nLoc)) t+ fixities = case fixity of+ Just f -> [(name, f)]+ Nothing -> []+++-- | Lookup docs for a declaration from maps.+lookupDocs :: AvailInfo -> WarningMap -> DocMap Name -> ArgMap Name+ -> (DocForDecl Name, [(Name, DocForDecl Name)])+lookupDocs avail warningMap docMap argMap =+ let n = availName avail in+ let lookupArgDoc x = M.findWithDefault M.empty x argMap in+ let doc = (lookupDoc n, lookupArgDoc n) in+ let subDocs = [ (s, (lookupDoc s, lookupArgDoc s))+ | s <- availSubordinates avail+ ] in+ (doc, subDocs)+ where+ lookupDoc name = Documentation (M.lookup name docMap) (M.lookup name warningMap)+++-- | Export the given module as `ExportModule`. We are not concerned with the+-- single export items of the given module.+moduleExport+ :: MonadIO m+ => Module -- ^ Module A (identity, NOT semantic)+ -> DynFlags -- ^ The flags used when typechecking A+ -> IfaceMap -- ^ Already created interfaces+ -> InstIfaceMap -- ^ Interfaces in other packages+ -> ModuleName -- ^ The exported module+ -> IfM m [ExportItem GhcRn] -- ^ Resulting export items+moduleExport thisMod dflags ifaceMap instIfaceMap expMod =+ -- NB: we constructed the identity module when looking up in+ -- the IfaceMap.+ case M.lookup m ifaceMap of+ Just iface+ | OptHide `elem` ifaceOptions iface -> return (ifaceExportItems iface)+ | otherwise -> return [ ExportModule m ]++ Nothing -> -- We have to try to find it in the installed interfaces+ -- (external packages).+ case M.lookup expMod (M.mapKeys moduleName instIfaceMap) of+ Just iface -> return [ ExportModule (instMod iface) ]+ Nothing -> do+ warn $+ "Warning: " ++ pretty dflags thisMod ++ ": Could not find " +++ "documentation for exported module: " ++ pretty dflags expMod+ return []+ where+ m = mkModule (moduleUnit thisMod) expMod -- Identity module!++-- Note [1]:+------------+-- It is unnecessary to document a subordinate by itself at the top level if+-- any of its parents is also documented. Furthermore, if the subordinate is a+-- record field or a class method, documenting it under its parent+-- indicates its special status.+--+-- A user might expect that it should show up separately, so we issue a+-- warning. It's a fine opportunity to also tell the user she might want to+-- export the subordinate through the parent export item for clarity.+--+-- The code removes top-level subordinates also when the parent is exported+-- through a 'module' export. I think that is fine.+--+-- (For more information, see Trac #69)+++-- | Simplified variant of 'mkExportItems', where we can assume that+-- every locally defined declaration is exported; thus, we just+-- zip through the renamed declarations.++fullModuleContents+ :: MonadIO m+ => Bool -- is it a signature+ -> IfaceMap+ -> Maybe Package -- this package+ -> Module -- this module+ -> Module -- semantic module+ -> WarningMap+ -> GlobalRdrEnv -- ^ The renaming environment+ -> [Name] -- exported names (orig)+ -> [LHsDecl GhcRn] -- renamed source declarations+ -> Maps+ -> FixMap+ -> [SrcSpan] -- splice locations+ -> InstIfaceMap+ -> DynFlags+ -> Avails+ -> IfM m [ExportItem GhcRn]+fullModuleContents is_sig modMap pkgName thisMod semMod warnings gre exportedNames+ decls maps@(_, _, declMap, _) fixMap splices instIfaceMap dflags avails = do+ let availEnv = availsToNameEnv (nubAvails avails)+ (concat . concat) `fmap` (for decls $ \decl -> do+ case decl of+ (L _ (DocD _ (DocGroup lev docStr))) -> do+ !doc <- force <$> processDocString dflags gre (hsDocString . unLoc $ docStr)+ return [[ExportGroup lev "" doc]]+ (L _ (DocD _ (DocCommentNamed _ docStr))) -> do+ !doc <- force <$> processDocStringParas dflags pkgName gre (hsDocString . unLoc $ docStr)+ return [[ExportDoc doc]]+ (L _ (ValD _ valDecl))+ | name:_ <- collectHsBindBinders CollNoDictBinders valDecl+ , Just (EOther (L _ SigD{})) <- M.lookup name declMap+ -> return []+ _ ->+ for (getMainDeclBinder emptyOccEnv (unLoc decl)) $ \nm -> do+ case lookupNameEnv availEnv nm of+ Just avail ->+ availExportItem is_sig modMap thisMod+ semMod warnings exportedNames maps fixMap+ splices instIfaceMap dflags avail+ Nothing -> pure [])++-- | 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+-- together a type signature for it...).+--+-- This function looks through the declarations in this module to try to find+-- the one with the right name.+extractDecl+ :: HasCallStack+ => DeclMap -- ^ all declarations in the file+ -> Name -- ^ name of the declaration to extract+ -> LHsDecl GhcRn -- ^ parent declaration+ -> Either String (LHsDecl GhcRn)+extractDecl declMap name decl+ | name `elem` getMainDeclBinder emptyOccEnv (unLoc decl) = pure 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 (L pos (SigD noExtField sig))+ (_, [L pos fam_decl]) -> pure (L pos (TyClD noExtField (FamDecl noExtField fam_decl)))++ ([], [])+ | Just (EOther famInstDecl) <- M.lookup name declMap+ -> extractDecl declMap name famInstDecl+ _ -> Left (concat [ "Ambiguous decl for ", getOccString name+ , " in class ", getOccString clsNm ])++ TyClD _ d@DataDecl { tcdLName = L _ dataNm+ , tcdDataDefn = HsDataDefn { dd_cons = dataCons } } -> 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+ , Just (EOther famInst) <- M.lookup name declMap+ -> extractDecl declMap name famInst+ InstD _ (DataFamInstD _ (DataFamInstDecl+ (FamEqn { feqn_tycon = L _ n+ , feqn_pats = tys+ , feqn_rhs = defn }))) ->+ 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 declMap name (noLocA (InstD noExtField (DataFamInstD noExtField d0)))+ _ -> 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 declMap name (noLocA . InstD noExtField $ DataFamInstD noExtField d0)+ _ -> Left "internal: extractDecl (ClsInstD)"+ _ -> 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 noAnn (HsUnrestrictedArrow noHsUniTok) 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 l ki) = HsAppKindTy l 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 noAnn (HsUnrestrictedArrow noHsUniTok) 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 l ki) = HsAppKindTy l 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 _ = True+++mkVisibleNames :: Maps -> [ExportItem GhcRn] -> [DocOption] -> [Name]+mkVisibleNames (_, _, _, instMap) exports opts+ | OptHide `elem` opts = []+ | 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.+ exportName _ = []++seqList :: [a] -> ()+seqList [] = ()+seqList (x : xs) = x `seq` seqList xs++-- | Find a stand-alone documentation comment by its name.+findNamedDoc :: MonadIO m => String -> [HsDecl GhcRn] -> IfM m (Maybe HsDocString)+findNamedDoc name = search+ where+ search [] = do+ -- TODO: Make sure this isn't duplicating messages+ warn $ "Cannot find documentation for: $" ++ name+ return Nothing+ search (DocD _ (DocCommentNamed name' doc) : rest)+ | name == name' = return (Just (hsDocString . unLoc $ doc))+ | otherwise = search rest search (_other_decl : rest) = search rest
+ src/Haddock/Interface/Json.hs view
@@ -0,0 +1,268 @@+{-# LANGUAGE RecordWildCards #-}+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.Utils.Outputable++import Control.Arrow+import Data.Map (Map)+import qualified Data.Map as Map++import Haddock.Types+import Haddock.InterfaceFile++jsonInterfaceFile :: InterfaceFile -> JsonDoc+jsonInterfaceFile InterfaceFile{..} =+ 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)+ ]++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))+ ]++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) (_version _meta))])+ , ("document", jsonDoc _doc)+ ]++showModName :: Wrap (ModuleName, OccName) -> String+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+ [ ("tag", jsonString "DocAppend")+ , ("first", jsonDoc x)+ , ("second", jsonDoc y)+ ]++jsonDoc (DocString s) = jsonObject+ [ ("tag", jsonString "DocString")+ , ("string", jsonString s)+ ]++jsonDoc (DocParagraph x) = jsonObject+ [ ("tag", jsonString "DocParagraph")+ , ("document", jsonDoc x)+ ]++jsonDoc (DocIdentifier name) = jsonObject+ [ ("tag", jsonString "DocIdentifier")+ , ("name", jsonString (showName name))+ ]++jsonDoc (DocIdentifierUnchecked modName) = jsonObject+ [ ("tag", jsonString "DocIdentifierUnchecked")+ , ("modName", jsonString (showModName modName))+ ]++jsonDoc (DocModule (ModLink m _l)) = jsonObject+ [ ("tag", jsonString "DocModule")+ , ("string", jsonString m)+ ]++jsonDoc (DocWarning x) = jsonObject+ [ ("tag", jsonString "DocWarning")+ , ("document", jsonDoc x)+ ]++jsonDoc (DocEmphasis x) = jsonObject+ [ ("tag", jsonString "DocEmphasis")+ , ("document", jsonDoc x)+ ]++jsonDoc (DocMonospaced x) = jsonObject+ [ ("tag", jsonString "DocMonospaced")+ , ("document", jsonDoc x)+ ]++jsonDoc (DocBold x) = jsonObject+ [ ("tag", jsonString "DocBold")+ , ("document", jsonDoc x)+ ]++jsonDoc (DocUnorderedList xs) = jsonObject+ [ ("tag", jsonString "DocUnorderedList")+ , ("documents", jsonArray (fmap jsonDoc xs))+ ]++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+ [ ("tag", jsonString "DocDefList")+ , ("definitions", jsonArray (fmap jsonDef xys))+ ]+ where+ jsonDef (x, y) = jsonObject [("document", jsonDoc x), ("y", jsonDoc y)]++jsonDoc (DocCodeBlock x) = jsonObject+ [ ("tag", jsonString "DocCodeBlock")+ , ("document", jsonDoc x)+ ]++jsonDoc (DocHyperlink hyperlink) = jsonObject+ [ ("tag", jsonString "DocHyperlink")+ , ("hyperlink", jsonHyperlink hyperlink)+ ]+ where+ jsonHyperlink Hyperlink{..} = jsonObject+ [ ("hyperlinkUrl", jsonString hyperlinkUrl)+ , ("hyperlinkLabel", jsonMaybe jsonDoc hyperlinkLabel)+ ]++jsonDoc (DocPic picture) = jsonObject+ [ ("tag", jsonString "DocPic")+ , ("picture", jsonPicture picture)+ ]+ where+ jsonPicture Picture{..} = jsonObject+ [ ("pictureUrl", jsonString pictureUri)+ , ("pictureLabel", jsonMaybe jsonString pictureTitle)+ ]++jsonDoc (DocMathInline s) = jsonObject+ [ ("tag", jsonString "DocMathInline")+ , ("string", jsonString s)+ ]++jsonDoc (DocMathDisplay s) = jsonObject+ [ ("tag", jsonString "DocMathDisplay")+ , ("string", jsonString s)+ ]++jsonDoc (DocAName s) = jsonObject+ [ ("tag", jsonString "DocAName")+ , ("string", jsonString s)+ ]++jsonDoc (DocProperty s) = jsonObject+ [ ("tag", jsonString "DocProperty")+ , ("string", jsonString s)+ ]++jsonDoc (DocExamples examples) = jsonObject+ [ ("tag", jsonString "DocExamples")+ , ("examples", jsonArray (fmap jsonExample examples))+ ]+ where+ jsonExample Example{..} = jsonObject+ [ ("exampleExpression", jsonString exampleExpression)+ , ("exampleResult", jsonArray (fmap jsonString exampleResult))+ ]++jsonDoc (DocHeader header) = jsonObject+ [ ("tag", jsonString "DocHeader")+ , ("header", jsonHeader header)+ ]+ where+ jsonHeader Header{..} = jsonObject+ [ ("headerLevel", jsonInt headerLevel)+ , ("headerTitle", jsonDoc headerTitle)+ ]++jsonDoc (DocTable table) = jsonObject+ [ ("tag", jsonString "DocTable")+ , ("table", jsonTable table)+ ]+ where+ jsonTable Table{..} = jsonObject+ [ ("tableHeaderRows", jsonArray (fmap jsonTableRow tableHeaderRows))+ , ("tableBodyRows", jsonArray (fmap jsonTableRow tableBodyRows))+ ]++ jsonTableRow TableRow{..} = jsonArray (fmap jsonTableCell tableRowCells)++ jsonTableCell TableCell{..} = jsonObject+ [ ("tableCellColspan", jsonInt tableCellColspan)+ , ("tableCellRowspan", jsonInt tableCellRowspan)+ , ("tableCellContents", jsonDoc tableCellContents)+ ]+++jsonModule :: Module -> JsonDoc+jsonModule = JSString . moduleStableString++jsonName :: Name -> JsonDoc+jsonName = JSString . nameStableString++jsonFixity :: Fixity -> JsonDoc+jsonFixity (Fixity _ prec dir) =+ jsonObject [ ("prec" , jsonInt prec)+ , ("direction" , jsonFixityDirection dir)+ ]++jsonFixityDirection :: FixityDirection -> JsonDoc+jsonFixityDirection InfixL = jsonString "infixl"+jsonFixityDirection InfixR = jsonString "infixr"+jsonFixityDirection InfixN = jsonString "infix"++renderJson :: JsonDoc -> SDoc+renderJson = renderJSON++jsonMaybe :: (a -> JsonDoc) -> Maybe a -> JsonDoc+jsonMaybe = maybe jsonNull++jsonString :: String -> JsonDoc+jsonString = JSString++jsonObject :: [(String, JsonDoc)] -> JsonDoc+jsonObject = JSObject++jsonArray :: [JsonDoc] -> JsonDoc+jsonArray = JSArray++jsonNull :: JsonDoc+jsonNull = JSNull++jsonInt :: Int -> JsonDoc+jsonInt = JSInt++jsonBool :: Bool -> JsonDoc+jsonBool = JSBool
src/Haddock/Interface/LexParseRn.hs view
@@ -1,5 +1,7 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -Wwarn #-}-{-# LANGUAGE BangPatterns #-} ----------------------------------------------------------------------------- -- | -- Module : Haddock.Interface.LexParseRn@@ -13,68 +15,117 @@ ----------------------------------------------------------------------------- module Haddock.Interface.LexParseRn ( processDocString+ , processDocStringFromString , processDocStringParas , processDocStrings , processModuleHeader ) where -import Data.IntSet (toList)-import Data.List+import Control.Arrow+import Control.Monad+import Control.Monad.State.Strict+import Data.Functor+import Data.List ((\\), maximumBy)+import Data.Ord+import qualified Data.Set as Set import Documentation.Haddock.Doc (metaDocConcat)-import DynFlags (languageExtensions)+import GHC.Driver.Session (languageExtensions) import qualified GHC.LanguageExtensions as LangExt-import FastString import GHC import Haddock.Interface.ParseModuleHeader import Haddock.Parser import Haddock.Types-import Name-import Outputable ( showPpr )-import RdrName-import RnEnv (dataTcOccs)+import GHC.Data.EnumSet as EnumSet+import GHC.Driver.Ppr ( showPpr, showSDoc )+import GHC.Parser.PostProcess+import GHC.Types.Name+import GHC.Types.Avail ( availName )+import GHC.Types.Name.Reader+import GHC.Utils.Outputable (Outputable) -processDocStrings :: DynFlags -> GlobalRdrEnv -> [HsDocString]- -> Maybe (MDoc Name)-processDocStrings dflags gre strs =- case metaDocConcat $ map (processDocStringParas dflags gre) strs of+processDocStrings+ :: MonadIO m+ => DynFlags+ -> Maybe Package+ -> GlobalRdrEnv+ -> [HsDocString]+ -> IfM m (Maybe (MDoc Name))+processDocStrings dflags pkg gre strs = do+ mdoc <- metaDocConcat <$> traverse (processDocStringParas dflags pkg gre) strs+ case mdoc of -- We check that we don't have any version info to render instead -- of just checking if there is no comment: there may not be a -- comment but we still want to pass through any meta data.- MetaDoc { _meta = Meta { _version = Nothing }, _doc = DocEmpty } -> Nothing- x -> Just x+ MetaDoc { _meta = Meta Nothing Nothing, _doc = DocEmpty } -> pure Nothing+ x -> pure (Just x) -processDocStringParas :: DynFlags -> GlobalRdrEnv -> HsDocString -> MDoc Name-processDocStringParas dflags gre (HsDocString fs) =- overDoc (rename dflags gre) $ parseParas dflags (unpackFS fs)+processDocStringParas+ :: MonadIO m+ => DynFlags+ -> Maybe Package+ -> GlobalRdrEnv+ -> HsDocString+ -> IfM m (MDoc Name)+processDocStringParas dflags pkg gre hds =+ overDocF (rename dflags gre) (parseParas dflags pkg (renderHsDocString hds)) -processDocString :: DynFlags -> GlobalRdrEnv -> HsDocString -> Doc Name-processDocString dflags gre (HsDocString fs) =- rename dflags gre $ parseString dflags (unpackFS fs)+processDocString+ :: MonadIO m+ => DynFlags+ -> GlobalRdrEnv+ -> HsDocString+ -> IfM m (Doc Name)+processDocString dflags gre hds =+ processDocStringFromString dflags gre (renderHsDocString hds) -processModuleHeader :: DynFlags -> GlobalRdrEnv -> SafeHaskellMode -> Maybe LHsDocString- -> ErrMsgM (HaddockModInfo Name, Maybe (MDoc Name))-processModuleHeader dflags gre safety mayStr = do+processDocStringFromString+ :: MonadIO m+ => DynFlags+ -> GlobalRdrEnv+ -> String+ -> IfM m (Doc Name)+processDocStringFromString dflags gre hds =+ rename dflags gre (parseString dflags hds)++processModuleHeader+ :: MonadIO m+ => DynFlags+ -> Maybe Package+ -> GlobalRdrEnv+ -> SafeHaskellMode+ -> Maybe HsDocString+ -> IfM m (HaddockModInfo Name, Maybe (MDoc Name))+processModuleHeader dflags pkgName gre safety mayStr = do (hmi, doc) <- case mayStr of Nothing -> return failure- Just (L _ (HsDocString fs)) -> do- let str = unpackFS fs- (hmi, doc) = parseModuleHeader dflags str- !descr = rename dflags gre <$> hmi_description hmi- hmi' = hmi { hmi_description = descr }- doc' = overDoc (rename dflags gre) doc+ Just hds -> do+ let str = renderHsDocString hds+ (hmi, doc) = parseModuleHeader dflags pkgName str+ !descr <- case hmi_description hmi of+ Just hmi_descr -> Just <$> rename dflags gre hmi_descr+ Nothing -> pure Nothing+ let hmi' = hmi { hmi_description = descr }+ doc' <- overDocF (rename dflags gre) 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 = map toEnum (toList $ extensionFlags dflags) \\ languageExtensions (language dflags)- return (hmi { hmi_safety = Just $ showPpr dflags safety- , hmi_language = language dflags- , hmi_extensions = flags- } , doc)+ flags = EnumSet.toList (extensionFlags dflags) \\ languageExtensions (language dflags)+ return+ (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)+ -- | Takes a 'GlobalRdrEnv' which (hopefully) contains all the -- definitions and a parsed comment and we attempt to make sense of -- where the identifiers in the comment point to. We're in effect@@ -82,25 +133,45 @@ -- fallbacks in case we can't locate the identifiers. -- -- See the comments in the source for implementation commentary.-rename :: DynFlags -> GlobalRdrEnv -> Doc RdrName -> Doc Name+rename+ :: MonadIO m+ => DynFlags+ -> GlobalRdrEnv+ -> Doc NsRdrName+ -> IfM m (Doc Name) rename dflags gre = rn where+ rn :: MonadIO m => Doc NsRdrName -> IfM m (Doc Name) rn d = case d of- DocAppend a b -> DocAppend (rn a) (rn b)- DocParagraph doc -> DocParagraph (rn doc)- DocIdentifier x -> do+ DocAppend a b -> DocAppend <$> rn a <*> rn b+ DocParagraph p -> DocParagraph <$> rn p+ DocIdentifier i -> do+ let NsRdrName ns x = unwrap i+ occ = rdrNameOcc x+ isValueName = isDataOcc occ || isVarOcc occ++ let valueNsChoices | isValueName = [x]+ | otherwise = [] -- is this ever possible?+ typeNsChoices | isValueName = [setRdrNameSpace x tcName]+ | otherwise = [x]+ -- Generate the choices for the possible kind of thing this- -- is.- let choices = dataTcOccs x- -- Try to look up all the names in the GlobalRdrEnv that match- -- the names.- let names = concatMap (\c -> map gre_name (lookupGRE_RdrName c gre)) choices+ -- 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 - case names of+ -- Lookup any GlobalRdrElts that match the choices.+ case concatMap (\c -> lookupGRE_RdrName c gre) choices of -- We found no names in the env so we start guessing. [] -> case choices of- [] -> DocMonospaced (DocString (showPpr dflags x))+ -- The only way this can happen is if a value namespace was+ -- specified on something that cannot be a value.+ [] -> invalidValue dflags i+ -- There was nothing in the environment so we need to -- pick some default from what's available to us. We -- diverge here from the old way where we would default@@ -109,52 +180,133 @@ -- type constructor names (such as in #253). So now we -- only get type constructor links if they are actually -- in scope.- a:_ -> outOfScope dflags a+ a:_ -> outOfScope dflags ns (i $> a) -- There is only one name in the environment that matches so -- use it.- [a] -> DocIdentifier a- -- But when there are multiple names available, default to- -- type constructors: somewhat awfully GHC returns the- -- values in the list positionally.- a:b:_ | isTyConName a -> DocIdentifier a- | otherwise -> DocIdentifier b+ [a] -> pure $ DocIdentifier (i $> greMangledName a) - DocWarning doc -> DocWarning (rn doc)- DocEmphasis doc -> DocEmphasis (rn doc)- DocBold doc -> DocBold (rn doc)- DocMonospaced doc -> DocMonospaced (rn doc)- DocUnorderedList docs -> DocUnorderedList (map rn docs)- DocOrderedList docs -> DocOrderedList (map rn docs)- DocDefList list -> DocDefList [ (rn a, rn b) | (a, b) <- list ]- DocCodeBlock doc -> DocCodeBlock (rn doc)- DocIdentifierUnchecked x -> DocIdentifierUnchecked x- DocModule str -> DocModule str- DocHyperlink l -> DocHyperlink l- DocPic str -> DocPic str- DocMathInline str -> DocMathInline str- DocMathDisplay str -> DocMathDisplay str- DocAName str -> DocAName str- DocProperty p -> DocProperty p- DocExamples e -> DocExamples e- DocEmpty -> DocEmpty- DocString str -> DocString str- DocHeader (Header l t) -> DocHeader $ Header l (rn t)+ -- There are multiple names available.+ gres -> ambiguous dflags i gres + DocWarning dw -> DocWarning <$> rn dw+ DocEmphasis de -> DocEmphasis <$> rn de+ DocBold db -> DocBold <$> rn db+ DocMonospaced dm -> DocMonospaced <$> rn dm+ DocUnorderedList docs -> DocUnorderedList <$> traverse rn docs+ DocOrderedList docs -> DocOrderedList <$> traverseSnd rn docs+ DocDefList list -> DocDefList <$> traverse (\(a, b) -> (,) <$> rn a <*> rn b) list+ DocCodeBlock dcb -> DocCodeBlock <$> rn dcb+ DocIdentifierUnchecked x -> pure (DocIdentifierUnchecked x)+ DocModule (ModLink m l) -> DocModule . ModLink m <$> traverse rn l+ DocHyperlink (Hyperlink u l) -> DocHyperlink . Hyperlink u <$> traverse rn l+ DocPic str -> pure (DocPic str)+ DocMathInline str -> pure (DocMathInline str)+ DocMathDisplay str -> pure (DocMathDisplay str)+ DocAName str -> pure (DocAName str)+ DocProperty p -> pure (DocProperty p)+ DocExamples e -> pure (DocExamples e)+ DocEmpty -> pure (DocEmpty)+ DocString str -> pure (DocString str)+ DocHeader (Header l t) -> DocHeader . Header l <$> rn t+ DocTable t -> DocTable <$> traverse rn t+ -- | Wrap an identifier that's out of scope (i.e. wasn't found in -- 'GlobalReaderEnv' during 'rename') in an appropriate doc. Currently -- we simply monospace the identifier in most cases except when the -- identifier is qualified: if the identifier is qualified then we can--- still try to guess and generate anchors accross modules but the+-- still try to guess and generate anchors across modules but the -- users shouldn't rely on this doing the right thing. See tickets -- #253 and #375 on the confusion this causes depending on which -- default we pick in 'rename'.-outOfScope :: DynFlags -> RdrName -> Doc a-outOfScope dflags x =- case x of- Unqual occ -> monospaced occ- Qual mdl occ -> DocIdentifierUnchecked (mdl, occ)- Orig _ occ -> monospaced occ- Exact name -> monospaced name -- Shouldn't happen since x is out of scope+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 where- monospaced a = DocMonospaced (DocString (showPpr dflags a))+ prefix =+ case ns of+ Value -> "the value "+ Type -> "the type "+ None -> ""++ warnAndMonospace :: (MonadIO m, Outputable a) => Wrap a -> IfM m (DocH mod id)+ warnAndMonospace a = do+ let a' = showWrapped (showPpr dflags) a++ -- If we have already warned for this identifier, don't warn again+ 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) })++ pure (monospaced a')+ monospaced = DocMonospaced . DocString++-- | Handle ambiguous identifiers.+--+-- Prefers local names primarily and type constructors or class names secondarily.+--+-- Emits a warning if the 'GlobalRdrElts's don't belong to the same type or class.+ambiguous+ :: MonadIO m+ => DynFlags+ -> Wrap NsRdrName+ -> [GlobalRdrElt] -- ^ More than one @gre@s sharing the same `RdrName` above.+ -> IfM m (Doc Name)+ambiguous dflags x gres = do+ let noChildren = map availName (gresToAvailInfo gres)+ dflt = maximumBy (comparing (isLocalName &&& isTyConName)) noChildren+ nameStr = showNsRdrName dflags x+ msg = "Warning: " ++ nameStr ++ " is ambiguous. It is defined\n" +++ concatMap (\n -> " * " ++ defnLoc n ++ "\n") (map greMangledName gres) +++ " 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.++ -- 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))+ where+ isLocalName (nameSrcLoc -> RealSrcLoc {}) = True+ isLocalName _ = False+ defnLoc = showSDoc dflags . pprNameDefnLoc++-- | Handle value-namespaced names that cannot be for values.+--+-- Emits a warning that the value-namespace is invalid on a non-value identifier.+invalidValue :: MonadIO m => DynFlags -> Wrap NsRdrName -> IfM m (Doc a)+invalidValue dflags x = do+ let nameStr = showNsRdrName dflags x++ -- If we have already warned for this name, do not warn again+ firstWarn <- Set.notMember nameStr <$> gets ifeInvalidValues+ when firstWarn $ do+ warn $+ "Warning: " ++ nameStr ++ " cannot be value, yet it is\n" +++ " namespaced as such. Did you mean to specify a type namespace\n" +++ " instead?"+ modify' (\env -> env { ifeInvalidValues = Set.insert nameStr (ifeInvalidValues env) })+ pure (DocMonospaced (DocString (showNsRdrName dflags x)))++-- | Printable representation of a wrapped and namespaced name+showNsRdrName :: DynFlags -> Wrap NsRdrName -> String+showNsRdrName dflags = (\p i -> p ++ "'" ++ i ++ "'") <$> prefix <*> ident+ where+ ident = showWrapped (showPpr dflags . rdrName)+ prefix = renderNs . namespace . unwrap
src/Haddock/Interface/ParseModuleHeader.hs view
@@ -1,4 +1,6 @@ {-# OPTIONS_GHC -Wwarn #-}+{-# LANGUAGE DeriveFunctor #-}+ ----------------------------------------------------------------------------- -- | -- Module : Haddock.Interface.ParseModuleHeader@@ -11,12 +13,12 @@ ----------------------------------------------------------------------------- module Haddock.Interface.ParseModuleHeader (parseModuleHeader) where -import Control.Monad (mplus)+import Control.Applicative (Alternative (..))+import Control.Monad (ap) import Data.Char-import DynFlags+import GHC.Driver.Session import Haddock.Parser import Haddock.Types-import RdrName -- ----------------------------------------------------------------------------- -- Parsing module headers@@ -24,36 +26,47 @@ -- NB. The headers must be given in the order Module, Description, -- Copyright, License, Maintainer, Stability, Portability, except that -- any or all may be omitted.-parseModuleHeader :: DynFlags -> String -> (HaddockModInfo RdrName, MDoc RdrName)-parseModuleHeader dflags str0 =+parseModuleHeader :: DynFlags -> Maybe Package -> String -> (HaddockModInfo NsRdrName, MDoc NsRdrName)+parseModuleHeader dflags pkgName str0 = let- getKey :: String -> String -> (Maybe String,String)- getKey key str = case parseKey key str of- Nothing -> (Nothing,str)- Just (value,rest) -> (Just value,rest)+ kvs :: [(String, String)]+ str1 :: String - (_moduleOpt,str1) = getKey "Module" str0- (descriptionOpt,str2) = getKey "Description" str1- (copyrightOpt,str3) = getKey "Copyright" str2- (licenseOpt,str4) = getKey "License" str3- (licenceOpt,str5) = getKey "Licence" str4- (maintainerOpt,str6) = getKey "Maintainer" str5- (stabilityOpt,str7) = getKey "Stability" str6- (portabilityOpt,str8) = getKey "Portability" str7+ (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 = licenseOpt `mplus` licenceOpt,+ 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 str8)+ }, parseParas dflags pkgName str1) --- | This function is how we read keys.+-------------------------------------------------------------------------------+-- Small parser to parse module header.+-------------------------------------------------------------------------------++-- | The below is a small parser framework how we read keys. -- -- all fields in the header are optional and have the form --@@ -72,78 +85,105 @@ -- -- the value will be "this is a .. description" and the rest will begin -- at "The module comment".-parseKey :: String -> String -> Maybe (String,String)-parseKey key toParse0 =- do- let- (spaces0,toParse1) = extractLeadingSpaces (dropWhile (`elem` ['\r', '\n']) toParse0) - indentation = spaces0- afterKey0 <- extractPrefix key toParse1- let- afterKey1 = extractLeadingSpaces afterKey0- afterColon0 <- case snd afterKey1 of- ':':afterColon -> return afterColon- _ -> Nothing- let- (_,afterColon1) = extractLeadingSpaces afterColon0+-- | 'C' is a 'Char' carrying its column.+--+-- This let us make an indentation-aware parser, as we know current indentation.+-- 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 - return (scanKey True indentation afterColon1)- where- scanKey :: Bool -> String -> String -> (String,String)- scanKey _ _ [] = ([],[])- scanKey isFirst indentation str =- let- (nextLine,rest1) = extractNextLine str+newtype P a = P { unP :: [C] -> Maybe ([C], a) }+ deriving Functor - accept = isFirst || sufficientIndentation || allSpaces+instance Applicative P where+ pure x = P $ \s -> Just (s, x)+ (<*>) = ap - sufficientIndentation = case extractPrefix indentation nextLine of- Just (c:_) | isSpace c -> True- _ -> False+instance Monad P where+ return = pure+ m >>= k = P $ \s0 -> do+ (s1, x) <- unP m s0+ unP (k x) s1 - allSpaces = case extractLeadingSpaces nextLine of- (_,[]) -> True- _ -> False- in- if accept- then- let- (scanned1,rest2) = scanKey False indentation rest1+instance Alternative P where+ empty = P $ \_ -> Nothing+ a <|> b = P $ \s -> unP a s <|> unP b s - scanned2 = case scanned1 of- "" -> if allSpaces then "" else nextLine- _ -> nextLine ++ "\n" ++ scanned1- in- (scanned2,rest2)- else- ([],str)+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']+ | l <- lines input+ ] - extractLeadingSpaces :: String -> (String,String)- extractLeadingSpaces [] = ([],[])- extractLeadingSpaces (s@(c:cs))- | isSpace c =- let- (spaces1,cs1) = extractLeadingSpaces cs- in- (c:spaces1,cs1)- | otherwise = ([],s)+-------------------------------------------------------------------------------+--+------------------------------------------------------------------------------- - extractNextLine :: String -> (String,String)- extractNextLine [] = ([],[])- extractNextLine (c:cs)- | c == '\n' =- ([],cs)- | otherwise =- let- (line,rest) = extractNextLine cs- in- (c:line,rest)+curInd :: P Int+curInd = P $ \s -> Just . (,) s $ case s of+ [] -> 0+ C i _ : _ -> i - -- comparison is case-insensitive.- extractPrefix :: String -> String -> Maybe String- extractPrefix [] s = Just s- extractPrefix _ [] = Nothing- extractPrefix (c1:cs1) (c2:cs2)- | toUpper c1 == toUpper c2 = extractPrefix cs1 cs2- | otherwise = Nothing+rest :: P String+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)+ where+ p' (C i c)+ | 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+ where+ p' (C i c)+ | 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++skipSpaces :: P ()+skipSpaces = P $ \cs -> Just (dropWhile (\(C _ c) -> isSpace c) cs, ())++takeWhileMaybe :: (a -> Maybe b) -> [a] -> ([b], [a])+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)++-------------------------------------------------------------------------------+-- Fields+-------------------------------------------------------------------------------++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)++fields :: P ([(String, String)], String)+fields = do+ skipSpaces+ i <- curInd+ fs <- many (field i)+ r <- rest+ return (fs, r)+
src/Haddock/Interface/Rename.hs view
@@ -1,4 +1,9 @@-{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+ ---------------------------------------------------------------------------- -- | -- Module : Haddock.Interface.Rename@@ -15,285 +20,437 @@ import Data.Traversable (mapM) +import Haddock.Backends.Hoogle (ppExportD) import Haddock.GhcUtils import Haddock.Types -import Bag (emptyBag)+import GHC.Data.Bag (emptyBag) import GHC hiding (NoLink)-import Name+import GHC.Types.Name+import GHC.Types.Name.Reader (RdrName(Exact))+import GHC.Builtin.Types (eqTyCon_RDR) import Control.Applicative+import Control.DeepSeq (force) import Control.Monad hiding (mapM)-import Data.List-import qualified Data.Map as Map hiding ( Map )+import Control.Monad.Reader+import Control.Monad.Writer.CPS+import Data.Foldable (traverse_)+import qualified Data.Map.Strict as Map+import qualified Data.Set as Set import Prelude hiding (mapM)---renameInterface :: DynFlags -> LinkEnv -> Bool -> Interface -> ErrMsgM Interface-renameInterface dflags renamingEnv warnings iface =-- -- first create the local env, where every name exported by this module- -- is mapped to itself, and everything else comes from the global renaming- -- env- let localEnv = foldl fn renamingEnv (ifaceVisibleExports iface)- where fn env name = Map.insert name (ifaceMod iface) env-- -- rename names in the exported declarations to point to things that- -- are closer to, or maybe even exported by, the current module.- (renamedExportItems, missingNames1)- = runRnFM localEnv (renameExportItems (ifaceExportItems iface))-- (rnDocMap, missingNames2) = runRnFM localEnv (mapM renameDoc (ifaceDocMap iface))+import GHC.Types.Basic ( TopLevelFlag(..) ) - (rnArgMap, missingNames3) = runRnFM localEnv (mapM (mapM renameDoc) (ifaceArgMap iface))+-- | Traverse docstrings and ASTs in the Haddock interface, renaming 'Name' to+-- 'DocName'.+--+-- What this really boils down to is: for each 'Name', figure out which of the+-- modules that export the name is the preferred place to link to.+--+-- The renamed output gets written into fields in the Haddock interface record+-- that were previously left empty.+renameInterface+ :: DynFlags+ -- ^ GHC session dyn flags+ -> Map.Map (Maybe String) (Set.Set String)+ -- ^ Ignored symbols. A map from module names to unqualified names. Module+ -- 'Just M' mapping to name 'f' means that link warnings should not be+ -- generated for occurances of specifically 'M.f'. Module 'Nothing' mapping to+ -- name 'f' means that link warnings should not be generated for any 'f'.+ -> LinkEnv+ -- ^ Link environment. A map from 'Name' to 'Module', where name 'n' maps to+ -- module 'M' if 'M' is the preferred link destination for name 'n'.+ -> Bool+ -- ^ Are warnings enabled?+ -> Bool+ -- ^ Is Hoogle output enabled?+ -> Interface+ -- ^ The interface we are renaming.+ -> Ghc Interface+ -- ^ The renamed interface. Note that there is nothing really special about+ -- 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'+ where+ -- The current module+ mdl :: Module+ mdl = ifaceMod iface - (renamedOrphanInstances, missingNames4)- = runRnFM localEnv (mapM renameDocInstance (ifaceOrphanInstances iface))+ -- The local link environment, where every name exported by this module is+ -- mapped to the module itself, and everything else comes from the global+ -- renaming env+ localLinkEnv :: LinkEnv+ localLinkEnv = foldr f renamingEnv (ifaceVisibleExports iface)+ where f name !env = Map.insert name mdl env - (finalModuleDoc, missingNames5)- = runRnFM localEnv (renameDocumentation (ifaceDoc iface))+ -- 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 - -- combine the missing names and filter out the built-ins, which would- -- otherwise always be missing.- missingNames = nub $ filter isExternalName -- XXX: isExternalName filters out too much- (missingNames1 ++ missingNames2 ++ missingNames3- ++ missingNames4 ++ missingNames5)+ -- Current module must not be hidden from Haddock+ && not (OptHide `elem` ifaceOptions iface) - -- filter out certain built in type constructors using their string- -- representation. TODO: use the Name constants from the GHC API.--- strings = filter (`notElem` ["()", "[]", "(->)"])--- (map pretty missingNames)- strings = map (pretty dflags) . filter (\n -> not (isSystemName n || isBuiltInSyntax n)) $ missingNames+ -- 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 - in do- -- report things that we couldn't link to. Only do this for non-hidden- -- modules.- unless (OptHide `elem` ifaceOptions iface || null strings || not warnings) $- tell ["Warning: " ++ moduleString (ifaceMod iface) ++- ": could not find link destinations for:\n"++- unwords (" " : strings) ]+ -- 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+ -- in unioned with the set of globally ignored symbols+ ignoreSet' :: Set.Set String+ ignoreSet' =+ Set.union+ (Map.findWithDefault Set.empty (Just $ modString name) ignoreSet)+ (Map.findWithDefault Set.empty Nothing ignoreSet) - return $ iface { ifaceRnDoc = finalModuleDoc,- ifaceRnDocMap = rnDocMap,- ifaceRnArgMap = rnArgMap,- ifaceRnExportItems = renamedExportItems,- ifaceRnOrphanInstances = renamedOrphanInstances}+ modString :: Name -> String+ modString = moduleString . nameModule +-- | Output warning messages indicating that the renamer could not find link+-- destinations for the names in the given set as they occur in the given+-- 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+ where+ qualifiedName :: Name -> String+ qualifiedName name = moduleString (nameModule name) ++ "." ++ getOccString name -------------------------------------------------------------------------------- -- Monad for renaming------ The monad does two things for us: it passes around the environment for--- renaming, and it returns a list of names which couldn't be found in--- the environment. -------------------------------------------------------------------------------- --newtype RnM a =- RnM { unRn :: (Name -> (Bool, DocName)) -- name lookup function- -> (a,[Name])- }--instance Monad RnM where- (>>=) = thenRn- return = pure--instance Functor RnM where- fmap f x = do a <- x; return (f a)--instance Applicative RnM where- pure = returnRn- (<*>) = ap+-- | 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 }+ deriving newtype (Functor, Applicative, Monad, MonadReader RnMEnv, MonadWriter (Set.Set Name)) -returnRn :: a -> RnM a-returnRn a = RnM (const (a,[]))-thenRn :: RnM a -> (a -> RnM b) -> RnM b-m `thenRn` k = RnM (\lkp -> case unRn m lkp of- (a,out1) -> case unRn (k a) lkp of- (b,out2) -> (b,out1++out2))+-- | 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 -getLookupRn :: RnM (Name -> (Bool, DocName))-getLookupRn = RnM (\lkp -> (lkp,[]))+ -- | Link warning predicate (whether failing to find a link destination+ -- for a given name should result in a warning)+ , rnWarnName :: (Name -> Bool) -outRn :: Name -> RnM ()-outRn name = RnM (const ((),[name]))+ -- | The current module+ , rnModuleString :: String -lookupRn :: Name -> RnM DocName-lookupRn name = do- lkp <- getLookupRn- case lkp name of- (False,maps_to) -> do outRn name; return maps_to- (True, maps_to) -> return maps_to+ -- | Should Hoogle output be generated for this module?+ , rnHoogleOutput :: Bool + -- | GHC Session DynFlags, necessary for Hoogle output generation+ , rnDynFlags :: DynFlags+ } -runRnFM :: LinkEnv -> RnM a -> (a,[Name])-runRnFM env rn = unRn rn lkp+-- | Run the renamer action in a renaming environment built using the given+-- module, link env, and link warning predicate. Returns the renamed value along+-- with a set of 'Name's that were not renamed and should be warned for (i.e.+-- 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 where- lkp n = case Map.lookup n env of- Nothing -> (False, Undocumented n)- Just mdl -> (True, Documented n mdl)-+ rnEnv :: RnMEnv+ rnEnv = RnMEnv+ { rnLinkEnv = linkEnv+ , rnWarnName = warnName+ , rnModuleString = moduleString mdl+ , rnHoogleOutput = hoogleOutput+ , rnDynFlags = dflags+ } -------------------------------------------------------------------------------- -- Renaming -------------------------------------------------------------------------------- +-- | Rename an `Interface` in the renaming environment.+renameInterfaceRn :: Interface -> RnM Interface+renameInterfaceRn iface = do+ exportItems <- renameExportItems (ifaceExportItems iface)+ orphans <- mapM renameDocInstance (ifaceOrphanInstances iface)+ finalModDoc <- renameDocumentation (ifaceDoc iface)+ pure $! iface+ { ifaceRnDoc = finalModDoc -rename :: Name -> RnM DocName-rename = lookupRn+ -- 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 = []+ } -renameL :: Located Name -> RnM (Located DocName)-renameL = mapM rename+-- | 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 +-- | 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 -renameExportItems :: [ExportItem Name] -> RnM [ExportItem DocName]+-- | Rename a located 'Name' in the current renaming environment.+renameNameL :: GenLocated l Name -> RnM (GenLocated l DocName)+renameNameL = mapM renameName++-- | Rename a list of export items in the current renaming environment.+renameExportItems :: [ExportItem GhcRn] -> RnM [ExportItem DocNameI] renameExportItems = mapM renameExportItem +-- | Rename an 'ExportItem' in the current renaming environment.+renameExportItem :: ExportItem GhcRn -> RnM (ExportItem DocNameI)+renameExportItem item = case item of+ ExportModule mdl -> return (ExportModule mdl)+ ExportGroup lev id_ doc -> do+ doc' <- renameDoc doc+ return (ExportGroup lev id_ doc')+ 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+ [] + decl' <- renameLDecl decl+ pats' <- renamePats pats+ doc' <- renameDocForDecl doc+ subs' <- mapM renameSub subs+ instances' <- forM instances renameDocInstance+ fixities' <- forM fixities $ \(name, fixity) -> do+ name' <- lookupRn name+ return (name', fixity)++ return $+ ExportDecl RnExportD+ { rnExpDExpD = ExportD decl' pats' doc' subs' instances' fixities' splice+ , rnExpDHoogle = hoogleOut+ }+ ExportNoDecl x subs -> do+ x' <- lookupRn x+ subs' <- mapM lookupRn subs+ return (ExportNoDecl x' subs')+ ExportDoc doc -> do+ doc' <- renameDoc doc+ return (ExportDoc doc')+ renameDocForDecl :: DocForDecl Name -> RnM (DocForDecl DocName) renameDocForDecl (doc, fnArgsDoc) = (,) <$> renameDocumentation doc <*> renameFnArgsDoc fnArgsDoc - renameDocumentation :: Documentation Name -> RnM (Documentation DocName) renameDocumentation (Documentation mDoc mWarning) = Documentation <$> mapM renameDoc mDoc <*> mapM renameDoc mWarning --renameLDocHsSyn :: LHsDocString -> RnM LHsDocString-renameLDocHsSyn = return-+renameLDocHsSyn :: Located (WithHsDocIdentifiers HsDocString a) -> RnM (Located (WithHsDocIdentifiers HsDocString b))+renameLDocHsSyn (L l doc) = return (L l (WithHsDocIdentifiers (hsDocString doc) [])) -renameDoc :: Traversable t => t Name -> RnM (t DocName)-renameDoc = traverse rename+renameDoc :: Traversable t => t (Wrap Name) -> RnM (t (Wrap DocName))+renameDoc = traverse (traverse renameName) renameFnArgsDoc :: FnArgsDoc Name -> RnM (FnArgsDoc DocName) renameFnArgsDoc = mapM renameDoc --renameLType :: LHsType Name -> RnM (LHsType DocName)+renameLType :: LHsType GhcRn -> RnM (LHsType DocNameI) renameLType = mapM renameType -renameLSigType :: LHsSigType Name -> RnM (LHsSigType DocName)-renameLSigType = renameImplicit renameLType+renameLTypeArg :: LHsTypeArg GhcRn -> RnM (LHsTypeArg DocNameI)+renameLTypeArg (HsValArg ty) = do { ty' <- renameLType ty+ ; return $ HsValArg ty' }+renameLTypeArg (HsTypeArg l ki) = do { ki' <- renameLKind ki+ ; return $ HsTypeArg l ki' }+renameLTypeArg (HsArgPar sp) = return $ HsArgPar sp -renameLSigWcType :: LHsSigWcType Name -> RnM (LHsSigWcType DocName)-renameLSigWcType = renameImplicit (renameWc renameLType)+renameLSigType :: LHsSigType GhcRn -> RnM (LHsSigType DocNameI)+renameLSigType = mapM renameSigType -renameLKind :: LHsKind Name -> RnM (LHsKind DocName)+renameLSigWcType :: LHsSigWcType GhcRn -> RnM (LHsSigWcType DocNameI)+renameLSigWcType = renameWc renameLSigType++renameLKind :: LHsKind GhcRn -> RnM (LHsKind DocNameI) renameLKind = renameLType -renameMaybeLKind :: Maybe (LHsKind Name) -> RnM (Maybe (LHsKind DocName))+renameMaybeLKind :: Maybe (LHsKind GhcRn) -> RnM (Maybe (LHsKind DocNameI)) renameMaybeLKind = traverse renameLKind -renameFamilyResultSig :: LFamilyResultSig Name -> RnM (LFamilyResultSig DocName)-renameFamilyResultSig (L loc NoSig)- = return (L loc NoSig)-renameFamilyResultSig (L loc (KindSig ki))+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 ki')) }-renameFamilyResultSig (L loc (TyVarSig bndr))+ ; return (L loc (KindSig noExtField ki')) }+renameFamilyResultSig (L loc (TyVarSig _ bndr)) = do { bndr' <- renameLTyVarBndr bndr- ; return (L loc (TyVarSig bndr')) }+ ; return (L loc (TyVarSig noExtField bndr')) } -renameInjectivityAnn :: LInjectivityAnn Name -> RnM (LInjectivityAnn DocName)-renameInjectivityAnn (L loc (InjectivityAnn lhs rhs))- = do { lhs' <- renameL lhs- ; rhs' <- mapM renameL rhs- ; return (L loc (InjectivityAnn lhs' rhs')) }+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 Name)- -> RnM (Maybe (LInjectivityAnn DocName))+renameMaybeInjectivityAnn :: Maybe (LInjectivityAnn GhcRn)+ -> RnM (Maybe (LInjectivityAnn DocNameI)) renameMaybeInjectivityAnn = traverse renameInjectivityAnn -renameType :: HsType Name -> RnM (HsType DocName)+renameArrow :: HsArrow GhcRn -> RnM (HsArrow DocNameI)+renameArrow (HsUnrestrictedArrow arr) = return (HsUnrestrictedArrow arr)+renameArrow (HsLinearArrow (HsPct1 pct1 arr)) = return (HsLinearArrow (HsPct1 pct1 arr))+renameArrow (HsLinearArrow (HsLolly arr)) = return (HsLinearArrow (HsLolly arr))+renameArrow (HsExplicitMult pct p arr) = (\p' -> HsExplicitMult pct p' arr) <$> renameLType p++renameType :: HsType GhcRn -> RnM (HsType DocNameI) renameType t = case t of- HsForAllTy { hst_bndrs = tyvars, hst_body = ltype } -> do- tyvars' <- mapM renameLTyVarBndr tyvars- ltype' <- renameLType ltype- return (HsForAllTy { hst_bndrs = tyvars', hst_body = ltype' })+ 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 lcontext' <- renameLContext lcontext ltype' <- renameLType ltype- return (HsQualTy { hst_ctxt = lcontext', hst_body = ltype' })+ return (HsQualTy { hst_xqual = noAnn, hst_ctxt = lcontext', hst_body = ltype' }) - HsTyVar (L l n) -> return . HsTyVar . L l =<< rename n- HsBangTy b ltype -> return . HsBangTy b =<< renameLType ltype+ HsTyVar _ ip (L l n) -> return . HsTyVar noAnn ip . L l =<< renameName n+ HsBangTy _ b ltype -> return . HsBangTy noAnn b =<< renameLType ltype - HsAppTy a b -> do+ HsStarTy _ isUni -> return (HsStarTy noAnn isUni)++ HsAppTy _ a b -> do a' <- renameLType a b' <- renameLType b- return (HsAppTy a' b')+ return (HsAppTy noAnn a' b') - HsFunTy a b -> do+ 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- return (HsFunTy a' b')+ w' <- renameArrow w+ return (HsFunTy noAnn w' a' b') - HsListTy ty -> return . HsListTy =<< renameLType ty- HsPArrTy ty -> return . HsPArrTy =<< renameLType ty- HsIParamTy n ty -> liftM (HsIParamTy n) (renameLType ty)- HsEqTy ty1 ty2 -> liftM2 HsEqTy (renameLType ty1) (renameLType ty2)+ HsListTy _ ty -> return . (HsListTy noAnn) =<< renameLType ty+ HsIParamTy _ n ty -> liftM (HsIParamTy noAnn n) (renameLType ty) - HsTupleTy b ts -> return . HsTupleTy b =<< mapM renameLType ts+ HsTupleTy _ b ts -> return . HsTupleTy noAnn b =<< mapM renameLType ts+ HsSumTy _ ts -> HsSumTy noAnn <$> mapM renameLType ts - HsOpTy a (L loc op) b -> do- op' <- rename op+ HsOpTy _ prom a (L loc op) b -> do+ op' <- renameName op a' <- renameLType a b' <- renameLType b- return (HsOpTy a' (L loc op') b')+ return (HsOpTy noAnn prom a' (L loc op') b') - HsParTy ty -> return . HsParTy =<< renameLType ty+ HsParTy _ ty -> return . (HsParTy noAnn) =<< renameLType ty - HsKindSig ty k -> do+ HsKindSig _ ty k -> do ty' <- renameLType ty k' <- renameLKind k- return (HsKindSig ty' k')+ return (HsKindSig noAnn ty' k') - HsDocTy ty doc -> do+ HsDocTy _ ty doc -> do ty' <- renameLType ty doc' <- renameLDocHsSyn doc- return (HsDocTy ty' doc')+ return (HsDocTy noAnn ty' doc') - HsTyLit x -> return (HsTyLit x)+ HsTyLit _ x -> return (HsTyLit noAnn (renameTyLit x)) - HsRecTy a -> HsRecTy <$> mapM renameConDeclFieldField a- HsCoreTy a -> pure (HsCoreTy a)- HsExplicitListTy a b -> HsExplicitListTy a <$> mapM renameLType b- HsExplicitTupleTy a b -> HsExplicitTupleTy a <$> mapM renameLType b- HsSpliceTy _ _ -> error "renameType: HsSpliceTy"- HsWildCardTy a -> HsWildCardTy <$> renameWildCardInfo a- HsAppsTy _ -> error "renameType: HsAppsTy"+ HsRecTy _ a -> HsRecTy noAnn <$> mapM renameConDeclFieldField a+ XHsType a -> pure (XHsType a)+ HsExplicitListTy _ a b -> HsExplicitListTy noAnn a <$> mapM renameLType b+ 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) -renameLHsQTyVars :: LHsQTyVars Name -> RnM (LHsQTyVars DocName)-renameLHsQTyVars (HsQTvs { hsq_implicit = _, hsq_explicit = tvs })+renameTyLit :: HsTyLit GhcRn -> HsTyLit DocNameI+renameTyLit t = case t of+ 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+ bndrs' <- renameOuterTyVarBndrs bndrs+ 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 tvs- ; return (HsQTvs { hsq_implicit = error "haddock:renameLHsQTyVars", hsq_explicit = tvs', hsq_dependent = error "haddock:renameLHsQTyVars" }) }- -- This is rather bogus, but I'm not sure what else to do+ ; return (HsQTvs { hsq_ext = noExtField+ , hsq_explicit = tvs' }) } -renameLTyVarBndr :: LHsTyVarBndr Name -> RnM (LHsTyVarBndr DocName)-renameLTyVarBndr (L loc (UserTyVar (L l n)))- = do { n' <- rename n- ; return (L loc (UserTyVar (L l n'))) }-renameLTyVarBndr (L loc (KindedTyVar (L lv n) kind))- = do { n' <- rename n+renameHsForAllTelescope :: HsForAllTelescope GhcRn -> RnM (HsForAllTelescope DocNameI)+renameHsForAllTelescope tele = case tele of+ HsForAllVis _ bndrs -> do bndrs' <- mapM renameLTyVarBndr bndrs+ pure $ HsForAllVis noExtField bndrs'+ HsForAllInvis _ bndrs -> do bndrs' <- mapM renameLTyVarBndr bndrs+ pure $ HsForAllInvis noExtField bndrs'++renameLTyVarBndr :: LHsTyVarBndr flag GhcRn -> RnM (LHsTyVarBndr flag DocNameI)+renameLTyVarBndr (L loc (UserTyVar _ fl (L l n)))+ = do { n' <- renameName n+ ; return (L loc (UserTyVar noExtField fl (L l n'))) }+renameLTyVarBndr (L loc (KindedTyVar _ fl (L lv n) kind))+ = do { n' <- renameName n ; kind' <- renameLKind kind- ; return (L loc (KindedTyVar (L lv n') kind')) }+ ; return (L loc (KindedTyVar noExtField fl (L lv n') kind')) } -renameLContext :: Located [LHsType Name] -> RnM (Located [LHsType DocName])+renameLContext :: LocatedC [LHsType GhcRn] -> RnM (LocatedC [LHsType DocNameI]) renameLContext (L loc context) = do context' <- mapM renameLType context return (L loc context') -renameWildCardInfo :: HsWildCardInfo Name -> RnM (HsWildCardInfo DocName)-renameWildCardInfo (AnonWildCard (L l name)) = AnonWildCard . L l <$> rename name--renameInstHead :: InstHead Name -> RnM (InstHead DocName)+renameInstHead :: InstHead GhcRn -> RnM (InstHead DocNameI) renameInstHead InstHead {..} = do- cname <- rename ihdClsName- kinds <- mapM renameType ihdKinds+ cname <- renameName ihdClsName types <- mapM renameType ihdTypes itype <- case ihdInstType of ClassInst { .. } -> ClassInst@@ -305,299 +462,358 @@ DataInst dd -> DataInst <$> renameTyClD dd return InstHead { ihdClsName = cname- , ihdKinds = kinds , ihdTypes = types , ihdInstType = itype } -renameLDecl :: LHsDecl Name -> RnM (LHsDecl DocName)+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')}) -renameDecl :: HsDecl Name -> RnM (HsDecl DocName)+renameDecl :: HsDecl GhcRn -> RnM (HsDecl DocNameI) renameDecl decl = case decl of- TyClD d -> do+ TyClD _ d -> do d' <- renameTyClD d- return (TyClD d')- SigD s -> do+ return (TyClD noExtField d')+ SigD _ s -> do s' <- renameSig s- return (SigD s')- ForD d -> do+ return (SigD noExtField s')+ ForD _ d -> do d' <- renameForD d- return (ForD d')- InstD d -> do+ return (ForD noExtField d')+ InstD _ d -> do d' <- renameInstD d- return (InstD d')+ return (InstD noExtField d')+ DerivD _ d -> do+ d' <- renameDerivD d+ return (DerivD noExtField d') _ -> error "renameDecl" -renameLThing :: (a Name -> RnM (a DocName)) -> Located (a Name) -> RnM (Located (a DocName))-renameLThing fn (L loc x) = return . L loc =<< fn x+renameLThing :: (a GhcRn -> RnM (a DocNameI)) -> LocatedAn an (a GhcRn) -> RnM (Located (a DocNameI))+renameLThing fn (L loc x) = return . L (locA loc) =<< fn x -renameTyClD :: TyClDecl Name -> RnM (TyClDecl DocName)+renameTyClD :: TyClDecl GhcRn -> RnM (TyClDecl DocNameI) renameTyClD d = case d of -- TyFamily flav lname ltyvars kind tckind -> do FamDecl { tcdFam = decl } -> do decl' <- renameFamilyDecl decl- return (FamDecl { tcdFam = decl' })+ return (FamDecl { tcdFExt = noExtField, tcdFam = decl' }) - SynDecl { tcdLName = lname, tcdTyVars = tyvars, tcdRhs = rhs, tcdFVs = _fvs } -> do- lname' <- renameL lname+ SynDecl { tcdLName = lname, tcdTyVars = tyvars, tcdFixity = fixity, tcdRhs = rhs } -> do+ lname' <- renameNameL lname tyvars' <- renameLHsQTyVars tyvars rhs' <- renameLType rhs- return (SynDecl { tcdLName = lname', tcdTyVars = tyvars', tcdRhs = rhs', tcdFVs = placeHolderNames })+ return (SynDecl { tcdSExt = noExtField, tcdLName = lname', tcdTyVars = tyvars'+ , tcdFixity = fixity, tcdRhs = rhs' }) - DataDecl { tcdLName = lname, tcdTyVars = tyvars, tcdDataDefn = defn, tcdFVs = _fvs } -> do- lname' <- renameL lname+ DataDecl { tcdLName = lname, tcdTyVars = tyvars, tcdFixity = fixity, tcdDataDefn = defn } -> do+ lname' <- renameNameL lname tyvars' <- renameLHsQTyVars tyvars defn' <- renameDataDefn defn- return (DataDecl { tcdLName = lname', tcdTyVars = tyvars', tcdDataDefn = defn', tcdDataCusk = PlaceHolder, tcdFVs = placeHolderNames })+ return (DataDecl { tcdDExt = noExtField, tcdLName = lname', tcdTyVars = tyvars'+ , tcdFixity = fixity, tcdDataDefn = defn' }) - ClassDecl { tcdCtxt = lcontext, tcdLName = lname, tcdTyVars = ltyvars+ ClassDecl { tcdLayout = layout+ , tcdCtxt = lcontext, tcdLName = lname, tcdTyVars = ltyvars, tcdFixity = fixity , tcdFDs = lfundeps, tcdSigs = lsigs, tcdATs = ats, tcdATDefs = at_defs } -> do- lcontext' <- renameLContext lcontext- lname' <- renameL lname+ 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 renameLTyFamDefltEqn at_defs+ at_defs' <- mapM (mapM renameTyFamDefltD) at_defs -- we don't need the default methods or the already collected doc entities- return (ClassDecl { tcdCtxt = lcontext', tcdLName = lname', tcdTyVars = ltyvars'+ return (ClassDecl { tcdCExt = noExtField+ , tcdLayout = renameLayoutInfo layout+ , tcdCtxt = lcontext', tcdLName = lname', tcdTyVars = ltyvars'+ , tcdFixity = fixity , tcdFDs = lfundeps', tcdSigs = lsigs', tcdMeths= emptyBag- , tcdATs = ats', tcdATDefs = at_defs', tcdDocs = [], tcdFVs = placeHolderNames })+ , tcdATs = ats', tcdATDefs = at_defs', tcdDocs = [] }) where- renameLFunDep (L loc (xs, ys)) = do- xs' <- mapM rename (map unLoc xs)- ys' <- mapM rename (map unLoc ys)- return (L loc (map noLoc xs', map noLoc ys'))+ renameLFunDep :: LHsFunDep GhcRn -> RnM (LHsFunDep DocNameI)+ renameLFunDep (L loc (FunDep _ xs ys)) = do+ xs' <- mapM renameName (map unLoc xs)+ ys' <- mapM renameName (map unLoc ys)+ return (L (locA loc) (FunDep noExtField (map noLocA xs') (map noLocA ys'))) - renameLSig (L loc sig) = return . L loc =<< renameSig sig+ renameLSig (L loc sig) = return . L (locA loc) =<< renameSig sig -renameFamilyDecl :: FamilyDecl Name -> RnM (FamilyDecl DocName)+renameLayoutInfo :: LayoutInfo GhcRn -> LayoutInfo DocNameI+renameLayoutInfo (ExplicitBraces ob cb) = ExplicitBraces ob cb+renameLayoutInfo (VirtualBraces n) = VirtualBraces n+renameLayoutInfo NoLayoutInfo = NoLayoutInfo++renameFamilyDecl :: FamilyDecl GhcRn -> RnM (FamilyDecl DocNameI) renameFamilyDecl (FamilyDecl { fdInfo = info, fdLName = lname- , fdTyVars = ltyvars, fdResultSig = result+ , fdTyVars = ltyvars+ , fdFixity = fixity+ , fdResultSig = result , fdInjectivityAnn = injectivity }) = do info' <- renameFamilyInfo info- lname' <- renameL lname+ lname' <- renameNameL lname ltyvars' <- renameLHsQTyVars ltyvars result' <- renameFamilyResultSig result injectivity' <- renameMaybeInjectivityAnn injectivity- return (FamilyDecl { fdInfo = info', fdLName = lname'- , fdTyVars = ltyvars', fdResultSig = result'+ return (FamilyDecl { fdExt = noExtField, fdInfo = info', fdTopLevel = TopLevel+ , fdLName = lname'+ , fdTyVars = ltyvars'+ , fdFixity = fixity+ , fdResultSig = result' , fdInjectivityAnn = injectivity' }) -renamePseudoFamilyDecl :: PseudoFamilyDecl Name- -> RnM (PseudoFamilyDecl DocName)+renamePseudoFamilyDecl :: PseudoFamilyDecl GhcRn+ -> RnM (PseudoFamilyDecl DocNameI) renamePseudoFamilyDecl (PseudoFamilyDecl { .. }) = PseudoFamilyDecl <$> renameFamilyInfo pfdInfo- <*> renameL pfdLName+ <*> renameNameL pfdLName <*> mapM renameLType pfdTyVars <*> renameFamilyResultSig pfdKindSig -renameFamilyInfo :: FamilyInfo Name -> RnM (FamilyInfo DocName)+renameFamilyInfo :: FamilyInfo GhcRn -> RnM (FamilyInfo DocNameI) renameFamilyInfo DataFamily = return DataFamily renameFamilyInfo OpenTypeFamily = return OpenTypeFamily renameFamilyInfo (ClosedTypeFamily eqns)- = do { eqns' <- mapM (mapM renameLTyFamInstEqn) eqns+ = do { eqns' <- mapM (mapM (mapM renameTyFamInstEqn)) eqns ; return $ ClosedTypeFamily eqns' } -renameDataDefn :: HsDataDefn Name -> RnM (HsDataDefn DocName)-renameDataDefn (HsDataDefn { dd_ND = nd, dd_ctxt = lcontext, dd_cType = cType+renameDataDefn :: HsDataDefn GhcRn -> RnM (HsDataDefn DocNameI)+renameDataDefn (HsDataDefn { dd_ctxt = lcontext, dd_cType = cType , dd_kindSig = k, dd_cons = cons }) = do- lcontext' <- renameLContext lcontext+ lcontext' <- traverse renameLContext lcontext k' <- renameMaybeLKind k- cons' <- mapM (mapM renameCon) cons+ cons' <- mapM (mapMA renameCon) cons -- I don't think we need the derivings, so we return Nothing- return (HsDataDefn { dd_ND = nd, dd_ctxt = lcontext', dd_cType = cType- , dd_kindSig = k', dd_cons = cons', dd_derivs = Nothing })+ return (HsDataDefn { dd_ext = noExtField+ , dd_ctxt = lcontext', dd_cType = cType+ , dd_kindSig = k', dd_cons = cons'+ , dd_derivs = [] }) -renameCon :: ConDecl Name -> RnM (ConDecl DocName)-renameCon decl@(ConDeclH98 { con_name = lname, con_qvars = ltyvars- , con_cxt = lcontext, con_details = details- , con_doc = mbldoc }) = do- lname' <- renameL lname- ltyvars' <- traverse renameLHsQTyVars ltyvars+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 ltyvars lcontext' <- traverse renameLContext lcontext- details' <- renameDetails details+ 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_dcolon = dcol+ , 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 (decl { con_name = lname', con_qvars = ltyvars', con_cxt = lcontext'- , con_details = details', con_doc = mbldoc' })+ return (ConDeclGADT+ { con_g_ext = noExtField, con_names = lnames'+ , con_dcolon = dcol, con_bndrs = bndrs'+ , con_mb_cxt = lcontext', con_g_args = details'+ , con_res_ty = res_ty', con_doc = mbldoc' }) - where- renameDetails (RecCon (L l fields)) = do- fields' <- mapM renameConDeclFieldField fields- return (RecCon (L l fields'))- renameDetails (PrefixCon ps) = return . PrefixCon =<< mapM renameLType ps- renameDetails (InfixCon a b) = do- a' <- renameLType a- b' <- renameLType b- return (InfixCon a' b')+renameHsScaled :: HsScaled GhcRn (LHsType GhcRn)+ -> RnM (HsScaled DocNameI (LHsType DocNameI))+renameHsScaled (HsScaled w ty) = HsScaled <$> renameArrow w <*> renameLType ty -renameCon decl@(ConDeclGADT { con_names = lnames- , con_type = lty- , con_doc = mbldoc }) = do- lnames' <- mapM renameL lnames- lty' <- renameLSigType lty- mbldoc' <- mapM renameLDocHsSyn mbldoc- return (decl { con_names = lnames'- , con_type = lty', con_doc = mbldoc' })+renameH98Details :: HsConDeclH98Details GhcRn+ -> RnM (HsConDeclH98Details DocNameI)+renameH98Details (RecCon (L l fields)) = do+ fields' <- mapM renameConDeclFieldField fields+ return (RecCon (L (locA l) fields'))+renameH98Details (PrefixCon ts ps) = PrefixCon ts <$> mapM renameHsScaled ps+renameH98Details (InfixCon a b) = do+ a' <- renameHsScaled a+ b' <- renameHsScaled b+ return (InfixCon a' b') -renameConDeclFieldField :: LConDeclField Name -> RnM (LConDeclField DocName)-renameConDeclFieldField (L l (ConDeclField names t doc)) = do+renameGADTDetails :: HsConDeclGADTDetails GhcRn+ -> RnM (HsConDeclGADTDetails DocNameI)+renameGADTDetails (RecConGADT (L l fields) arr) = do+ fields' <- mapM renameConDeclFieldField fields+ return (RecConGADT (L (locA l) fields') arr)+renameGADTDetails (PrefixConGADT ps) = PrefixConGADT <$> mapM renameHsScaled ps++renameConDeclFieldField :: LConDeclField GhcRn -> RnM (LConDeclField DocNameI)+renameConDeclFieldField (L l (ConDeclField _ names t doc)) = do names' <- mapM renameLFieldOcc names t' <- renameLType t doc' <- mapM renameLDocHsSyn doc- return $ L l (ConDeclField names' t' doc')+ return $ L (locA l) (ConDeclField noExtField names' t' doc') -renameLFieldOcc :: LFieldOcc Name -> RnM (LFieldOcc DocName)-renameLFieldOcc (L l (FieldOcc lbl sel)) = do- sel' <- rename sel- return $ L l (FieldOcc lbl sel')+renameLFieldOcc :: LFieldOcc GhcRn -> RnM (LFieldOcc DocNameI)+renameLFieldOcc (L l (FieldOcc sel lbl)) = do+ sel' <- renameName sel+ return $ L l (FieldOcc sel' lbl) -renameSig :: Sig Name -> RnM (Sig DocName)+renameSig :: Sig GhcRn -> RnM (Sig DocNameI) renameSig sig = case sig of- TypeSig lnames ltype -> do- lnames' <- mapM renameL lnames+ TypeSig _ lnames ltype -> do+ lnames' <- mapM renameNameL lnames ltype' <- renameLSigWcType ltype- return (TypeSig lnames' ltype')- ClassOpSig is_default lnames sig_ty -> do- lnames' <- mapM renameL lnames+ return (TypeSig noExtField lnames' ltype')+ ClassOpSig _ is_default lnames sig_ty -> do+ lnames' <- mapM renameNameL lnames ltype' <- renameLSigType sig_ty- return (ClassOpSig is_default lnames' ltype')- PatSynSig lname sig_ty -> do- lname' <- renameL lname+ return (ClassOpSig noExtField is_default lnames' ltype')+ PatSynSig _ lnames sig_ty -> do+ lnames' <- mapM renameNameL lnames sig_ty' <- renameLSigType sig_ty- return $ PatSynSig lname' sig_ty'- FixSig (FixitySig lnames fixity) -> do- lnames' <- mapM renameL lnames- return $ FixSig (FixitySig lnames' fixity)- MinimalSig src (L l s) -> do- s' <- traverse renameL s- return $ MinimalSig src (L l s')+ return $ PatSynSig noExtField lnames' sig_ty'+ FixSig _ (FixitySig _ lnames fixity) -> do+ lnames' <- mapM renameNameL lnames+ return $ FixSig noExtField (FixitySig noExtField lnames' fixity)+ MinimalSig _ (L l s) -> do+ s' <- traverse (traverse lookupRn) s+ return $ MinimalSig noExtField (L l s') -- we have filtered out all other kinds of signatures in Interface.Create _ -> error "expected TypeSig" -renameForD :: ForeignDecl Name -> RnM (ForeignDecl DocName)-renameForD (ForeignImport lname ltype co x) = do- lname' <- renameL lname+renameForD :: ForeignDecl GhcRn -> RnM (ForeignDecl DocNameI)+renameForD (ForeignImport _ lname ltype x) = do+ lname' <- renameNameL lname ltype' <- renameLSigType ltype- return (ForeignImport lname' ltype' co x)-renameForD (ForeignExport lname ltype co x) = do- lname' <- renameL lname+ return (ForeignImport noExtField lname' ltype' (renameForI x))+renameForD (ForeignExport _ lname ltype x) = do+ lname' <- renameNameL lname ltype' <- renameLSigType ltype- return (ForeignExport lname' ltype' co x)+ return (ForeignExport noExtField lname' ltype' (renameForE x)) +renameForI :: ForeignImport GhcRn -> ForeignImport DocNameI+renameForI (CImport _ cconv safety mHeader spec) = CImport noExtField cconv safety mHeader spec -renameInstD :: InstDecl Name -> RnM (InstDecl DocName)+renameForE :: ForeignExport GhcRn -> ForeignExport DocNameI+renameForE (CExport _ spec) = CExport noExtField spec+++renameInstD :: InstDecl GhcRn -> RnM (InstDecl DocNameI) renameInstD (ClsInstD { cid_inst = d }) = do d' <- renameClsInstD d- return (ClsInstD { cid_inst = d' })+ return (ClsInstD { cid_d_ext = noExtField, cid_inst = d' }) renameInstD (TyFamInstD { tfid_inst = d }) = do d' <- renameTyFamInstD d- return (TyFamInstD { tfid_inst = d' })+ return (TyFamInstD { tfid_ext = noExtField, tfid_inst = d' }) renameInstD (DataFamInstD { dfid_inst = d }) = do d' <- renameDataFamInstD d- return (DataFamInstD { dfid_inst = d' })+ return (DataFamInstD { dfid_ext = noExtField, dfid_inst = d' }) -renameClsInstD :: ClsInstDecl Name -> RnM (ClsInstDecl DocName)+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 })++renameDerivStrategy :: DerivStrategy GhcRn -> RnM (DerivStrategy DocNameI)+renameDerivStrategy (StockStrategy a) = pure (StockStrategy a)+renameDerivStrategy (AnyclassStrategy a) = pure (AnyclassStrategy a)+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_overlap_mode = omode+ 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 Name -> RnM (TyFamInstDecl DocName)+renameTyFamInstD :: TyFamInstDecl GhcRn -> RnM (TyFamInstDecl DocNameI) renameTyFamInstD (TyFamInstDecl { tfid_eqn = eqn })- = do { eqn' <- renameLTyFamInstEqn eqn- ; return (TyFamInstDecl { tfid_eqn = eqn'- , tfid_fvs = placeHolderNames }) }+ = do { eqn' <- renameTyFamInstEqn eqn+ ; return (TyFamInstDecl { tfid_xtn = noExtField, tfid_eqn = eqn' }) } -renameLTyFamInstEqn :: LTyFamInstEqn Name -> RnM (LTyFamInstEqn DocName)-renameLTyFamInstEqn (L loc (TyFamEqn { tfe_tycon = tc, tfe_pats = pats, tfe_rhs = rhs }))- = do { tc' <- renameL tc- ; pats' <- renameImplicit (mapM renameLType) pats+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 (L loc (TyFamEqn { tfe_tycon = tc'- , tfe_pats = pats'- , tfe_rhs = rhs' })) }+ ; return (FamEqn { feqn_ext = noExtField+ , feqn_tycon = tc'+ , feqn_bndrs = bndrs'+ , feqn_pats = pats'+ , feqn_fixity = fixity+ , feqn_rhs = rhs' }) } -renameLTyFamDefltEqn :: LTyFamDefltEqn Name -> RnM (LTyFamDefltEqn DocName)-renameLTyFamDefltEqn (L loc (TyFamEqn { tfe_tycon = tc, tfe_pats = tvs, tfe_rhs = rhs }))- = do { tc' <- renameL tc- ; tvs' <- renameLHsQTyVars tvs- ; rhs' <- renameLType rhs- ; return (L loc (TyFamEqn { tfe_tycon = tc'- , tfe_pats = tvs'- , tfe_rhs = rhs' })) }+renameTyFamDefltD :: TyFamDefltDecl GhcRn -> RnM (TyFamDefltDecl DocNameI)+renameTyFamDefltD = renameTyFamInstD -renameDataFamInstD :: DataFamInstDecl Name -> RnM (DataFamInstDecl DocName)-renameDataFamInstD (DataFamInstDecl { dfid_tycon = tc, dfid_pats = pats, dfid_defn = defn })- = do { tc' <- renameL tc- ; pats' <- renameImplicit (mapM renameLType) pats- ; defn' <- renameDataDefn defn- ; return (DataFamInstDecl { dfid_tycon = tc'- , dfid_pats = pats'- , dfid_defn = defn', dfid_fvs = placeHolderNames }) }+renameDataFamInstD :: DataFamInstDecl GhcRn -> RnM (DataFamInstDecl DocNameI)+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' }) } -renameImplicit :: (in_thing -> RnM out_thing)- -> HsImplicitBndrs Name in_thing- -> RnM (HsImplicitBndrs DocName out_thing)-renameImplicit rn_thing (HsIB { hsib_body = thing })- = do { thing' <- rn_thing thing- ; return (HsIB { hsib_body = thing'- , hsib_vars = PlaceHolder }) }+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 exp_bndrs renameWc :: (in_thing -> RnM out_thing)- -> HsWildCardBndrs Name in_thing- -> RnM (HsWildCardBndrs DocName 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_wcs = PlaceHolder, hswc_ctx = Nothing }) }+ , hswc_ext = noExtField }) } -renameDocInstance :: DocInstance Name -> RnM (DocInstance DocName)-renameDocInstance (inst, idoc, L l n) = do+renameDocInstance :: DocInstance GhcRn -> RnM (DocInstance DocNameI)+renameDocInstance (inst, idoc, L l n, m) = do inst' <- renameInstHead inst- n' <- rename n+ n' <- renameName n idoc' <- mapM renameDoc idoc- return (inst', idoc',L l n')--renameExportItem :: ExportItem Name -> RnM (ExportItem DocName)-renameExportItem item = case item of- ExportModule mdl -> return (ExportModule mdl)- ExportGroup lev id_ doc -> do- doc' <- renameDoc doc- return (ExportGroup lev id_ doc')- ExportDecl decl doc subs instances fixities splice -> do- decl' <- renameLDecl decl- doc' <- renameDocForDecl doc- subs' <- mapM renameSub subs- instances' <- forM instances renameDocInstance- fixities' <- forM fixities $ \(name, fixity) -> do- name' <- lookupRn name- return (name', fixity)- return (ExportDecl decl' doc' subs' instances' fixities' splice)- ExportNoDecl x subs -> do- x' <- lookupRn x- subs' <- mapM lookupRn subs- return (ExportNoDecl x' subs')- ExportDoc doc -> do- doc' <- renameDoc doc- return (ExportDoc doc')-+ return (inst', idoc', L l n', m) renameSub :: (Name, DocForDecl Name) -> RnM (DocName, DocForDecl DocName) renameSub (n,doc) = do- n' <- rename n+ n' <- renameName n doc' <- renameDocForDecl doc return (n', doc')
src/Haddock/Interface/Specialize.hs view
@@ -1,23 +1,26 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-} {-# LANGUAGE RecordWildCards #-}-+{-# LANGUAGE GADTs #-}+{-# OPTIONS_GHC -Wno-incomplete-record-updates #-} module Haddock.Interface.Specialize ( specializeInstHead ) where +import Haddock.GhcUtils ( hsTyVarBndrName ) import Haddock.Syb import Haddock.Types import GHC-import Name-import FastString+import GHC.Types.Name+import GHC.Data.FastString+import GHC.Builtin.Types ( listTyConName, unrestrictedFunTyConName ) import Control.Monad-import Control.Monad.Trans.Reader import Control.Monad.Trans.State import Data.Data@@ -28,73 +31,62 @@ import Data.Set (Set) import qualified Data.Set as Set ---- | Instantiate all occurrences of given name with particular type.-specialize :: (Eq name, Typeable name)- => Data a- => name -> HsType name -> a -> a-specialize name details =- everywhere $ mkT step+-- | Instantiate all occurrences of given names with corresponding types.+specialize :: Data a => [(Name, HsType GhcRn)] -> a -> a+specialize specs = go spec_map0 where- step (HsTyVar (L _ name')) | name == name' = details- step typ = typ+ go :: forall x. Data x => Map Name (HsType GhcRn) -> x -> x+ go spec_map = everywhereButType @Name $ mkT $ sugar . strip_kind_sig . specialize_ty_var spec_map + strip_kind_sig :: HsType GhcRn -> HsType GhcRn+ strip_kind_sig (HsKindSig _ (L _ t) _) = t+ strip_kind_sig typ = typ --- | Instantiate all occurrences of given names with corresponding types.------ It is just a convenience function wrapping 'specialize' that supports more--- that one specialization.-specialize' :: (Eq name, Typeable name)- => Data a- => [(name, HsType name)] -> a -> a-specialize' = flip $ foldr (uncurry specialize)+ specialize_ty_var :: Map Name (HsType GhcRn) -> HsType GhcRn -> HsType GhcRn+ specialize_ty_var spec_map (HsTyVar _ _ (L _ name'))+ | Just t <- Map.lookup name' spec_map = t+ specialize_ty_var _ typ = typ + -- This is a tricky recursive definition. By adding in the specializations+ -- one by one, we should avoid infinite loops.+ spec_map0 = foldr (\(n,t) acc -> Map.insert n (go acc t) acc) mempty specs +{-# SPECIALIZE specialize :: [(Name, HsType GhcRn)] -> HsType GhcRn -> HsType GhcRn #-}+ -- | Instantiate given binders with corresponding types. -- -- Again, it is just a convenience function around 'specialize'. Note that -- length of type list should be the same as the number of binders.-specializeTyVarBndrs :: (Eq name, DataId name)- => Data a- => LHsQTyVars name -> [HsType name]- -> a -> a-specializeTyVarBndrs bndrs typs =- specialize' $ zip bndrs' typs+specializeTyVarBndrs :: Data a => LHsQTyVars GhcRn -> [HsType GhcRn] -> a -> a+specializeTyVarBndrs bndrs typs = specialize $ zip bndrs' typs where- bndrs' = map (bname . unLoc) . hsq_explicit $ bndrs- bname (UserTyVar (L _ name)) = name- bname (KindedTyVar (L _ name) _) = name+ bndrs' = map (hsTyVarBndrName . unLoc) . hsq_explicit $ bndrs -specializePseudoFamilyDecl :: (Eq name, DataId name)- => LHsQTyVars name -> [HsType name]- -> PseudoFamilyDecl name- -> PseudoFamilyDecl name-specializePseudoFamilyDecl bndrs typs decl =- decl { pfdTyVars = map specializeTyVars (pfdTyVars decl) }- where- specializeTyVars = specializeTyVarBndrs bndrs typs +specializePseudoFamilyDecl :: LHsQTyVars GhcRn -> [HsType GhcRn]+ -> PseudoFamilyDecl GhcRn+ -> PseudoFamilyDecl GhcRn+specializePseudoFamilyDecl bndrs typs decl =+ decl {pfdTyVars = map (fmap (specializeTyVarBndrs bndrs typs)) (pfdTyVars decl)} -specializeSig :: forall name . (Eq name, DataId name, SetName name)- => LHsQTyVars name -> [HsType name]- -> Sig name- -> Sig name-specializeSig bndrs typs (TypeSig lnames typ) =- TypeSig lnames (typ { hsib_body = (hsib_body typ) { hswc_body = noLoc typ'}})+specializeSig :: LHsQTyVars GhcRn -> [HsType GhcRn]+ -> Sig GhcRn+ -> Sig GhcRn+specializeSig bndrs typs (TypeSig _ lnames typ) =+ TypeSig noAnn lnames (typ {hswc_body = noLocA typ'}) where- true_type :: HsType name- true_type = unLoc (hswc_body (hsib_body typ))- typ' :: HsType name- typ' = rename fv . sugar $ specializeTyVarBndrs bndrs typs true_type- fv = foldr Set.union Set.empty . map freeVariables $ typs+ true_type :: HsSigType GhcRn+ true_type = unLoc (dropWildCards typ)+ typ' :: HsSigType GhcRn+ typ' = rename fv $ specializeTyVarBndrs bndrs typs true_type+ fv = foldr Set.union Set.empty . map freeVariablesType $ typs specializeSig _ _ sig = sig -- | Make all details of instance head (signatures, associated types) -- specialized to that particular instance type.-specializeInstHead :: (Eq name, DataId name, SetName name)- => InstHead name -> InstHead name+specializeInstHead :: InstHead GhcRn -> InstHead GhcRn specializeInstHead ihd@InstHead { ihdInstType = clsi@ClassInst { .. }, .. } = ihd { ihdInstType = instType' } where@@ -113,45 +105,36 @@ -- and tuple literals resulting in types like @[] a@ or @(,,) a b c@. This -- can be fixed using 'sugar' function, that will turn such types into @[a]@ -- and @(a, b, c)@.-sugar :: forall name. (NamedThing name, DataId name)- => HsType name -> HsType name-sugar =- everywhere $ mkT step- where- step :: HsType name -> HsType name- step = sugarOperators . sugarTuples . sugarLists-+sugar :: HsType GhcRn -> HsType GhcRn+sugar = sugarOperators . sugarTuples . sugarLists -sugarLists :: NamedThing name => HsType name -> HsType name-sugarLists (HsAppTy (L _ (HsTyVar (L _ name))) ltyp)- | isBuiltInSyntax name' && strName == "[]" = HsListTy ltyp- where- name' = getName name- strName = occNameString . nameOccName $ name'+sugarLists :: NamedThing (IdP (GhcPass p)) => HsType (GhcPass p) -> HsType (GhcPass p)+sugarLists (HsAppTy _ (L _ (HsTyVar _ _ (L _ name))) ltyp)+ | getName name == listTyConName = HsListTy noAnn ltyp sugarLists typ = typ -sugarTuples :: NamedThing name => HsType name -> HsType name+sugarTuples :: NamedThing (IdP (GhcPass p)) => HsType (GhcPass p) -> HsType (GhcPass p) sugarTuples typ = aux [] typ where- aux apps (HsAppTy (L _ ftyp) atyp) = aux (atyp:apps) ftyp- aux apps (HsParTy (L _ typ')) = aux apps typ'- aux apps (HsTyVar (L _ name))- | isBuiltInSyntax name' && suitable = HsTupleTy HsBoxedTuple apps+ aux apps (HsAppTy _ (L _ ftyp) atyp) = aux (atyp:apps) ftyp+ aux apps (HsParTy _ (L _ typ')) = aux apps typ'+ aux apps (HsTyVar _ _ (L _ name))+ | isBuiltInSyntax name' && suitable = HsTupleTy noAnn HsBoxedOrConstraintTuple apps where name' = getName name- strName = occNameString . nameOccName $ name'+ strName = getOccString name suitable = case parseTupleArity strName of Just arity -> arity == length apps Nothing -> False aux _ _ = typ -sugarOperators :: NamedThing name => HsType name -> HsType name-sugarOperators (HsAppTy (L _ (HsAppTy (L _ (HsTyVar (L l name))) la)) lb)- | isSymOcc $ getOccName name' = mkHsOpTy la (L l name) lb- | isBuiltInSyntax name' && getOccString name == "(->)" = HsFunTy la lb+sugarOperators :: HsType GhcRn -> HsType GhcRn+sugarOperators (HsAppTy _ (L _ (HsAppTy _ (L _ (HsTyVar _ prom (L l name))) la)) lb)+ | isSymOcc $ getOccName name' = mkHsOpTy prom la (L l name) lb+ | unrestrictedFunTyConName == name' = HsFunTy noAnn (HsUnrestrictedArrow noHsUniTok) la lb where name' = getName name sugarOperators typ = typ@@ -193,19 +176,25 @@ -- not converted to 'String' or alike to avoid new allocations. Additionally, -- since it is stored mostly in 'Set', fast comparison of 'FastString' is also -- quite nice.-type NameRep = FastString+newtype NameRep+ = NameRep FastString+ deriving (Eq) +instance Ord NameRep where+ compare (NameRep fs1) (NameRep fs2) = uniqCompareFS fs1 fs2++ getNameRep :: NamedThing name => name -> NameRep-getNameRep = occNameFS . getOccName+getNameRep = NameRep . getOccFS nameRepString :: NameRep -> String-nameRepString = unpackFS+nameRepString (NameRep fs) = unpackFS fs stringNameRep :: String -> NameRep-stringNameRep = mkFastString+stringNameRep = NameRep . mkFastString setInternalNameRep :: SetName name => NameRep -> name -> name-setInternalNameRep = setInternalOccName . mkVarOccFS+setInternalNameRep (NameRep fs) = setInternalOccName (mkVarOccFS fs) setInternalOccName :: SetName name => OccName -> name -> name setInternalOccName occ name =@@ -215,22 +204,39 @@ nname' = mkInternalName (nameUnique nname) occ (nameSrcSpan nname) --- | Compute set of free variables of given type.-freeVariables :: forall name. (NamedThing name, DataId name)- => HsType name -> Set NameRep-freeVariables =- everythingWithState Set.empty Set.union query+-- | Compute set of free variables of a given 'HsType'.+freeVariablesType :: HsType GhcRn -> Set Name+freeVariablesType =+ everythingWithState Set.empty Set.union+ (mkQ (\ctx -> (Set.empty, ctx)) queryType)++-- | Compute set of free variables of a given 'HsType'.+freeVariablesSigType :: HsSigType GhcRn -> Set Name+freeVariablesSigType =+ everythingWithState Set.empty Set.union+ (mkQ (\ctx -> (Set.empty, ctx)) queryType `extQ` querySigType)++queryType :: HsType GhcRn -> Set Name -> (Set Name, Set Name)+queryType term ctx = case term of+ HsForAllTy _ tele _ ->+ (Set.empty, Set.union ctx (teleNames tele))+ HsTyVar _ _ (L _ name)+ | getName name `Set.member` ctx -> (Set.empty, ctx)+ | otherwise -> (Set.singleton $ getName name, ctx)+ _ -> (Set.empty, ctx) where- query term ctx = case cast term :: Maybe (HsType name) of- Just (HsForAllTy bndrs _) ->- (Set.empty, Set.union ctx (bndrsNames bndrs))- Just (HsTyVar (L _ name))- | getName name `Set.member` ctx -> (Set.empty, ctx)- | otherwise -> (Set.singleton $ getNameRep name, ctx)- _ -> (Set.empty, ctx)- bndrsNames = Set.fromList . map (getName . tyVarName . unLoc)+ teleNames :: HsForAllTelescope GhcRn -> Set Name+ teleNames (HsForAllVis _ bndrs) = bndrsNames bndrs+ teleNames (HsForAllInvis _ bndrs) = bndrsNames bndrs +querySigType :: HsSigType GhcRn -> Set Name -> (Set Name, Set Name)+querySigType (HsSig { sig_bndrs = outer_bndrs }) ctx =+ (Set.empty, Set.union ctx (bndrsNames (hsOuterExplicitBndrs outer_bndrs))) +bndrsNames :: [LHsTyVarBndr flag GhcRn] -> Set Name+bndrsNames = Set.fromList . map (getName . tyVarName . unLoc)++ -- | Make given type visually unambiguous. -- -- After applying 'specialize' method, some free type variables may become@@ -238,140 +244,140 @@ -- @(a -> b)@ we get @(a -> b) -> b@ where first occurrence of @b@ refers to -- different type variable than latter one. Applying 'rename' function -- will fix that type to be visually unambiguous again (making it something--- like @(a -> c) -> b@).-rename :: SetName name => Set NameRep -> HsType name -> HsType name-rename fv typ = runReader (renameType typ) $ RenameEnv- { rneFV = fv- , rneCtx = Map.empty- }-+-- like @(a -> b0) -> b@).+rename :: Set Name -> HsSigType GhcRn -> HsSigType GhcRn+rename fv typ = evalState (renameSigType typ) env+ where+ env = RenameEnv+ { rneHeadFVs = Map.fromList . map mkPair . Set.toList $ fv+ , rneSigFVs = Set.map getNameRep $ freeVariablesSigType typ+ , rneCtx = Map.empty+ }+ mkPair name = (getNameRep name, name) -- | Renaming monad.-type Rename name = Reader (RenameEnv name)---- | Binding generation monad.-type Rebind name = State (RenameEnv name)+type Rename name = State (RenameEnv name) data RenameEnv name = RenameEnv- { rneFV :: Set NameRep- , rneCtx :: Map Name name- }+ { rneHeadFVs :: Map NameRep Name+ , rneSigFVs :: Set NameRep+ , rneCtx :: Map Name name+ } -renameType :: SetName name => HsType name -> Rename name (HsType name)-renameType (HsForAllTy bndrs lt) = rebind bndrs $ \bndrs' ->- HsForAllTy- <$> pure bndrs'+renameSigType :: HsSigType GhcRn -> Rename (IdP GhcRn) (HsSigType GhcRn)+renameSigType (HsSig x bndrs body) =+ HsSig x <$> renameOuterTyVarBndrs bndrs <*> renameLType body++renameOuterTyVarBndrs :: HsOuterTyVarBndrs flag GhcRn+ -> Rename (IdP GhcRn) (HsOuterTyVarBndrs flag GhcRn)+renameOuterTyVarBndrs (HsOuterImplicit imp_tvs) =+ HsOuterImplicit <$> mapM renameName imp_tvs+renameOuterTyVarBndrs (HsOuterExplicit x exp_bndrs) =+ HsOuterExplicit x <$> mapM renameLBinder exp_bndrs++renameType :: HsType GhcRn -> Rename (IdP GhcRn) (HsType GhcRn)+renameType (HsForAllTy x tele lt) =+ HsForAllTy x+ <$> renameForAllTelescope tele <*> renameLType lt-renameType (HsQualTy lctxt lt) =- HsQualTy- <$> located renameContext lctxt+renameType (HsQualTy x lctxt lt) =+ HsQualTy x+ <$> renameLContext lctxt <*> renameLType lt-renameType (HsTyVar name) = HsTyVar <$> located renameName name-renameType (HsAppTy lf la) = HsAppTy <$> renameLType lf <*> renameLType la-renameType (HsFunTy la lr) = HsFunTy <$> renameLType la <*> renameLType lr-renameType (HsListTy lt) = HsListTy <$> renameLType lt-renameType (HsPArrTy lt) = HsPArrTy <$> renameLType lt-renameType (HsTupleTy srt lt) = HsTupleTy srt <$> mapM renameLType lt-renameType (HsOpTy la lop lb) =- HsOpTy <$> renameLType la <*> located renameName lop <*> renameLType lb-renameType (HsParTy lt) = HsParTy <$> renameLType lt-renameType (HsIParamTy ip lt) = HsIParamTy ip <$> renameLType lt-renameType (HsEqTy la lb) = HsEqTy <$> renameLType la <*> renameLType lb-renameType (HsKindSig lt lk) = HsKindSig <$> renameLType lt <*> pure lk+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+renameType (HsAppKindTy x lt lk) = HsAppKindTy x <$> renameLType lt <*> renameLKind lk+renameType (HsFunTy x w la lr) = HsFunTy x <$> renameHsArrow w <*> renameLType la <*> renameLType lr+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 prom la lop lb) =+ HsOpTy x prom <$> 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 renameType t@(HsSpliceTy _ _) = pure t-renameType (HsDocTy lt doc) = HsDocTy <$> renameLType lt <*> pure doc-renameType (HsBangTy bang lt) = HsBangTy bang <$> renameLType lt-renameType t@(HsRecTy _) = pure t-renameType t@(HsCoreTy _) = pure t-renameType (HsExplicitListTy ph ltys) =- HsExplicitListTy ph <$> renameLTypes ltys-renameType (HsExplicitTupleTy phs ltys) =- HsExplicitTupleTy phs <$> renameLTypes ltys-renameType t@(HsTyLit _) = pure t+renameType (HsDocTy x lt doc) = HsDocTy x <$> renameLType lt <*> pure doc+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+renameType (HsExplicitTupleTy x ltys) =+ HsExplicitTupleTy x <$> renameLTypes ltys+renameType t@(HsTyLit _ _) = pure t renameType (HsWildCardTy wc) = pure (HsWildCardTy wc)-renameType (HsAppsTy _) = error "HsAppsTy: Only used before renaming" +renameHsArrow :: HsArrow GhcRn -> Rename (IdP GhcRn) (HsArrow GhcRn)+renameHsArrow (HsExplicitMult pct p arr) = (\p' -> HsExplicitMult pct p' arr) <$> renameLType p+renameHsArrow mult = pure mult -renameLType :: SetName name => LHsType name -> Rename name (LHsType name)++renameLType :: LHsType GhcRn -> Rename (IdP GhcRn) (LHsType GhcRn) renameLType = located renameType +renameLKind :: LHsKind GhcRn -> Rename (IdP GhcRn) (LHsKind GhcRn)+renameLKind = renameLType -renameLTypes :: SetName name => [LHsType name] -> Rename name [LHsType name]+renameLTypes :: [LHsType GhcRn] -> Rename (IdP GhcRn) [LHsType GhcRn] renameLTypes = mapM renameLType +renameLContext :: LHsContext GhcRn -> Rename (IdP GhcRn) (LHsContext GhcRn)+renameLContext (L l ctxt) = do+ ctxt' <- renameContext ctxt+ return (L l ctxt') -renameContext :: SetName name => HsContext name -> Rename name (HsContext name)+renameContext :: HsContext GhcRn -> Rename (IdP GhcRn) (HsContext GhcRn) renameContext = renameLTypes -{--renameLTyOp :: SetName name => LHsTyOp name -> Rename name (LHsTyOp name)-renameLTyOp (wrap, lname) = (,) wrap <$> located renameName lname--}+renameForAllTelescope :: HsForAllTelescope GhcRn+ -> Rename (IdP GhcRn) (HsForAllTelescope GhcRn)+renameForAllTelescope (HsForAllVis x bndrs) =+ HsForAllVis x <$> mapM renameLBinder bndrs+renameForAllTelescope (HsForAllInvis x bndrs) =+ HsForAllInvis x <$> mapM renameLBinder bndrs +renameBinder :: HsTyVarBndr flag GhcRn -> Rename (IdP GhcRn) (HsTyVarBndr flag GhcRn)+renameBinder (UserTyVar x fl lname) = UserTyVar x fl <$> locatedN renameName lname+renameBinder (KindedTyVar x fl lname lkind) =+ KindedTyVar x fl <$> locatedN renameName lname <*> located renameType lkind +renameLBinder :: LHsTyVarBndr flag GhcRn -> Rename (IdP GhcRn) (LHsTyVarBndr flag GhcRn)+renameLBinder = located renameBinder++-- | Core renaming logic. renameName :: SetName name => name -> Rename name name renameName name = do- RenameEnv { rneCtx = ctx } <- ask- pure $ fromMaybe name (Map.lookup (getName name) ctx)---rebind :: SetName name- => [LHsTyVarBndr name] -> ([LHsTyVarBndr name] -> Rename name a)- -> Rename name a-rebind lbndrs action = do- (lbndrs', env') <- runState (rebindLTyVarBndrs lbndrs) <$> ask- local (const env') (action lbndrs')---rebindLTyVarBndrs :: SetName name- => [LHsTyVarBndr name] -> Rebind name [LHsTyVarBndr name]-rebindLTyVarBndrs lbndrs = mapM (located rebindTyVarBndr) lbndrs---rebindTyVarBndr :: SetName name- => HsTyVarBndr name -> Rebind name (HsTyVarBndr name)-rebindTyVarBndr (UserTyVar (L l name)) =- UserTyVar . L l <$> rebindName name-rebindTyVarBndr (KindedTyVar name kinds) =- KindedTyVar <$> located rebindName name <*> pure kinds---rebindName :: SetName name => name -> Rebind name name-rebindName name = do RenameEnv { .. } <- get- taken <- takenNames case Map.lookup (getName name) rneCtx of- Just name' -> pure name'- Nothing | getNameRep name `Set.member` taken -> freshName name- Nothing -> reuseName name+ 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 -> Rebind name name+freshName :: SetName name => name -> Rename name name freshName name = do- env@RenameEnv { .. } <- get taken <- takenNames let name' = setInternalNameRep (findFreshName taken rep) name- put $ env { rneCtx = Map.insert nname name' rneCtx }+ modify $ \rne -> rne+ { rneCtx = Map.insert (getName name) name' (rneCtx rne) } return name' where nname = getName name rep = getNameRep nname -reuseName :: SetName name => name -> Rebind name name-reuseName name = do- env@RenameEnv { .. } <- get- put $ env { rneCtx = Map.insert (getName name) name rneCtx }- return name---takenNames :: NamedThing name => Rebind name (Set NameRep)+takenNames :: NamedThing name => Rename name (Set NameRep) takenNames = do RenameEnv { .. } <- get- return $ Set.union rneFV (ctxElems rneCtx)+ return $ Set.unions [headReps rneHeadFVs, rneSigFVs, ctxElems rneCtx] where+ headReps = Set.fromList . Map.keys ctxElems = Set.fromList . map getNameRep . Map.elems @@ -383,24 +389,19 @@ alternativeNames :: NameRep -> [NameRep]-alternativeNames name- | [_] <- nameRepString name = letterNames ++ alternativeNames' name- where- letterNames = map (stringNameRep . pure) ['a'..'z']-alternativeNames name = alternativeNames' name---alternativeNames' :: NameRep -> [NameRep]-alternativeNames' name =+alternativeNames name = [ stringNameRep $ str ++ show i | i :: Int <- [0..] ] where str = nameRepString name -located :: Functor f => (a -> f b) -> Located a -> f (Located b)+located :: Functor f => (a -> f b) -> GenLocated l a -> f (GenLocated l b) located f (L loc e) = L loc <$> f e +locatedN :: Functor f => (a -> f b) -> LocatedN a -> f (LocatedN b)+locatedN f (L loc e) = L loc <$> f e -tyVarName :: HsTyVarBndr name -> name-tyVarName (UserTyVar name) = unLoc name-tyVarName (KindedTyVar (L _ name) _) = name++tyVarName :: HsTyVarBndr flag GhcRn -> IdP GhcRn+tyVarName (UserTyVar _ _ name) = unLoc name+tyVarName (KindedTyVar _ _ (L _ name) _) = name
src/Haddock/InterfaceFile.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE CPP, RankNTypes, ScopedTypeVariables #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE NamedFieldPuns #-} {-# OPTIONS_GHC -fno-warn-orphans #-} ----------------------------------------------------------------------------- -- |@@ -14,59 +16,99 @@ -- Reading and writing the .haddock interface file ----------------------------------------------------------------------------- module Haddock.InterfaceFile (- InterfaceFile(..), ifUnitId, ifModule,- readInterfaceFile, nameCacheFromGhc, freshNameCache, NameCacheAccessor,- writeInterfaceFile, binaryInterfaceVersion, binaryInterfaceVersionCompatibility+ InterfaceFile(..), PackageInfo(..), ifUnitId, ifModule,+ PackageInterfaces(..), mkPackageInterfaces, ppPackageInfo,+ readInterfaceFile, writeInterfaceFile,+ freshNameCache,+ binaryInterfaceVersion, binaryInterfaceVersionCompatibility ) where import Haddock.Types-import Haddock.Utils hiding (out) -import Control.Monad-import Data.Array import Data.IORef-import Data.List import qualified Data.Map as Map import Data.Map (Map)+import Data.Version import Data.Word+import Text.ParserCombinators.ReadP (readP_to_S) -import BinIface (getSymtabName, getDictFastString)-import Binary-import FastMutInt-import FastString+import GHC.Iface.Binary (getWithUserData, putSymbolTable)+import GHC.Unit.State+import GHC.Utils.Binary+import GHC.Data.FastMutInt+import GHC.Data.FastString import GHC hiding (NoLink)-import GhcMonad (withSession)-import HscTypes-import IfaceEnv-import Name-import UniqFM-import UniqSupply-import Unique+import GHC.Types.Name.Cache+import GHC.Types.Unique.FM+import GHC.Types.Unique +import Haddock.Options (Visibility (..)) data InterfaceFile = InterfaceFile { ifLinkEnv :: LinkEnv,+ -- | 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] } +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) = unpackFS (unPackageName name) ++ "-" ++ showVersion version++data PackageInterfaces = PackageInterfaces {+ piPackageInfo :: PackageInfo,+ piVisibility :: Visibility,+ piInstalledInterfaces :: [InstalledInterface]+}++mkPackageInterfaces :: Visibility -> InterfaceFile -> PackageInterfaces+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 -ifUnitId :: InterfaceFile -> UnitId+ifUnitId :: InterfaceFile -> Unit ifUnitId if_ = case ifInstalledIfaces if_ of [] -> error "empty InterfaceFile"- iface:_ -> moduleUnitId $ instMod iface+ iface:_ -> moduleUnit $ instMod iface binaryInterfaceMagic :: Word32 binaryInterfaceMagic = 0xD0Cface +-- Note [The DocModule story]+--+-- Breaking changes to the DocH type result in Haddock being unable to read+-- existing interfaces. This is especially painful for interfaces shipped+-- with GHC distributions since there is no easy way to regenerate them!+--+-- PR #1315 introduced a breaking change to the DocModule constructor. To+-- maintain backward compatibility we+--+-- Parse the old DocModule constructor format (tag 5) and parse the contained+-- string into a proper ModLink structure. When writing interfaces we exclusively+-- use the new DocModule format (tag 24) -- IMPORTANT: Since datatypes in the GHC API might change between major -- versions, and because we store GHC datatypes in our interface files, we need@@ -81,8 +123,8 @@ -- (2) set `binaryInterfaceVersionCompatibility` to [binaryInterfaceVersion] -- binaryInterfaceVersion :: Word16-#if (__GLASGOW_HASKELL__ >= 711) && (__GLASGOW_HASKELL__ < 801)-binaryInterfaceVersion = 28+#if MIN_VERSION_ghc(9,6,0) && !MIN_VERSION_ghc(9,7,0)+binaryInterfaceVersion = 42 binaryInterfaceVersionCompatibility :: [Word16] binaryInterfaceVersionCompatibility = [binaryInterfaceVersion]@@ -110,14 +152,12 @@ put_ bh0 symtab_p_p -- Make some intial state- symtab_next <- newFastMutInt- writeFastMutInt symtab_next 0+ symtab_next <- newFastMutInt 0 symtab_map <- newIORef emptyUFM let bin_symtab = BinSymbolTable { bin_symtab_next = symtab_next, bin_symtab_map = symtab_map }- dict_next_ref <- newFastMutInt- writeFastMutInt dict_next_ref 0+ dict_next_ref <- newFastMutInt 0 dict_map_ref <- newIORef emptyUFM let bin_dict = BinDictionary { bin_dict_next = dict_next_ref,@@ -125,8 +165,9 @@ -- put the main thing let bh = setUserData bh0 $ newWriteState (putName bin_symtab)+ (putName bin_symtab) (putFastString bin_dict)- put_ bh iface+ putInterfaceFile_ bh iface -- write the symtab pointer at the front of the file symtab_p <- tellBin bh@@ -153,101 +194,31 @@ return () -type NameCacheAccessor m = (m NameCache, NameCache -> m ())---nameCacheFromGhc :: NameCacheAccessor Ghc-nameCacheFromGhc = ( read_from_session , write_to_session )- where- read_from_session = do- ref <- withSession (return . hsc_NC)- liftIO $ readIORef ref- write_to_session nc' = do- ref <- withSession (return . hsc_NC)- liftIO $ writeIORef ref nc'---freshNameCache :: NameCacheAccessor IO-freshNameCache = ( create_fresh_nc , \_ -> return () )- where- create_fresh_nc = do- u <- mkSplitUniqSupply 'a' -- ??- return (initNameCache u [])-+freshNameCache :: IO NameCache+freshNameCache = initNameCache 'a' -- ??+ [] -- | Read a Haddock (@.haddock@) interface file. Return either an -- 'InterfaceFile' or an error message. -- -- 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. The function is therefore generic in the--- monad being used. The exact monad is whichever monad the first--- argument, the getter and setter of the name cache, requires.----readInterfaceFile :: forall m.- MonadIO m- => NameCacheAccessor m+-- a new empty name cache is used.+readInterfaceFile :: NameCache -> FilePath- -> m (Either String InterfaceFile)-readInterfaceFile (get_name_cache, set_name_cache) filename = do- bh0 <- liftIO $ readBinMem filename-- magic <- liftIO $ get bh0- version <- liftIO $ get bh0-- case () of- _ | magic /= binaryInterfaceMagic -> return . Left $- "Magic number mismatch: couldn't load interface file: " ++ filename- | version `notElem` binaryInterfaceVersionCompatibility -> return . Left $- "Interface file is of wrong version: " ++ filename- | otherwise -> with_name_cache $ \update_nc -> do-- dict <- get_dictionary bh0-- -- read the symbol table so we are capable of reading the actual data- bh1 <- do- let bh1 = setUserData bh0 $ newReadState (error "getSymtabName")- (getDictFastString dict)- symtab <- update_nc (get_symbol_table bh1)- return $ setUserData bh1 $ newReadState (getSymtabName (NCU (\f -> update_nc (return . f))) dict symtab)- (getDictFastString dict)-- -- load the actual data- iface <- liftIO $ get bh1- return (Right iface)- where- with_name_cache :: forall a.- ((forall n b. MonadIO n- => (NameCache -> n (NameCache, b))- -> n b)- -> m a)- -> m a- with_name_cache act = do- nc_var <- get_name_cache >>= (liftIO . newIORef)- x <- act $ \f -> do- nc <- liftIO $ readIORef nc_var- (nc', x) <- f nc- liftIO $ writeIORef nc_var nc'- return x- liftIO (readIORef nc_var) >>= set_name_cache- return x-- get_dictionary bin_handle = liftIO $ do- dict_p <- get bin_handle- data_p <- tellBin bin_handle- seekBin bin_handle dict_p- dict <- getDictionary bin_handle- seekBin bin_handle data_p- return dict-- get_symbol_table bh1 theNC = liftIO $ do- symtab_p <- get bh1- data_p' <- tellBin bh1- seekBin bh1 symtab_p- (nc', symtab) <- getSymbolTable bh1 theNC- seekBin bh1 data_p'- return (nc', symtab)+ -> 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+ if magic /= binaryInterfaceMagic+ then return . Left $ "Magic number mismatch: couldn't load interface file: " ++ filename+ else do+ version <- get bh+ if not bypass_checks && (version `notElem` binaryInterfaceVersionCompatibility)+ then return . Left $ "Interface file is of wrong version: " ++ filename+ else Right <$> getWithUserData name_cache bh ------------------------------------------------------------------------------- -- * Symbol table@@ -272,7 +243,7 @@ data BinSymbolTable = BinSymbolTable { bin_symtab_next :: !FastMutInt, -- The next index to use- bin_symtab_map :: !(IORef (UniqFM (Int,Name)))+ bin_symtab_map :: !(IORef (UniqFM Name (Int,Name))) -- indexed by Name } @@ -282,72 +253,22 @@ bin_dict_map = out_r} bh f = do out <- readIORef out_r- let unique = getUnique f- case lookupUFM out unique of+ 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 out unique (j, f)+ 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 (Int,FastString)))+ bin_dict_map :: !(IORef (UniqFM FastString (Int,FastString))) -- indexed by FastString } --putSymbolTable :: BinHandle -> Int -> UniqFM (Int,Name) -> IO ()-putSymbolTable bh next_off symtab = do- put_ bh next_off- let names = elems (array (0,next_off-1) (eltsUFM symtab))- mapM_ (\n -> serialiseName bh n symtab) names---getSymbolTable :: BinHandle -> NameCache -> IO (NameCache, Array Int Name)-getSymbolTable bh namecache = do- sz <- get bh- od_names <- replicateM sz (get bh)- let arr = listArray (0,sz-1) names- (namecache', names) = mapAccumR (fromOnDiskName arr) namecache od_names- return (namecache', arr)---type OnDiskName = (UnitId, ModuleName, OccName)---fromOnDiskName- :: Array Int Name- -> NameCache- -> OnDiskName- -> (NameCache, Name)-fromOnDiskName _ nc (pid, mod_name, occ) =- let- modu = mkModule pid mod_name- cache = nsNames nc- in- case lookupOrigNameCache cache modu occ of- Just name -> (nc, name)- Nothing ->- let- us = nsUniqs nc- u = uniqFromSupply us- name = mkExternalName u modu occ noSrcSpan- new_cache = extendNameCache cache modu occ name- in- case splitUniqSupply us of { (us',_) ->- ( nc{ nsUniqs = us', nsNames = new_cache }, name )- }---serialiseName :: BinHandle -> Name -> UniqFM (Int,Name) -> IO ()-serialiseName bh name _ = do- let modu = nameModule name- put_ bh (moduleUnitId modu, moduleName modu, nameOccName name)-- ------------------------------------------------------------------------------- -- * GhcBinary instances -------------------------------------------------------------------------------@@ -357,44 +278,60 @@ 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 (unPackageName piPackageName)+ put_ bh (showVersion piPackageVersion)+ get bh = do+ name <- PackageName <$> get bh+ versionString <- get bh+ let version = case readP_to_S parseVersion versionString of+ [] -> makeVersion []+ vs -> fst (last vs)+ return $ PackageInfo name version instance Binary InterfaceFile where- put_ bh (InterfaceFile env ifaces) = do+ put_ bh (InterfaceFile env info ifaces) = do put_ bh env+ put_ bh info put_ bh ifaces get bh = do env <- get bh+ info <- get bh ifaces <- get bh- return (InterfaceFile env ifaces)+ return (InterfaceFile env info ifaces) +putInterfaceFile_ :: BinHandle -> InterfaceFile -> IO ()+putInterfaceFile_ bh (InterfaceFile env info ifaces) = do+ put_ bh env+ put_ bh info+ put_ bh ifaces+ instance Binary InstalledInterface where- put_ bh (InstalledInterface modu info docMap argMap- exps visExps opts subMap fixMap) = do+ put_ bh (InstalledInterface modu is_sig info docMap argMap+ exps visExps opts fixMap) = do put_ bh modu+ put_ bh is_sig put_ bh info- put_ bh docMap- put_ bh argMap+ lazyPut bh (docMap, argMap) put_ bh exps put_ bh visExps put_ bh opts- put_ bh subMap put_ bh fixMap get bh = do modu <- get bh+ is_sig <- get bh info <- get bh- docMap <- get bh- argMap <- get bh+ ~(docMap, argMap) <- lazyGet bh exps <- get bh visExps <- get bh opts <- get bh- subMap <- get bh fixMap <- get bh-- return (InstalledInterface modu info docMap argMap- exps visExps opts subMap fixMap)+ return (InstalledInterface modu is_sig info docMap argMap+ exps visExps opts fixMap) instance Binary DocOption where@@ -433,7 +370,7 @@ result <- get bh return (Example expression result) -instance Binary Hyperlink where+instance Binary a => Binary (Hyperlink a) where put_ bh (Hyperlink url label) = do put_ bh url put_ bh label@@ -442,6 +379,15 @@ 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)+ instance Binary Picture where put_ bh (Picture uri title) = do put_ bh uri@@ -460,9 +406,40 @@ 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)++instance Binary a => Binary (TableRow a) where+ 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)+ instance Binary Meta where- put_ bh Meta { _version = v } = put_ bh v- get bh = (\v -> Meta { _version = v }) <$> get bh+ put_ bh (Meta v p) = do+ put_ bh v+ put_ bh p+ get bh = do+ v <- get bh+ p <- get bh+ return (Meta v p) instance (Binary mod, Binary id) => Binary (MetaDoc mod id) where put_ bh MetaDoc { _meta = m, _doc = d } = do@@ -489,9 +466,6 @@ put_ bh (DocIdentifier ae) = do putByte bh 4 put_ bh ae- put_ bh (DocModule af) = do- putByte bh 5- put_ bh af put_ bh (DocEmphasis ag) = do putByte bh 6 put_ bh ag@@ -543,6 +517,13 @@ 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@@ -562,9 +543,13 @@ 4 -> do ae <- get bh return (DocIdentifier ae)+ -- See note [The DocModule story] 5 -> do af <- get bh- return (DocModule af)+ return $ DocModule ModLink+ { modLinkName = af+ , modLinkLabel = Nothing+ } 6 -> do ag <- get bh return (DocEmphasis ag)@@ -616,6 +601,13 @@ 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" @@ -663,3 +655,28 @@ name <- get bh return (Undocumented name) _ -> error "get DocName: Bad h"++instance Binary n => Binary (Wrap n) where+ put_ bh (Unadorned n) = do+ putByte bh 0+ put_ bh n+ put_ bh (Parenthesized n) = do+ putByte bh 1+ put_ bh n+ put_ bh (Backticked n) = do+ putByte bh 2+ put_ bh n++ get bh = do+ h <- getByte bh+ case h of+ 0 -> do+ name <- get bh+ return (Unadorned name)+ 1 -> do+ name <- get bh+ return (Parenthesized name)+ 2 -> do+ name <- get bh+ return (Backticked name)+ _ -> error "get Wrap: Bad h"
src/Haddock/ModuleTree.hs view
@@ -14,45 +14,45 @@ import Haddock.Types ( MDoc ) -import GHC ( Name )-import Module ( Module, moduleNameString, moduleName, moduleUnitId, unitIdString )-import DynFlags ( DynFlags )-import Packages ( lookupPackage )-import PackageConfig ( sourcePackageIdString )+import GHC ( Name )+import GHC.Unit.Module ( Module, moduleNameString, moduleName, moduleUnit, unitString )+import GHC.Unit.State ( UnitState, lookupUnit, unitPackageIdString ) +import qualified Control.Applicative as A -data ModuleTree = Node String Bool (Maybe String) (Maybe String) (Maybe (MDoc Name)) [ModuleTree] +data ModuleTree = Node String (Maybe Module) (Maybe String) (Maybe String) (Maybe (MDoc Name)) [ModuleTree] -mkModuleTree :: DynFlags -> Bool -> [(Module, Maybe (MDoc Name))] -> [ModuleTree]-mkModuleTree dflags showPkgs mods =- foldr fn [] [ (splitModule mdl, modPkg mdl, modSrcPkg mdl, short) | (mdl, short) <- mods ]++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 ] where- modPkg mod_ | showPkgs = Just (unitIdString (moduleUnitId mod_))+ modPkg mod_ | showPkgs = Just (unitString (moduleUnit mod_)) | otherwise = Nothing- modSrcPkg mod_ | showPkgs = fmap sourcePackageIdString- (lookupPackage dflags (moduleUnitId mod_))+ modSrcPkg mod_ | showPkgs = fmap unitPackageIdString+ (lookupUnit state (moduleUnit mod_)) | otherwise = Nothing- fn (mod_,pkg,srcPkg,short) = addToTrees mod_ pkg srcPkg short+ fn (m,mod_,pkg,srcPkg,short) = addToTrees mod_ m pkg srcPkg short -addToTrees :: [String] -> Maybe String -> Maybe String -> Maybe (MDoc Name) -> [ModuleTree] -> [ModuleTree]-addToTrees [] _ _ _ ts = ts-addToTrees ss pkg srcPkg short [] = mkSubTree ss pkg srcPkg short-addToTrees (s1:ss) pkg srcPkg short (t@(Node s2 leaf node_pkg node_srcPkg node_short subs) : ts)- | s1 > s2 = t : addToTrees (s1:ss) pkg srcPkg short ts- | s1 == s2 = Node s2 (leaf || null ss) this_pkg this_srcPkg this_short (addToTrees ss pkg srcPkg short subs) : ts- | otherwise = mkSubTree (s1:ss) pkg srcPkg short ++ t : ts+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 -mkSubTree :: [String] -> Maybe String -> Maybe String -> Maybe (MDoc Name) -> [ModuleTree]-mkSubTree [] _ _ _ = []-mkSubTree [s] pkg srcPkg short = [Node s True pkg srcPkg short []]-mkSubTree (s:ss) pkg srcPkg short = [Node s (null ss) Nothing Nothing Nothing (mkSubTree ss pkg srcPkg 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)] splitModule :: Module -> [String]
src/Haddock/Options.hs view
@@ -15,6 +15,7 @@ module Haddock.Options ( parseHaddockOpts, Flag(..),+ Visibility(..), getUsage, optTitle, outputDir,@@ -24,25 +25,38 @@ optSourceCssFile, sourceUrls, wikiUrls,+ baseUrl,+ optParCount, optDumpInterfaceFile,+ optShowInterfaceFile, optLaTeXStyle, optMathjax, qualification,+ sinceQualification, verbosity, ghcFlags,+ reexportFlags, readIfaceArgs, optPackageName,- optPackageVersion+ optPackageVersion,+ modulePackageInfo,+ ignoredSymbols ) where import qualified Data.Char as Char+import Data.List (dropWhileEnd)+import Data.Map (Map)+import qualified Data.Map as Map+import Data.Set (Set)+import qualified Data.Set as Set import Data.Version-import Distribution.Verbosity-import FastString+import Control.Applicative+import GHC.Data.FastString+import GHC ( Module, moduleUnit )+import GHC.Unit.State import Haddock.Types import Haddock.Utils-import Packages import System.Console.GetOpt import qualified Text.ParserCombinators.ReadP as RP @@ -53,6 +67,7 @@ -- | Flag_DocBook | Flag_ReadInterface String | Flag_DumpInterface String+ | Flag_ShowInterface String | Flag_Heading String | Flag_Html | Flag_Hoogle@@ -64,10 +79,12 @@ | Flag_SourceEntityURL String | Flag_SourceLEntityURL String | Flag_WikiBaseURL String+ | Flag_BaseURL String | Flag_WikiModuleURL String | Flag_WikiEntityURL String | Flag_LaTeX | Flag_LaTeXStyle String+ | Flag_QuickJumpIndex | Flag_HyperlinkedSource | Flag_SourceCss String | Flag_Mathjax String@@ -76,12 +93,15 @@ | Flag_Version | Flag_CompatibleInterfaceVersions | Flag_InterfaceVersion+ | Flag_BypassInterfaceVersonCheck | Flag_UseContents String | Flag_GenContents | Flag_UseIndex String | Flag_GenIndex | Flag_IgnoreAllExports | Flag_HideModule String+ | Flag_ShowModule String+ | Flag_ShowAllModules | Flag_ShowExtensions String | Flag_OptGhc String | Flag_GhcLibDir String@@ -96,6 +116,10 @@ | Flag_NoPrintMissingDocs | Flag_PackageName String | Flag_PackageVersion String+ | Flag_Reexport String+ | Flag_SinceQualification String+ | Flag_IgnoreLinkSymbol String+ | Flag_ParCount (Maybe Int) deriving (Eq, Show) @@ -112,6 +136,8 @@ "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)@@ -122,6 +148,8 @@ 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")@@ -137,6 +165,8 @@ "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")@@ -159,6 +189,8 @@ "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")@@ -170,9 +202,13 @@ 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 atribute",+ "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")@@ -190,10 +226,18 @@ "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"+ "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" ] @@ -267,17 +311,23 @@ ,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 ] +optShowInterfaceFile :: [Flag] -> Maybe FilePath+optShowInterfaceFile flags = optLast [ str | Flag_ShowInterface str <- flags ] optLaTeXStyle :: [Flag] -> Maybe String optLaTeXStyle flags = optLast [ str | Flag_LaTeXStyle str <- flags ] - optMathjax :: [Flag] -> Maybe String optMathjax flags = optLast [ str | Flag_Mathjax str <- flags ] +optParCount :: [Flag] -> Maybe (Maybe Int)+optParCount flags = optLast [ n | Flag_ParCount n <- flags ] qualification :: [Flag] -> Either String QualOption qualification flags =@@ -291,34 +341,114 @@ [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" verbosity :: [Flag] -> Verbosity verbosity flags = case [ str | Flag_Verbosity str <- flags ] of- [] -> normal+ [] -> Normal x:_ -> case parseVerbosity x of Left e -> throwE e Right v -> v +-- | Get the ignored symbols from the given flags. These are the symbols for+-- which no link warnings will be generated if their link destinations cannot be+-- determined.+--+-- Symbols may be provided as qualified or unqualified names (e.g.+-- 'Data.Map.dropWhileEnd' or 'dropWhileEnd', resp). If qualified, no link+-- warnings will be produced for occurances of that name when it is imported+-- from that module. If unqualified, no link warnings will be produced for any+-- 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 ]+ where+ -- Split a symbol into its module name and unqualified name, producing+ -- 'Nothing' for the module name if the given symbol is already unqualified+ splitSymbol :: String -> (Maybe String, String)+ 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+ -- string. Drop the length of `s'` from the original string `s` to+ -- obtain to the unqualified name.+ s' -> (Just $ init s', drop (length s') s)++ -- Add a (module name, name) pair to the map from modules to their ignored+ -- symbols+ addToMap :: (Maybe String, String) -> Map (Maybe String) (Set String) -> Map (Maybe String) (Set String)+ addToMap (m, name) symbs = Map.insertWith (Set.union) m (Set.singleton name) symbs+ ghcFlags :: [Flag] -> [String] ghcFlags flags = [ option | Flag_OptGhc option <- flags ] +reexportFlags :: [Flag] -> [String]+reexportFlags flags = [ option | Flag_Reexport option <- flags ] -readIfaceArgs :: [Flag] -> [(DocPaths, FilePath)]+data Visibility = Visible | Hidden+ deriving (Eq, Show)++readIfaceArgs :: [Flag] -> [(DocPaths, Visibility, FilePath)] readIfaceArgs flags = [ parseIfaceOption s | Flag_ReadInterface s <- flags ] where- parseIfaceOption :: String -> (DocPaths, FilePath)+ parseIfaceOption :: String -> (DocPaths, Visibility, FilePath) parseIfaceOption str = case break (==',') str of (fpath, ',':rest) -> case break (==',') rest of- (src, ',':file) -> ((fpath, Just src), file)- (file, _) -> ((fpath, Nothing), file)- (file, _) -> (("", Nothing), file)+ (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)+ (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 _unit_state _flags Nothing = (Nothing, Nothing)+modulePackageInfo unit_state flags (Just modu) =+ ( optPackageName flags <|> fmap unitPackageName pkgDb+ , optPackageVersion flags <|> fmap unitPackageVersion pkgDb+ )+ where+ pkgDb = lookupUnit unit_state (moduleUnit modu)
src/Haddock/Parser.hs view
@@ -1,8 +1,3 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE StandaloneDeriving- , FlexibleInstances, UndecidableInstances- , IncoherentInstances #-}-{-# LANGUAGE LambdaCase #-} -- | -- Module : Haddock.Parser -- Copyright : (c) Mateusz Kowalczyk 2013,@@ -19,26 +14,43 @@ ) where import qualified Documentation.Haddock.Parser as P-import DynFlags (DynFlags)-import FastString (mkFastString) import Documentation.Haddock.Types-import Lexer (mkPState, unP, ParseResult(POk))-import Parser (parseIdentifier)-import RdrName (RdrName)-import SrcLoc (mkRealSrcLoc, unLoc)-import StringBuffer (stringToStringBuffer)+import Haddock.Types -parseParas :: DynFlags -> String -> MetaDoc mod RdrName-parseParas d = overDoc (P.overIdentifier (parseIdent d)) . P.parseParas+import GHC.Driver.Session ( DynFlags )+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 ) -parseString :: DynFlags -> String -> DocH mod RdrName++parseParas :: DynFlags -> Maybe Package -> String -> MetaDoc mod (Wrap NsRdrName)+parseParas d p = overDoc (P.overIdentifier (parseIdent d)) . P.parseParas p++parseString :: DynFlags -> String -> DocH mod (Wrap NsRdrName) parseString d = P.overIdentifier (parseIdent d) . P.parseString -parseIdent :: DynFlags -> String -> Maybe RdrName-parseIdent dflags str0 =- let buffer = stringToStringBuffer str0- realSrcLc = mkRealSrcLoc (mkFastString "<unknown file>") 0 0- pstate = mkPState dflags buffer realSrcLc- in case unP parseIdentifier pstate of- POk _ name -> Just (unLoc name)- _ -> Nothing+parseIdent :: DynFlags -> Namespace -> String -> Maybe (Wrap NsRdrName)+parseIdent dflags ns str0 =+ case unP parseIdentifier (pstate str1) of+ POk _ (L _ name)+ -- 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{} -> Nothing+ where+ realSrcLc = mkRealSrcLoc (fsLit "<unknown file>") 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)
src/Haddock/Syb.hs view
@@ -1,25 +1,25 @@ {-# LANGUAGE Rank2Types #-}-+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ScopedTypeVariables #-} module Haddock.Syb- ( everything, everythingWithState, everywhere+ ( everythingWithState+ , everywhereButType , mkT- , combine+ , mkQ+ , extQ ) where import Data.Data-import Control.Applicative----- | Perform a query on each level of a tree.------ This is stolen directly from SYB package and copied here to not introduce--- additional dependencies.-everything :: (r -> r -> r) -> (forall a. Data a => a -> r)- -> (forall a. Data a => a -> r)-everything k f x = foldl k (f x) (gmapQ (everything k f) x)+import Data.Maybe+import Data.Foldable +-- | Returns true if a == t.+-- requires AllowAmbiguousTypes+isType :: forall a b. (Typeable a, Typeable b) => b -> Bool+isType _ = isJust $ eqT @a @b -- | Perform a query with state on each level of a tree. --@@ -31,15 +31,24 @@ -> (forall a. Data a => a -> r) everythingWithState s k f x = let (r, s') = f x s- in foldl k r (gmapQ (everythingWithState s' k f) x)-+ in foldl' k r (gmapQ (everythingWithState s' k f) x) --- | Apply transformation on each level of a tree.---+-- | Variation on everywhere with an extra stop condition -- Just like 'everything', this is stolen from SYB package.-everywhere :: (forall a. Data a => a -> a) -> (forall a. Data a => a -> a)-everywhere f = f . gmapT (everywhere f)+everywhereBut :: (forall a. Data a => a -> Bool)+ -> (forall a. Data a => a -> a)+ -> (forall a. Data a => a -> a)+everywhereBut q f x+ | q x = x+ | otherwise = f (gmapT (everywhereBut q f) x) +-- | Variation of "everywhere" that does not recurse into children of type t+-- requires AllowAmbiguousTypes+everywhereButType :: forall t . (Typeable t)+ => (forall a. Data a => a -> a)+ -> (forall a. Data a => a -> a)+everywhereButType = everywhereBut (isType @t)+ -- | Create generic transformation. -- -- Another function stolen from SYB package.@@ -48,8 +57,17 @@ Just f' -> f' Nothing -> id --- | Combine two queries into one using alternative combinator.-combine :: Alternative f => (forall a. Data a => a -> f r)- -> (forall a. Data a => a -> f r)- -> (forall a. Data a => a -> f r)-combine f g x = f x <|> g x+-- | Create generic query.+--+-- Another function stolen from SYB package.+mkQ :: (Typeable a, Typeable b) => r -> (b -> r) -> a -> r+(r `mkQ` br) a = case cast a of+ Just b -> br b+ Nothing -> r+++-- | Extend a generic query by a type-specific case.+--+-- Another function stolen from SYB package.+extQ :: (Typeable a, Typeable b) => (a -> q) -> (b -> q) -> a -> q+extQ f g a = maybe (f a) g (cast a)
src/Haddock/Types.hs view
@@ -1,7 +1,21 @@+{-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveDataTypeable, DeriveFunctor, DeriveFoldable, DeriveTraversable, StandaloneDeriving #-}-{-# LANGUAGE TypeFamilies, RecordWildCards #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PartialTypeSignatures #-}+{-# LANGUAGE UndecidableInstances #-} -- Note [Pass sensitive types]+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+ ----------------------------------------------------------------------------- -- | -- Module : Haddock.Types@@ -24,27 +38,28 @@ , module Documentation.Haddock.Types ) where -import Control.Exception-import Control.Arrow hiding ((<+>)) import Control.DeepSeq-import Data.Typeable+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 qualified Data.Map as Map+import qualified Data.Set as Set import Documentation.Haddock.Types-import BasicTypes (Fixity(..))+import qualified GHC.Data.Strict as Strict+import GHC.Types.Fixity (Fixity(..))+import GHC.Types.Name (stableNameCmp)+import GHC.Types.Name.Reader (RdrName(..))+import GHC.Types.SourceText (SourceText(..))+import GHC.Types.SrcLoc (BufSpan(..), BufPos(..))+import GHC.Types.Var (Specificity) -import GHC hiding (NoLink)-import DynFlags (Language)+import GHC+import GHC.Driver.Session (Language) import qualified GHC.LanguageExtensions as LangExt-import Coercion-import NameSet-import OccName-import Outputable-import Control.Applicative (Applicative(..))-import Control.Monad (ap)--import Haddock.Backends.Hyperlinker.Types+import GHC.Types.Name.Occurrence+import GHC.Utils.Outputable ----------------------------------------------------------------------------- -- * Convenient synonyms@@ -56,17 +71,17 @@ 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 [LHsDecl Name]-type InstMap = Map SrcSpan 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) -------------------------------------------------------------------------------- * Interface+-- * Interfaces and Interface creation ----------------------------------------------------------------------------- - -- | 'Interface' holds all information used to render a single Haddock page. -- It represents the /interface/ of a module. The core business of Haddock -- lies in creating this structure. Note that the record contains some fields@@ -77,6 +92,9 @@ -- | The module behind this interface. ifaceMod :: !Module + -- | Is this a signature?+ , ifaceIsSig :: !Bool+ -- | Original file name of the module. , ifaceOrigFilename :: !FilePath @@ -90,149 +108,186 @@ , ifaceRnDoc :: !(Documentation DocName) -- | Haddock options for this module (prune, ignore-exports, etc).- , ifaceOptions :: ![DocOption]+ , ifaceOptions :: [DocOption] -- | Declarations originating from the module. Excludes declarations without -- names (instances and stand-alone documentation comments). Includes -- names of subordinate declarations mapped to their parent declarations.- , ifaceDeclMap :: !(Map Name [LHsDecl Name])+ , ifaceDeclMap :: !DeclMap -- | Documentation of declarations originating from the module (including -- subordinates). , ifaceDocMap :: !(DocMap Name) , ifaceArgMap :: !(ArgMap Name) - -- | Documentation of declarations originating from the module (including- -- subordinates).- , ifaceRnDocMap :: !(DocMap DocName)- , ifaceRnArgMap :: !(ArgMap DocName)-- , ifaceSubMap :: !(Map Name [Name]) , ifaceFixMap :: !(Map Name Fixity) - , ifaceExportItems :: ![ExportItem Name]- , ifaceRnExportItems :: ![ExportItem DocName]+ , ifaceExportItems :: [ExportItem GhcRn]+ , ifaceRnExportItems :: [ExportItem DocNameI] -- | All names exported by the module.- , ifaceExports :: ![Name]+ , 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.- , ifaceVisibleExports :: ![Name]+ , ifaceVisibleExports :: [Name] -- | Aliases of module imports as in @import A.B.C as C@. , ifaceModuleAliases :: !AliasMap -- | Instances exported by the module.- , ifaceInstances :: ![ClsInst]- , ifaceFamInstances :: ![FamInst]+ , ifaceInstances :: [HaddockClsInst] -- | Orphan instances- , ifaceOrphanInstances :: ![DocInstance Name]- , ifaceRnOrphanInstances :: ![DocInstance DocName]+ , ifaceOrphanInstances :: [DocInstance GhcRn]+ , 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)+ , ifaceHaddockCoverage :: (Int, Int) -- | Warnings for things defined in this module.- , ifaceWarningMap :: !WarningMap+ , ifaceWarningMap :: WarningMap - -- | Tokenized source code of module (avaliable if Haddock is invoked with+ -- | Tokenized source code of module (available if Haddock is invoked with -- source generation flag).- , ifaceTokenizedSrc :: !(Maybe [RichToken])- }--type WarningMap = Map Name (Doc Name)+ , ifaceHieFile :: !(Maybe FilePath) + , 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+ instMod :: Module + -- | Is this a signature?+ , instIsSig :: Bool+ -- | Textual information about the module.- , instInfo :: HaddockModInfo Name+ , instInfo :: HaddockModInfo Name -- | Documentation of declarations originating from the module (including -- subordinates).- , instDocMap :: DocMap Name+ , instDocMap :: DocMap Name - , instArgMap :: ArgMap Name+ , instArgMap :: ArgMap Name -- | All names exported by this module.- , instExports :: [Name]+ , 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]+ , instVisibleExports :: [Name] -- | Haddock options for this module (prune, ignore-exports, etc).- , instOptions :: [DocOption]+ , instOptions :: [DocOption] - , instSubMap :: Map Name [Name]- , instFixMap :: Map Name Fixity+ , instFixMap :: Map Name Fixity } - -- | Convert an 'Interface' to an 'InstalledInterface' toInstalledIface :: Interface -> InstalledInterface toInstalledIface interface = InstalledInterface- { instMod = ifaceMod interface- , instInfo = ifaceInfo interface- , instDocMap = ifaceDocMap interface- , instArgMap = ifaceArgMap interface- , instExports = ifaceExports interface- , instVisibleExports = ifaceVisibleExports interface- , instOptions = ifaceOptions interface- , instSubMap = ifaceSubMap interface- , instFixMap = ifaceFixMap interface+ { instMod = ifaceMod interface+ , instIsSig = ifaceIsSig interface+ , instInfo = ifaceInfo interface+ , instDocMap = ifaceDocMap interface+ , instArgMap = ifaceArgMap interface+ , instExports = ifaceExports interface+ , instVisibleExports = ifaceVisibleExports interface+ , instOptions = ifaceOptions interface+ , instFixMap = ifaceFixMap interface } --------------------------------------------------------------------------------- * Export items & declarations------------------------------------------------------------------------------+-- | A monad in which we create Haddock interfaces. Not to be confused with+-- `GHC.Tc.Types.IfM` which is used to write GHC interfaces.+--+-- 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 } +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) -data ExportItem name+-- | Interface creation environment. The name sets are used primarily during+-- processing of doc strings to avoid emitting the same type of warning for the+-- same name twice. This was previously done using a Writer monad and then+-- 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) - -- | An exported declaration.- = ExportDecl+ -- | Names which we have warned about for being out of scope+ , ifeOutOfScopeNames :: !(Set.Set String)++ -- | Names which we have warned about for being ambiguous+ , ifeAmbiguousNames :: !(Set.Set String)++ -- | Named which we have warned about for being inappropriately namespaced+ -- as values+ , ifeInvalidValues :: !(Set.Set String)+ }++-- | Run an `IfM` action.+runIfM+ :: (Monad m)+ -- | Lookup a global name in the current session. Used in cases+ -- where declarations don't+ => (Name -> m (Maybe TyThing))+ -- | The action to run.+ -> IfM m a+ -- | Result and accumulated error/warning messages.+ -> m a+runIfM lookup_name action = do+ let+ if_env = IfEnv {- -- | A declaration.- expItemDecl :: !(LHsDecl name)+ ifeLookupName = lookup_name+ , ifeOutOfScopeNames = Set.empty+ , ifeAmbiguousNames = Set.empty+ , ifeInvalidValues = Set.empty+ }+ evalStateT (unIfM action) if_env - -- | Maybe a doc comment, and possibly docs for arguments (if this- -- decl is a function or type-synonym).- , expItemMbDoc :: !(DocForDecl name)+-- | Look up a name in the current environment+lookupName :: Monad m => Name -> IfM m (Maybe TyThing)+lookupName name = IfM $ do+ lookup_name <- gets ifeLookupName+ lift (lookup_name name) - -- | Subordinate names, possibly with documentation.- , expItemSubDocs :: ![(name, DocForDecl name)]+-- | Very basic logging function that simply prints to stdout+warn :: MonadIO m => String -> IfM m ()+warn msg = liftIO $ putStrLn msg - -- | Instances relevant to this declaration, possibly with- -- documentation.- , expItemInstances :: ![DocInstance name]+-----------------------------------------------------------------------------+-- * Export items & declarations+----------------------------------------------------------------------------- - -- | Fixity decls relevant to this declaration (including subordinates).- , expItemFixities :: ![(name, Fixity)] - -- | Whether the ExportItem is from a TH splice or not, for generating- -- the appropriate type of Source link.- , expItemSpliced :: !Bool- }+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- { expItemName :: !name+ { expItemName :: !(IdP name) -- | Subordinate names.- , expItemSubs :: ![name]+ , expItemSubs :: [IdP name] } -- | A section heading.@@ -245,31 +300,115 @@ , expItemSectionId :: !String -- | Section heading text.- , expItemSectionText :: !(Doc name)+ , expItemSectionText :: !(Doc (IdP name)) } -- | Some documentation.- | ExportDoc !(MDoc name)+ | 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+-- declarations which do not include Hoogle output ('ExportD'), since Hoogle output is+-- generated during the Haddock renaming step. The post-renaming type index+-- ('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 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+ }++-- | Represents export declarations that have undergone renaming such that every+-- 'Name' in the declaration points to an optimal link destination. Since Hoogle+-- output is also generated during the renaming step, each declaration is also+-- attached to its Hoogle textual database entries, /if/ Hoogle output is+-- 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]+ }+ data Documentation name = Documentation- { documentationDoc :: Maybe (MDoc name)- , documentationWarning :: !(Maybe (Doc name))+ { documentationDoc :: Maybe (MDoc name)+ , documentationWarning :: Maybe (Doc name) } deriving Functor +instance NFData name => NFData (Documentation name) where+ rnf (Documentation d w) = d `deepseq` w `deepseq` () -- | 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-noDocForDecl = (Documentation Nothing Nothing, Map.empty)+noDocForDecl = (Documentation Nothing Nothing, mempty) +-- | As we build the declaration map, we really only care to track whether we+-- have only seen a value declaration for a 'Name', or anything else. This type+-- is used to represent those cases. If the only declaration attached to a+-- 'Name' is a 'ValD', we will consult the GHC interface file to determine the+-- type of the value, and attach the 'SrcSpan' from the 'EValD' constructor to+-- it. If we see any other type of declaration for the 'Name', we can just use+-- it.+--+-- This type saves us from storing /every/ declaration we see for a given 'Name'+-- in the map, which is unnecessary and very problematic for overall memory+-- usage.+data DeclMapEntry+ = EValD !SrcSpan+ | EOther (LHsDecl GhcRn) +instance Semigroup DeclMapEntry where+ (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+-- care to store in the 'DeclMap' due to the way top-level bindings with no type+-- 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+ ----------------------------------------------------------------------------- -- * Cross-referencing -----------------------------------------------------------------------------@@ -278,6 +417,15 @@ -- | Type of environment used to cross-reference identifiers in the syntax. type LinkEnv = Map Name Module +-- | An 'RdrName' tagged with some type/value namespace information.+data NsRdrName = NsRdrName+ { namespace :: !Namespace+ , rdrName :: !RdrName+ }++instance NFData NsRdrName where+ rnf (NsRdrName ns rdrN) = ns `seq` rdrN `deepseq` ()+ -- | Extends 'Name' with cross-reference information. data DocName = Documented Name Module@@ -289,15 +437,17 @@ -- documentation, as far as Haddock knows. deriving (Eq, Data) -type instance PostRn DocName NameSet = PlaceHolder-type instance PostRn DocName Fixity = PlaceHolder-type instance PostRn DocName Bool = PlaceHolder-type instance PostRn DocName [Name] = PlaceHolder+data DocNameI -type instance PostTc DocName Kind = PlaceHolder-type instance PostTc DocName Type = PlaceHolder-type instance PostTc DocName Coercion = PlaceHolder+type instance NoGhcTc DocNameI = DocNameI +type instance IdP DocNameI = DocName++instance CollectPass DocNameI where+ collectXXPat _ ext = dataConCantHappen ext+ collectXXHsBindsLR ext = dataConCantHappen ext+ collectXSplicePat _ ext = dataConCantHappen ext+ instance NamedThing DocName where getName (Documented name _) = name getName (Undocumented name) = name@@ -326,12 +476,93 @@ 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+ deriving (Show, Functor, Foldable, Traversable) +instance NFData n => NFData (Wrap n) where+ rnf w = case w of+ Unadorned n -> rnf n+ Parenthesized 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 '`' ]++showWrapped :: (a -> String) -> Wrap a -> String+showWrapped f (Unadorned n) = f n+showWrapped f (Parenthesized n) = "(" ++ f n ++ ")"+showWrapped f (Backticked n) = "`" ++ f n ++ "`"++instance HasOccName DocName where++ occName = occName . getName+ ----------------------------------------------------------------------------- -- * Instances ----------------------------------------------------------------------------- +data HaddockClsInst = HaddockClsInst+ { haddockClsInstPprHoogle :: Maybe String+ , haddockClsInstName :: Name+ , haddockClsInstClsName :: Name+ , haddockClsInstIsOrphan :: Bool+ , haddockClsInstHead :: ([Int], SName, [SimpleType])+ , haddockClsInstSynified :: InstHead GhcRn+ , haddockClsInstTyNames :: Set.Set Name+ }++-- | TODO: This instance is not lawful. We leave the 'InstHead' segment of the+-- class instance evaluated only to WHNF. This should probably be fixed.+instance NFData HaddockClsInst where+ rnf (HaddockClsInst h n cn o hd s ns) =+ h+ `deepseq` n+ `deepseq` cn+ `deepseq` o+ `deepseq` hd+ `deepseq` s+ `seq` ns+ `deepseq` ()++-- | Stable name for stable comparisons. GHC's `Name` uses unstable+-- ordering based on their `Unique`'s.+newtype SName = SName Name+ deriving newtype NFData++instance Eq SName where+ SName n1 == SName n2 = n1 `stableNameCmp` n2 == EQ++instance Ord SName where+ SName n1 `compare` SName n2 = n1 `stableNameCmp` n2++-- | Simplified type for sorting types, ignoring qualification (not visible+-- 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)++instance NFData SimpleType where+ rnf st =+ case st of+ SimpleType sn sts -> sn `deepseq` sts `deepseq` ()+ SimpleIntTyLit i -> rnf i+ SimpleStringTyLit s -> rnf s+ SimpleCharTyLit c -> rnf c+ -- | The three types of instances data InstType name = ClassInst@@ -343,7 +574,8 @@ | TypeInst (Maybe (HsType name)) -- ^ Body (right-hand side) | DataInst (TyClDecl name) -- ^ Data constructors -instance OutputableBndr a => Outputable (InstType a) where+instance (OutputableBndrId p)+ => Outputable (InstType (GhcPass p)) where ppr (ClassInst { .. }) = text "ClassInst" <+> ppr clsiCtx <+> ppr clsiTyVars@@ -361,13 +593,13 @@ -- 'PseudoFamilyDecl' type is introduced. data PseudoFamilyDecl name = PseudoFamilyDecl { pfdInfo :: FamilyInfo name- , pfdLName :: Located name+ , pfdLName :: LocatedN (IdP name) , pfdTyVars :: [LHsType name] , pfdKindSig :: LFamilyResultSig name } -mkPseudoFamilyDecl :: FamilyDecl name -> PseudoFamilyDecl name+mkPseudoFamilyDecl :: FamilyDecl GhcRn -> PseudoFamilyDecl GhcRn mkPseudoFamilyDecl (FamilyDecl { .. }) = PseudoFamilyDecl { pfdInfo = fdInfo , pfdLName = fdLName@@ -375,21 +607,21 @@ , pfdKindSig = fdResultSig } where- mkType (KindedTyVar (L loc name) lkind) =- HsKindSig tvar lkind+ mkType :: HsTyVarBndr flag GhcRn -> HsType GhcRn+ mkType (KindedTyVar _ _ (L loc name) lkind) =+ HsKindSig noAnn tvar lkind where- tvar = L loc (HsTyVar (L loc name))- mkType (UserTyVar name) = HsTyVar name+ tvar = L (na2la loc) (HsTyVar noAnn NotPromoted (L loc name))+ mkType (UserTyVar _ _ name) = HsTyVar noAnn NotPromoted name -- | An instance head that may have documentation and a source location.-type DocInstance name = (InstHead name, Maybe (MDoc name), Located name)+type DocInstance name = (InstHead name, Maybe (MDoc (IdP name)), Located (IdP name), Maybe Module) --- | The head of an instance. Consists of a class name, a list of kind--- parameters, a list of type parameters and an instance type+-- | 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 :: name- , ihdKinds :: [HsType name]+ { ihdClsName :: IdP name , ihdTypes :: [HsType name] , ihdInstType :: InstType name }@@ -419,9 +651,17 @@ type LDoc id = Located (Doc id) -type Doc id = DocH (ModuleName, OccName) id-type MDoc id = MetaDoc (ModuleName, OccName) id+type Doc id = DocH (Wrap (ModuleName, OccName)) (Wrap id)+type MDoc id = MetaDoc (Wrap (ModuleName, OccName)) (Wrap id) +type DocMarkup id a = DocMarkupH (Wrap (ModuleName, OccName)) id a++instance NFData Meta where+ rnf (Meta v p) = v `deepseq` p `deepseq` ()++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 rnf doc = case doc of@@ -448,6 +688,7 @@ 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@@ -459,47 +700,45 @@ instance NFData id => NFData (Header id) where rnf (Header a b) = a `deepseq` b `deepseq` () -instance NFData Hyperlink where+instance NFData id => NFData (Hyperlink id) where rnf (Hyperlink a b) = a `deepseq` b `deepseq` () +instance NFData id => NFData (ModLink id) where+ rnf (ModLink a b) = a `deepseq` b `deepseq` ()+ instance NFData Picture where rnf (Picture a b) = a `deepseq` b `deepseq` () 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` () +instance NFData id => NFData (TableRow id) where+ rnf (TableRow cs) = cs `deepseq` ()++instance NFData id => NFData (TableCell id) where+ rnf (TableCell i j c) = i `deepseq` j `deepseq` c `deepseq` ()+ exampleToString :: Example -> String exampleToString (Example expression result) = ">>> " ++ expression ++ "\n" ++ unlines result --data DocMarkup id a = Markup- { markupEmpty :: a- , markupString :: String -> a- , markupParagraph :: a -> a- , markupAppend :: a -> a -> a- , markupIdentifier :: id -> a- , markupIdentifierUnchecked :: (ModuleName, OccName) -> a- , markupModule :: String -> a- , markupWarning :: a -> a- , markupEmphasis :: a -> a- , markupBold :: a -> a- , markupMonospaced :: a -> a- , markupUnorderedList :: [a] -> a- , markupOrderedList :: [a] -> a- , markupDefList :: [(a,a)] -> a- , markupCodeBlock :: a -> a- , markupHyperlink :: Hyperlink -> a- , markupAName :: String -> a- , markupPic :: Picture -> a- , markupMathInline :: String -> a- , markupMathDisplay :: String -> a- , markupProperty :: String -> a- , markupExample :: [Example] -> a- , markupHeader :: Header a -> a- }+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` () +instance NFData LangExt.Extension data HaddockModInfo name = HaddockModInfo { hmi_description :: Maybe (Doc name)@@ -513,7 +752,6 @@ , hmi_extensions :: [LangExt.Extension] } - emptyHaddockModInfo :: HaddockModInfo a emptyHaddockModInfo = HaddockModInfo { hmi_description = Nothing@@ -584,97 +822,321 @@ OptFullQual -> FullQual OptNoQual -> NoQual +-- | Whether to hide empty contexts+-- Since pattern synonyms have two contexts with different semantics, it is+-- important to all of them, even if one of them is empty.+data HideEmptyContexts+ = HideEmptyContexts+ | ShowEmptyToplevelContexts +-- | When to qualify @since@ annotations with their package+data SinceQual+ = Always+ | External -- ^ only qualify when the thing being annotated is from+ -- an external package+ ----------------------------------------------------------------------------- -- * Error handling ----------------------------------------------------------------------------- +-- | Haddock's own exception type.+data HaddockException+ = HaddockException String+ | WithContext [String] SomeException+ deriving Typeable --- A monad which collects error messages, locally defined to avoid a dep on mtl+instance Show HaddockException where+ show (HaddockException str) = str+ show (WithContext ctxts se) = unlines $ ["While " ++ ctxt ++ ":\n" | ctxt <- reverse ctxts] ++ [show se] +throwE :: String -> a+instance Exception HaddockException+throwE str = throw (HaddockException str) -type ErrMsg = String-newtype ErrMsgM a = Writer { runWriter :: (a, [ErrMsg]) }+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]) +-----------------------------------------------------------------------------+-- * Pass sensitive types+----------------------------------------------------------------------------- -instance Functor ErrMsgM where- fmap f (Writer (a, msgs)) = Writer (f a, msgs)+type instance XRec DocNameI a = GenLocated (Anno a) a+instance UnXRec DocNameI where+ unXRec = unLoc+instance MapXRec DocNameI where+ mapXRec = fmap+instance WrapXRec DocNameI (HsType DocNameI) where+ wrapXRec = noLocA -instance Applicative ErrMsgM where- pure a = Writer (a, [])- (<*>) = ap+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) = SrcAnn NoEpAnns+type instance Anno (FieldOcc DocNameI) = SrcAnn NoEpAnns+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 [LocatedA (TyFamInstDecl DocNameI)] = SrcSpanAnnL+type instance Anno (FamilyDecl DocNameI) = SrcSpan+type instance Anno (Sig DocNameI) = SrcSpan+type instance Anno (InjectivityAnn DocNameI) = SrcAnn NoEpAnns+type instance Anno (HsDecl DocNameI) = SrcSpanAnnA+type instance Anno (FamilyResultSig DocNameI) = SrcAnn NoEpAnns+type instance Anno (HsOuterTyVarBndrs Specificity DocNameI) = SrcSpanAnnA+type instance Anno (HsSigType DocNameI) = SrcSpanAnnA -instance Monad ErrMsgM where- return = pure- m >>= k = Writer $ let- (a, w) = runWriter m- (b, w') = runWriter (k a)- in (b, w ++ w')+type XRecCond a+ = ( XParTy a ~ EpAnn AnnParen+ , NoGhcTc a ~ a+ , MapXRec a+ , UnXRec a+ , WrapXRec a (HsType a)+ ) +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 = EpAnn 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 -tell :: [ErrMsg] -> ErrMsgM ()-tell w = Writer ((), w)+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 XXHsForAllTelescope DocNameI = DataConCantHappen --- Exceptions+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 --- | Haddock's own exception type.-data HaddockException = HaddockException String deriving Typeable+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 -instance Show HaddockException where- show (HaddockException str) = str+type instance XCImport DocNameI = NoExtField+type instance XCExport DocNameI = NoExtField +type instance XXForeignImport DocNameI = DataConCantHappen+type instance XXForeignExport DocNameI = DataConCantHappen -throwE :: String -> a-instance Exception HaddockException-throwE str = throw (HaddockException str)+type instance XConDeclGADT DocNameI = NoExtField+type instance XConDeclH98 DocNameI = NoExtField+type instance XXConDecl 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 --- In "Haddock.Interface.Create", we need to gather--- @Haddock.Types.ErrMsg@s a lot, like @ErrMsgM@ does,--- but we can't just use @GhcT ErrMsgM@ because GhcT requires the--- transformed monad to be MonadIO.-newtype ErrMsgGhc a = WriterGhc { runWriterGhc :: Ghc (a, [ErrMsg]) }---instance MonadIO ErrMsgGhc where--- liftIO = WriterGhc . fmap (\a->(a,[])) liftIO---er, implementing GhcMonad involves annoying ExceptionMonad and---WarnLogMonad classes, so don't bother.-liftGhcToErrMsgGhc :: Ghc a -> ErrMsgGhc a-liftGhcToErrMsgGhc = WriterGhc . fmap (\a->(a,[]))-liftErrMsg :: ErrMsgM a -> ErrMsgGhc a-liftErrMsg = WriterGhc . return . runWriter--- for now, use (liftErrMsg . tell) for this---tell :: [ErrMsg] -> ErrMsgGhc ()---tell msgs = WriterGhc $ return ( (), msgs )+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 -instance Functor ErrMsgGhc where- fmap f (WriterGhc x) = WriterGhc (fmap (first f) x)+type instance XCClsInstDecl 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 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 -instance Applicative ErrMsgGhc where- pure a = WriterGhc (return (a, []))- (<*>) = ap+type instance XHsWC DocNameI _ = NoExtField -instance Monad ErrMsgGhc where- return = pure- m >>= k = WriterGhc $ runWriterGhc m >>= \ (a, msgs1) ->- fmap (second (msgs1 ++)) (runWriterGhc (k a))+type instance XHsOuterExplicit DocNameI _ = NoExtField+type instance XHsOuterImplicit DocNameI = NoExtField+type instance XXHsOuterTyVarBndrs DocNameI = DataConCantHappen +type instance XHsSig DocNameI = NoExtField+type instance XXHsSigType DocNameI = DataConCantHappen +type instance XHsQTvs DocNameI = NoExtField+type instance XConDeclField DocNameI = NoExtField+type instance XXConDeclField DocNameI = DataConCantHappen++type instance XXPat DocNameI = DataConCantHappen+type instance XXHsBindsLR DocNameI a = DataConCantHappen++type instance XSplicePat DocNameI = DataConCantHappen++type instance XCInjectivityAnn DocNameI = NoExtField++type instance XCFunDep DocNameI = NoExtField++type instance XCTyFamInstDecl DocNameI = NoExtField+ -------------------------------------------------------------------------------- * Pass sensitive types+-- * NFData instances for GHC types ----------------------------------------------------------------------------- -type instance PostRn DocName NameSet = PlaceHolder-type instance PostRn DocName Fixity = PlaceHolder-type instance PostRn DocName Bool = PlaceHolder-type instance PostRn DocName Name = DocName-type instance PostRn DocName (Located Name) = Located DocName-type instance PostRn DocName [Name] = PlaceHolder-type instance PostRn DocName DocName = DocName+instance NFData RdrName where+ rnf (Unqual on) = rnf on+ rnf (Qual mn on) = mn `deepseq` on `deepseq` ()+ rnf (Orig m on) = m `deepseq` on `deepseq` ()+ rnf (Exact n) = rnf n -type instance PostTc DocName Kind = PlaceHolder-type instance PostTc DocName Type = PlaceHolder-type instance PostTc DocName Coercion = PlaceHolder+instance NFData SourceText where+ rnf NoSourceText = ()+ rnf (SourceText s) = rnf s++instance NFData FixityDirection where+ rnf InfixL = ()+ rnf InfixR = ()+ rnf InfixN = ()++instance NFData Fixity where+ rnf (Fixity sourceText n dir) =+ sourceText `deepseq` n `deepseq` dir `deepseq` ()++instance NFData ann => NFData (SrcSpanAnn' ann) where+ rnf (SrcSpanAnn a ss) = a `deepseq` ss `deepseq` ()++instance NFData (EpAnn NameAnn) where+ rnf EpAnnNotUsed = ()+ rnf (EpAnn en ann cs) = en `deepseq` ann `deepseq` cs `deepseq` ()++instance NFData NameAnn where+ rnf (NameAnn a b c d e) =+ 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` ()+ rnf (NameAnnBars a b c d e) =+ a+ `deepseq` b+ `deepseq` c+ `deepseq` d+ `deepseq` e+ `deepseq` ()+ rnf (NameAnnOnly a b c d) =+ a+ `deepseq` b+ `deepseq` c+ `deepseq` d+ `deepseq` ()+ rnf (NameAnnRArrow a b) =+ a+ `deepseq` b+ `deepseq` ()+ rnf (NameAnnQuote a b c) =+ 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++instance NFData NameAdornment where+ rnf NameParens = ()+ rnf NameParensHash = ()+ rnf NameBackquotes = ()+ rnf NameSquare = ()++instance NFData EpaLocation where+ rnf (EpaSpan ss bs) = ss `seq` bs `deepseq` ()+ rnf (EpaDelta dp lc) = dp `seq` lc `deepseq` ()++instance NFData EpAnnComments where+ rnf (EpaComments cs) = rnf cs+ rnf (EpaCommentsBalanced cs1 cs2) = cs1 `deepseq` cs2 `deepseq` ()++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 (EpaBlockComment s) = rnf s+ rnf EpaEofComment = ()+++instance NFData a => NFData (Strict.Maybe a) where+ rnf Strict.Nothing = ()+ rnf (Strict.Just x) = rnf x++instance NFData BufSpan where+ rnf (BufSpan p1 p2) = p1 `deepseq` p2 `deepseq` ()++instance NFData BufPos where+ rnf (BufPos n) = rnf n++instance NFData Anchor where+ rnf (Anchor ss op) = ss `seq` op `deepseq` ()++instance NFData AnchorOperation where+ rnf UnchangedAnchor = ()+ rnf (MovedAnchor dp) = rnf dp++instance NFData DeltaPos where+ rnf (SameLine n) = rnf n+ rnf (DifferentLine n m) = n `deepseq` m `deepseq` ()+
src/Haddock/Utils.hs view
@@ -1,4 +1,7 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE GADTs #-}++{-# OPTIONS_GHC -Wno-incomplete-record-updates #-} ----------------------------------------------------------------------------- -- | -- Module : Haddock.Utils@@ -13,17 +16,12 @@ ----------------------------------------------------------------------------- module Haddock.Utils ( - -- * Misc utilities- restrictTo, emptyHsQTvs,- toDescription, toInstalledDescription,- mkEmptySigWcType, addClassContext, lHsQTyVarsToTypes,- -- * Filename utilities moduleHtmlFile, moduleHtmlFile',- contentsHtmlFile, indexHtmlFile,- moduleIndexFrameName, mainFrameName, synopsisFrameName,+ contentsHtmlFile, indexHtmlFile, indexJsonFile, subIndexHtmlFile,- jsFile,+ haddockJsFile, jsQuickJumpFile,+ quickJumpCssFile, -- * Anchor and URL utilities moduleNameUrl, moduleNameUrl', moduleUrl,@@ -31,25 +29,21 @@ makeAnchorId, -- * Miscellaneous utilities- getProgramName, bye, die, dieMsg, noDieMsg, mapSnd, mapMaybeM, escapeStr,+ getProgramName, bye, die, escapeStr,+ writeUtf8File, withTempDir, -- * HTML cross reference mapping html_xrefs_ref, html_xrefs_ref', -- * Doc markup- markup,- idMarkup, mkMeta, -- * List utilities replace, spanWith, - -- * MTL stuff- MonadIO(..),- -- * Logging- parseVerbosity,+ parseVerbosity, Verbosity(..), silent, normal, verbose, deafening, out, -- * System tools@@ -59,44 +53,54 @@ import Documentation.Haddock.Doc (emptyMetaDoc) import Haddock.Types-import Haddock.GhcUtils import GHC-import Name-import NameSet ( emptyNameSet )-import HsTypes (selectorFieldOcc)+import GHC.Types.Name -import Control.Monad ( liftM )+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 Data.Maybe ( mapMaybe ) import System.Environment ( getProgName ) import System.Exit-import System.IO ( hPutStr, stderr )+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 Distribution.Verbosity-import Distribution.ReadE #ifndef mingw32_HOST_OS import qualified System.Posix.Internals #endif -import MonadUtils ( MonadIO(..) )-- -------------------------------------------------------------------------------- -- * Logging -------------------------------------------------------------------------------- +data Verbosity = Silent | Normal | Verbose | Deafening+ deriving (Eq, Ord, Enum, Bounded, Show) -parseVerbosity :: String -> Either String Verbosity-parseVerbosity = runReadE flagToVerbosity+silent, normal, verbose, deafening :: Verbosity+silent = Silent+normal = Normal+verbose = Verbose+deafening = Deafening +-- | Parse out a verbosity level. Inspired from Cabal's verbosity parsing.+parseVerbosity :: String -> Either String Verbosity+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 "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@@ -113,129 +117,14 @@ -------------------------------------------------------------------------------- --- | Extract a module's short description.-toDescription :: Interface -> Maybe (MDoc Name)-toDescription = fmap mkMeta . hmi_description . ifaceInfo ---- | Extract a module's short description.-toInstalledDescription :: InstalledInterface -> Maybe (MDoc Name)-toInstalledDescription = fmap mkMeta . hmi_description . instInfo- mkMeta :: Doc a -> MDoc a mkMeta x = emptyMetaDoc { _doc = x } -mkEmptySigWcType :: LHsType Name -> LHsSigWcType Name--- Dubious, because the implicit binders are empty even--- though the type might have free varaiables-mkEmptySigWcType ty = mkEmptyImplicitBndrs (mkEmptyWildCardBndrs ty)--addClassContext :: Name -> LHsQTyVars Name -> LSig Name -> LSig Name--- Add the class context to a class-op signature-addClassContext cls tvs0 (L pos (ClassOpSig _ lname ltype))- = L pos (TypeSig lname (mkEmptySigWcType (go (hsSigType ltype))))- -- The mkEmptySigWcType is suspicious- where- go (L loc (HsForAllTy { hst_bndrs = tvs, hst_body = ty }))- = L loc (HsForAllTy { hst_bndrs = tvs, hst_body = go ty })- go (L loc (HsQualTy { hst_ctxt = ctxt, hst_body = ty }))- = L loc (HsQualTy { hst_ctxt = add_ctxt ctxt, hst_body = ty })- go (L loc ty)- = L loc (HsQualTy { hst_ctxt = add_ctxt (L loc []), hst_body = L loc ty })-- extra_pred = nlHsTyConApp cls (lHsQTyVarsToTypes tvs0)- add_ctxt (L loc preds) = L loc (extra_pred : preds)--addClassContext _ _ sig = sig -- E.g. a MinimalSig is fine--lHsQTyVarsToTypes :: LHsQTyVars Name -> [LHsType Name]-lHsQTyVarsToTypes tvs- = [ noLoc (HsTyVar (noLoc (hsLTyVarName tv)))- | tv <- hsQTvExplicit tvs ]- ----------------------------------------------------------------------------------- * Making abstract declarations------------------------------------------------------------------------------------restrictTo :: [Name] -> LHsDecl Name -> LHsDecl Name-restrictTo names (L loc decl) = L loc $ case decl of- TyClD d | isDataDecl d ->- TyClD (d { tcdDataDefn = restrictDataDefn names (tcdDataDefn d) })- TyClD d | isClassDecl d ->- TyClD (d { tcdSigs = restrictDecls names (tcdSigs d),- tcdATs = restrictATs names (tcdATs d) })- _ -> decl--restrictDataDefn :: [Name] -> HsDataDefn Name -> HsDataDefn Name-restrictDataDefn names defn@(HsDataDefn { dd_ND = new_or_data, dd_cons = cons })- | DataType <- new_or_data- = defn { dd_cons = restrictCons names cons }- | otherwise -- Newtype- = case restrictCons names cons of- [] -> defn { dd_ND = DataType, dd_cons = [] }- [con] -> defn { dd_cons = [con] }- _ -> error "Should not happen"--restrictCons :: [Name] -> [LConDecl Name] -> [LConDecl Name]-restrictCons names decls = [ L p d | L p (Just d) <- map (fmap keep) decls ]- where- keep d | any (\n -> n `elem` names) (map unLoc $ getConNames d) =- case getConDetails h98d of- PrefixCon _ -> Just d- RecCon fields- | all field_avail (unL fields) -> Just d- | otherwise -> Just (h98d { con_details = PrefixCon (field_types (map unL (unL 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- where- h98d = h98ConDecl d- h98ConDecl c@ConDeclH98{} = c- h98ConDecl c@ConDeclGADT{} = c'- where- (details,_res_ty,cxt,tvs) = gadtDeclDetails (con_type c)- c' :: ConDecl Name- c' = ConDeclH98- { con_name = head (con_names c)- , con_qvars = Just $ HsQTvs { hsq_implicit = mempty- , hsq_explicit = tvs- , hsq_dependent = emptyNameSet }- , con_cxt = Just cxt- , con_details = details- , con_doc = con_doc c- }-- field_avail :: LConDeclField Name -> Bool- field_avail (L _ (ConDeclField fs _ _))- = all (\f -> selectorFieldOcc (unLoc f) `elem` names) fs- field_types flds = [ t | ConDeclField _ t _ <- flds ]-- keep _ = Nothing--restrictDecls :: [Name] -> [LSig Name] -> [LSig Name]-restrictDecls names = mapMaybe (filterLSigNames (`elem` names))---restrictATs :: [Name] -> [LFamilyDecl Name] -> [LFamilyDecl Name]-restrictATs names ats = [ at | at <- ats , unL (fdLName (unL at)) `elem` names ]--emptyHsQTvs :: LHsQTyVars Name--- This function is here, rather than in HsTypes, because it *renamed*, but--- does not necessarily have all the rigt kind variables. It is used--- in Haddock just for printing, so it doesn't matter-emptyHsQTvs = HsQTvs { hsq_implicit = error "haddock:emptyHsQTvs"- , hsq_explicit = []- , hsq_dependent = error "haddock:emptyHsQTvs" }----------------------------------------------------------------------------------- -- * Filename mangling functions stolen from s main/DriverUtil.lhs. -------------------------------------------------------------------------------- - baseName :: ModuleName -> FilePath baseName = map (\c -> if c == '.' then '-' else c) . moduleNameString @@ -256,16 +145,10 @@ Just fp0 -> HtmlPath.joinPath [fp0, baseName mdl ++ ".html"] -contentsHtmlFile, indexHtmlFile :: String+contentsHtmlFile, indexHtmlFile, indexJsonFile :: String contentsHtmlFile = "index.html" indexHtmlFile = "doc-index.html"----moduleIndexFrameName, mainFrameName, synopsisFrameName :: String-moduleIndexFrameName = "modules"-mainFrameName = "main"-synopsisFrameName = "synopsis"+indexJsonFile = "doc-index.json" subIndexHtmlFile :: String -> String@@ -326,17 +209,22 @@ ------------------------------------------------------------------------------- -jsFile :: String-jsFile = "haddock-util.js"+haddockJsFile :: String+haddockJsFile = "haddock-bundle.min.js" +jsQuickJumpFile :: String+jsQuickJumpFile = "quick-jump.min.js" +quickJumpCssFile :: String+quickJumpCssFile = "quick-jump.css"+ ------------------------------------------------------------------------------- -- * Misc. ------------------------------------------------------------------------------- getProgramName :: IO String-getProgramName = liftM (`withoutSuffix` ".bin") getProgName+getProgramName = fmap (`withoutSuffix` ".bin") getProgName where str `withoutSuffix` suff | suff `isSuffixOf` str = take (length str - length suff) str | otherwise = str@@ -345,25 +233,6 @@ bye :: String -> IO a bye s = putStr s >> exitSuccess --dieMsg :: String -> IO ()-dieMsg s = getProgramName >>= \prog -> die (prog ++ ": " ++ s)---noDieMsg :: String -> IO ()-noDieMsg s = getProgramName >>= \prog -> hPutStr stderr (prog ++ ": " ++ s)---mapSnd :: (b -> c) -> [(a,b)] -> [(a,c)]-mapSnd _ [] = []-mapSnd f ((x,y):xs) = (x,f y) : mapSnd f xs---mapMaybeM :: Monad m => (a -> m b) -> Maybe a -> m (Maybe b)-mapMaybeM _ Nothing = return Nothing-mapMaybeM f (Just a) = liftM Just (f a)-- escapeStr :: String -> String escapeStr = escapeURIString isUnreserved @@ -400,7 +269,20 @@ isDigitChar c = c >= '0' && c <= '9' isAlphaNumChar c = isAlphaChar c || isDigitChar c +-- | Utility to write output to UTF-8 encoded files.+--+-- The problem with 'writeFile' is that it picks up its 'TextEncoding' from+-- 'getLocaleEncoding', and on some platforms (like Windows) this default+-- 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 +withTempDir :: (MonadIO m, MonadMask m) => FilePath -> m a -> m a+withTempDir dir = bracket_ (liftIO $ createDirectory dir)+ (liftIO $ removeDirectoryRecursive dir)+ ----------------------------------------------------------------------------- -- * HTML cross references --@@ -447,71 +329,6 @@ spanWith p xs@(a:as) | Just b <- p a = let (bs,cs) = spanWith p as in (b:bs,cs) | otherwise = ([],xs)----------------------------------------------------------------------------------- * Put here temporarily---------------------------------------------------------------------------------markup :: DocMarkup id a -> Doc 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 mod0) = markupModule m mod0-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 (markup m) ds)-markup m (DocDefList ds) = markupDefList m (map (markupPair m) ds)-markup m (DocCodeBlock d) = markupCodeBlock m (markup m d)-markup m (DocHyperlink l) = markupHyperlink 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))---markupPair :: DocMarkup id a -> (Doc id, Doc id) -> (a, a)-markupPair m (a,b) = (markup m a, markup m b)----- | The identity markup-idMarkup :: DocMarkup a (Doc a)-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- }- ----------------------------------------------------------------------------- -- * System tools
+ src/Haddock/Utils/Json.hs view
@@ -0,0 +1,558 @@+{-# LANGUAGE OverloadedStrings #-}+{-# 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++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 Data.Char+import Data.Int+import Data.Word+import Data.List (intersperse)+import Data.Monoid++import GHC.Natural++-- TODO: We may want to replace 'String' with 'Text' or 'ByteString'++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+++infixr 8 .=++-- | A key-value pair for encoding a JSON object.+(.=) :: ToJSON v => String -> v -> Pair+k .= v = (k, toJSON v)+++-- | A type that can be converted to JSON.+class ToJSON a where+ -- | Convert a Haskell value to a JSON-friendly intermediate type.+ toJSON :: a -> Value++instance ToJSON () where+ toJSON () = Array []++instance ToJSON Value where+ toJSON = id++instance ToJSON Bool where+ toJSON = Bool++instance ToJSON a => ToJSON [a] where+ toJSON = Array . map toJSON++instance ToJSON a => ToJSON (Maybe a) where+ 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 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 Float where+ toJSON = Number . realToFrac++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 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++-- | Possibly lossy due to conversion to 'Double'+instance ToJSON Word64 where toJSON = Number . realToFrac++-- | Possibly lossy due to conversion to 'Double'+instance ToJSON Integer where toJSON = Number . fromInteger++------------------------------------------------------------------------------+-- 'BB.Builder'-based encoding++-- | Serialise value as JSON/UTF8-encoded 'Builder'+encodeToBuilder :: ToJSON a => a -> Builder+encodeToBuilder = encodeValueBB . toJSON++encodeValueBB :: Value -> Builder+encodeValueBB jv = case jv of+ Bool True -> "true"+ Bool False -> "false"+ Null -> "null"+ Number n+ | isNaN n || isInfinite n -> encodeValueBB Null+ | Just i <- doubleToInt64 n -> BB.int64Dec i+ | otherwise -> BB.doubleDec n+ Array a -> encodeArrayBB a+ String s -> encodeStringBB s+ Object o -> encodeObjectBB o++encodeArrayBB :: [Value] -> Builder+encodeArrayBB [] = "[]"+encodeArrayBB jvs = BB.char8 '[' <> go jvs <> BB.char8 ']'+ where+ go = Data.Monoid.mconcat . intersperse (BB.char8 ',') . map encodeValueBB++encodeObjectBB :: Object -> Builder+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++encodeStringBB :: String -> Builder+encodeStringBB str = BB.char8 '"' <> go str <> BB.char8 '"'+ where+ go = BB.stringUtf8 . escapeString++------------------------------------------------------------------------------+-- 'String'-based encoding++-- | Serialise value as JSON-encoded Unicode 'String'+encodeToString :: ToJSON a => a -> String+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"+ Number n+ | isNaN n || isInfinite n -> encodeValue Null+ | Just i <- doubleToInt64 n -> shows i+ | otherwise -> shows n+ Array a -> encodeArray a+ String s -> encodeString s+ Object o -> encodeObject o++encodeArray :: [Value] -> ShowS+encodeArray [] = showString "[]"+encodeArray jvs = ('[':) . go jvs . (']':)+ where+ go [] = id+ go [x] = encodeValue x+ go (x:xs) = encodeValue x . (',':) . go xs++encodeObject :: Object -> ShowS+encodeObject [] = showString "{}"+encodeObject jvs = ('{':) . go jvs . ('}':)+ where+ 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) . ('"':)++------------------------------------------------------------------------------+-- helpers++-- | Try to convert 'Double' into 'Int64', return 'Nothing' if not+-- representable loss-free as integral 'Int64' value.+doubleToInt64 :: Double -> Maybe Int64+doubleToInt64 x+ | fromInteger x' == x+ , x' <= toInteger (maxBound :: Int64)+ , x' >= toInteger (minBound :: Int64)+ = Just (fromIntegral x')+ | otherwise = Nothing+ where+ x' = round x++-- | Minimally escape a 'String' in accordance with RFC 7159, "7. Strings"+escapeString :: String -> String+escapeString s+ | not (any needsEscape s) = 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++ -- unescaped = %x20-21 / %x23-5B / %x5D-10FFFF+ needsEscape c = ord c < 0x20 || c `elem` ['\\','"']++------------------------------------------------------------------------------+-- FromJSON++-- | 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]\".+ deriving (Eq, Show, Ord)++type JSONPath = [JSONPathElement]++-- | Failure continuation.+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+ }++modifyFailure :: (String -> String) -> Parser a -> Parser a+modifyFailure f (Parser p) = Parser $ \path kf ks ->+ p path (\p' m -> kf p' (f m)) ks++prependFailure :: String -> Parser a -> Parser a+prependFailure = modifyFailure . (++)++prependContext :: String -> Parser a -> Parser a+prependContext name = prependFailure ("parsing " ++ name ++ " failed, ")++typeMismatch :: String -> Value -> Parser a+typeMismatch expected 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++instance Fail.MonadFail Parser where+ 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'++instance Applicative Parser where+ pure a = Parser $ \_path _kf ks -> ks a+ (<*>) = apP++instance Alternative Parser where+ 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++instance Semigroup (Parser a) where+ (<>) = mplus++instance Monoid (Parser a) where+ mempty = fail "mempty"+ mappend = (<>)++apP :: Parser (a -> b) -> Parser a -> Parser b+apP d e = do+ b <- d+ b <$> e++(<?>) :: Parser a -> JSONPathElement -> Parser a+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++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)++withArray :: String -> ([Value] -> Parser a) -> Value -> Parser a+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)++withDouble :: String -> (Double -> Parser a) -> Value -> Parser a+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)++class FromJSON a where+ parseJSON :: Value -> Parser a++ parseJSONList :: Value -> Parser [a]+ parseJSONList = withArray "[]" (zipWithM (parseIndexedJSON parseJSON) [0..])++instance FromJSON Bool where+ 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"++instance FromJSON Char where+ parseJSON = withString "Char" parseChar++ 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"++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)++instance FromJSON Double where+ parseJSON = parseRealFloat "Double"++instance FromJSON Float where+ 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++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++parseIntegral :: Integral a => String -> Value -> Parser a+parseIntegral name = withDouble name parseIntegralFromDouble++instance FromJSON Integer where+ parseJSON = parseIntegral "Integer"++instance FromJSON Natural where+ parseJSON = withDouble "Natural"+ (parseIntegralFromDouble >=> parseNatural)++instance FromJSON Int where+ parseJSON = parseIntegral "Int"++instance FromJSON Int8 where+ parseJSON = parseIntegral "Int8"++instance FromJSON Int16 where+ parseJSON = parseIntegral "Int16"++instance FromJSON Int32 where+ parseJSON = parseIntegral "Int32"++instance FromJSON Int64 where+ parseJSON = parseIntegral "Int64"++instance FromJSON Word where+ parseJSON = parseIntegral "Word"++instance FromJSON Word8 where+ parseJSON = parseIntegral "Word8"++instance FromJSON Word16 where+ parseJSON = parseIntegral "Word16"++instance FromJSON Word32 where+ parseJSON = parseIntegral "Word32"++instance FromJSON Word64 where+ parseJSON = parseIntegral "Word64"++instance FromJSON a => FromJSON [a] where+ parseJSON = parseJSONList++data Result a = Error String+ | Success a+ deriving (Eq, Show)++fromJSON :: FromJSON a => Value -> Result a+fromJSON = parse parseJSON++parse :: (a -> Parser b) -> a -> Result b+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)++formatError :: JSONPath -> String -> String+formatError path msg = "Error in " ++ formatPath path ++ ": " ++ msg++formatPath :: JSONPath -> String+formatPath path = "$" ++ formatRelativePath path++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++ formatKey :: String -> String+ formatKey key+ | isIdentifierKey key = "." ++ key+ | otherwise = "['" ++ escapeKey key ++ "']"++ isIdentifierKey :: String -> Bool+ isIdentifierKey [] = False+ isIdentifierKey (x:xs) = isAlpha x && all isAlphaNum xs++ escapeKey :: String -> String+ escapeKey = concatMap escapeChar++ escapeChar :: Char -> String+ escapeChar '\'' = "\\'"+ escapeChar '\\' = "\\\\"+ 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++(.:) :: 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++(.:?) :: FromJSON a => Object -> String -> Parser (Maybe a)+(.:?) = explicitParseFieldMaybe parseJSON+++decodeWith :: (Value -> Result a) -> BSL.ByteString -> Maybe a+decodeWith decoder bsl =+ case Parsec.parse parseJSONValue "<input>" 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 "<input>" 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+++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)+
+ src/Haddock/Utils/Json/Parser.hs view
@@ -0,0 +1,102 @@+-- | Json "Parsec" parser, based on+-- [json](https://hackage.haskell.org/package/json) package.+--+module Haddock.Utils.Json.Parser+ ( parseJSONValue+ ) where++import Prelude hiding (null)++import Control.Applicative (Alternative (..))+import Control.Monad (MonadPlus (..))+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 ((<?>))+import qualified Text.ParserCombinators.Parsec as Parsec++import Haddock.Utils.Json.Types hiding (object)++parseJSONValue :: Parser Value+parseJSONValue = Parsec.spaces *> parseValue++tok :: Parser a -> Parser a+tok p = p <* Parsec.spaces++parseValue :: Parser Value+parseValue =+ parseNull+ <|> Bool <$> parseBoolean+ <|> Array <$> parseArray+ <|> String <$> parseString+ <|> Object <$> parseObject+ <|> Number <$> parseNumber+ <?> "JSON value"++parseNull :: Parser Value+parseNull = tok+ $ Parsec.string "null"+ $> Null++parseBoolean :: Parser Bool+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 ','))++parseString :: Parser String+parseString =+ Parsec.between+ (tok (Parsec.char '"'))+ (tok (Parsec.char '"'))+ (many char)+ where+ 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"++ 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)++parseObject :: Parser Object+parseObject =+ Parsec.between+ (tok (Parsec.char '{'))+ (tok (Parsec.char '}'))+ (field `Parsec.sepBy` tok (Parsec.char ','))+ where+ field :: Parser (String, Value)+ field = (,)+ <$> parseString+ <* 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
+ src/Haddock/Utils/Json/Types.hs view
@@ -0,0 +1,42 @@+module Haddock.Utils.Json.Types+ ( Value(..)+ , typeOf+ , Pair+ , Object+ , object+ ) where++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)++typeOf :: Value -> String+typeOf v = case v of+ Object _ -> "Object"+ Array _ -> "Array"+ String _ -> "String"+ Number _ -> "Number"+ Bool _ -> "Boolean"+ Null -> "Null"++-- | A key\/value pair for an 'Object'+type Pair = (String, Value)++-- | A JSON \"object\" (key/value map).+type Object = [Pair]++-- | Create a 'Value' from a list of name\/value 'Pair's.+object :: [Pair] -> Value+object = Object++instance IsString Value where+ fromString = String
test/Haddock/Backends/Hyperlinker/ParserSpec.hs view
@@ -1,98 +1,162 @@+{-# 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 Data.String ( fromString )+import Data.ByteString ( ByteString )+import qualified Data.ByteString as BS ++import Haddock (getGhcDirs) import Haddock.Backends.Hyperlinker.Parser import Haddock.Backends.Hyperlinker.Types +withDynFlags :: (DynFlags -> IO ()) -> IO ()+withDynFlags cont = do+ libDir <- fmap snd (getGhcDirs [])+ runGhc libDir $ do+ dflags <- getSessionDynFlags+ liftIO $ cont dflags + main :: IO () main = hspec spec spec :: Spec-spec = do- describe "parse" parseSpec+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)++-- | 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 "" = True++instance Arbitrary NoGhcRewrite where+ arbitrary = fmap NoGhcRewrite (arbitrary `suchThat` noGhcRewrite)+ shrink (NoGhcRewrite src) = [ NoGhcRewrite shrunk+ | shrunk <- shrink src+ , noGhcRewrite shrunk+ ]++ parseSpec :: Spec-parseSpec = do+parseSpec = around withDynFlags $ do - it "is total" $- property $ \src -> length (parse src) `shouldSatisfy` (>= 0)+ it "is total" $ \dflags ->+ property $ \src -> length (parse dflags "" (fromString src)) `shouldSatisfy` (>= 0) - it "retains file layout" $- property $ \src -> concatMap tkValue (parse src) == src+ 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" $- "-- some very simple comment\nidentifier"- `shouldParseTo`- [TkComment, TkSpace, TkIdentifier]+ 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" $- "-- first line\\\nsecond line\\\nand another one"- `shouldParseTo`- [TkComment]+ 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" $- "{- comment {- nested -} still comment -} {- next comment -}"- `shouldParseTo`- [TkComment, TkSpace, TkComment]+ it "should support nested comments" $ \dflags ->+ shouldParseTo+ "{- comment {- nested -} still comment -} {- next comment -}"+ [TkComment, TkSpace, TkComment]+ dflags - it "should distinguish compiler pragma" $- "{- comment -}{-# LANGUAGE GADTs #-}{- comment -}"- `shouldParseTo`- [TkComment, TkPragma, TkComment]+ it "should distinguish compiler pragma" $ \dflags ->+ shouldParseTo+ "{- comment -}{-# LANGUAGE GADTs #-}{- comment -}"+ [TkComment, TkPragma, TkComment]+ dflags - it "should recognize preprocessor directives" $ do- "\n#define foo bar" `shouldParseTo` [TkSpace, TkCpp]- "x # y" `shouldParseTo`- [TkIdentifier, TkSpace, TkOperator, TkSpace,TkIdentifier]+ 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" $ do- "(* 2) <$> (\"abc\", foo)" `shouldParseTo`+ 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 ]- "let foo' = foo in foo' + foo'" `shouldParseTo`+ dflags+ + shouldParseTo+ "let foo' = foo in foo' + foo'" [ TkKeyword, TkSpace, TkIdentifier , TkSpace, TkGlyph, TkSpace , TkIdentifier, TkSpace, TkKeyword, TkSpace , TkIdentifier, TkSpace, TkOperator, TkSpace, TkIdentifier ]- "square x = y^2 where y = x" `shouldParseTo`+ 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" $ do- "do { foo <- getLine; putStrLn foo }" `shouldParseTo`+ 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 - unlines- [ "do"- , " foo <- getLine"- , " putStrLn foo"- ] `shouldParseTo`+ shouldParseTo+ (fromString $ unlines+ [ "do"+ , " foo <- getLine"+ , " putStrLn foo"+ ]) [ TkKeyword, TkSpace, TkIdentifier , TkSpace, TkGlyph, TkSpace, TkIdentifier, TkSpace , TkIdentifier, TkSpace, TkIdentifier, TkSpace ]---shouldParseTo :: String -> [TokenType] -> Expectation-str `shouldParseTo` tokens = map tkType (parse str) `shouldBe` tokens+ dflags+ where+ shouldParseTo :: ByteString -> [TokenType] -> DynFlags -> Expectation+ shouldParseTo str tokens dflags = [ tkType tok+ | tok <- parse dflags "" str+ , not (BS.null (tkValue tok)) ] `shouldBe` tokens