0 | module Idris.Doc.HTML
3 | import Core.Directory
6 | import Data.SortedMap
8 | import Libraries.Text.PrettyPrint.Prettyprinter
9 | import Libraries.Text.PrettyPrint.Prettyprinter.Render.HTML
10 | import Libraries.Text.PrettyPrint.Prettyprinter.SimpleDocTree
12 | import Idris.Doc.Annotations
13 | import Idris.Package.Types
15 | import Idris.Version
19 | getNS : Name -> String
20 | getNS (NS ns _) = show ns
23 | hasNS : Name -> Bool
24 | hasNS (NS {}) = True
27 | tryCanonicalName : {auto c : Ref Ctxt Defs} ->
28 | FC -> Name -> Core (Maybe Name)
29 | tryCanonicalName fc n with (hasNS n)
30 | tryCanonicalName fc n | True
31 | = do defs <- get Ctxt
32 | case !(lookupCtxtName n (gamma defs)) of
33 | [(n, _, _)] => pure $
Just n
35 | tryCanonicalName fc n | False = pure Nothing
37 | packageInternal : {auto c : Ref Ctxt Defs} ->
39 | packageInternal (NS ns _) =
40 | do let mi = nsAsModuleIdent ns
41 | catch ((const True) <$> nsToSource emptyFC mi) (\_ => pure False)
42 | packageInternal _ = pure False
44 | addLink : {auto c : Ref Ctxt Defs} ->
45 | Maybe Name -> String -> Core String
46 | addLink Nothing rest = pure rest
47 | addLink (Just n) rest = do
48 | Just cName <- tryCanonicalName emptyFC n
49 | | Nothing => pure $
"<span class=\"implicit\">" <+> rest <+> "</span>"
50 | True <- packageInternal cName
51 | | False => pure $
fastConcat
52 | [ "<span class=\"type resolved\" title=\""
53 | , htmlEscape (show cName)
59 | [ "<a class=\"type\" href=\""
60 | , htmlEscape $
getNS cName
62 | , htmlEscape $
show cName
68 | makeFCAttributes : FC -> String
69 | makeFCAttributes (MkFC (PhysicalIdrSrc mi) start _) =
70 | "data-src-mod=\"\{htmlEscape $ show mi}\" data-src-start=\"\{htmlEscape $ showPos start}\""
71 | makeFCAttributes (MkVirtualFC (PhysicalIdrSrc mi) start _) =
72 | "data-src-mod=\"\{htmlEscape $ show mi}\" data-src-start=\"\{htmlEscape $ showPos start}\" data-fc-type=\"virtual\""
73 | makeFCAttributes fc = ""
75 | renderHtml : {auto c : Ref Ctxt Defs} ->
76 | SimpleDocTree IdrisDocAnn ->
78 | renderHtml STEmpty = pure neutral
79 | renderHtml (STChar ' ') = pure " "
80 | renderHtml (STChar c) = pure $
cast c
81 | renderHtml (STText _ text) = pure $
htmlEscape text
82 | renderHtml (STLine _) = pure "<br>"
83 | renderHtml (STAnn Declarations rest)
84 | = pure $
"<dl class=\"decls\">" <+> !(renderHtml rest) <+> "</dl>"
85 | renderHtml (STAnn (Decl n fc) rest) = pure $
"<dt \{makeFCAttributes fc} id=\"" ++ (htmlEscape $
show n) ++ "\"><code>" <+> !(renderHtml rest) <+> "</code></dt>"
86 | renderHtml (STAnn DocStringBody rest)
87 | = pure $
"<dd>" <+> !(renderHtml rest) <+> "</dd>"
88 | renderHtml (STAnn UserDocString rest)
89 | = pure $
"<pre>" <+> !(renderHtml rest) <+> "</pre>"
90 | renderHtml (STAnn (Syntax (DCon mn)) rest) = do
91 | dcon <- renderHtml rest
92 | addLink mn $
"<span class=\"name constructor\">" <+> dcon <+> "</span>"
93 | renderHtml (STAnn (Syntax (TCon mn)) rest) = do
94 | tcon <- renderHtml rest
95 | addLink mn $
"<span class=\"name type\">" <+> tcon <+> "</span>"
96 | renderHtml (STAnn (Syntax (Fun n)) rest) = do
97 | fun <- renderHtml rest
98 | addLink (Just n) $
"<span class=\"name function\">" <+> fun <+> "</span>"
99 | renderHtml (STAnn (Syntax Keyword) rest) = do
100 | key <- renderHtml rest
101 | pure $
"<span class=\"keyword\">" <+> key <+> "</span>"
102 | renderHtml (STAnn (Syntax Bound) rest) = do
103 | bnd <- renderHtml rest
104 | pure $
"<span class=\"boundvar\">" <+> bnd <+> "</span>"
105 | renderHtml (STAnn Header rest) = do
106 | resthtml <- renderHtml rest
107 | pure $
"<b>" <+> resthtml <+> "</b>"
108 | renderHtml (STAnn ann rest) = do
109 | resthtml <- renderHtml rest
110 | pure $
"<!-- ann ignored START -->" ++ resthtml ++ "<!-- ann END -->"
111 | renderHtml (STConcat docs) = pure $
fastConcat !(traverse renderHtml docs)
113 | removeNewlinesFromDeclarations : SimpleDocTree IdrisDocAnn -> SimpleDocTree IdrisDocAnn
114 | removeNewlinesFromDeclarations = go False
116 | go : Bool -> SimpleDocTree IdrisDocAnn -> SimpleDocTree IdrisDocAnn
117 | go False l@(STLine i) = l
118 | go True l@(STLine i) = STEmpty
119 | go ignoring (STConcat docs) = STConcat $
map (go ignoring) docs
120 | go _ (STAnn Declarations rest) = STAnn Declarations $
go True rest
121 | go _ (STAnn ann rest) = STAnn ann $
go False rest
124 | docDocToHtml : {auto c : Ref Ctxt Defs} ->
128 | let dt = SimpleDocTree.fromStream $
layoutUnbounded doc in
129 | renderHtml $
removeNewlinesFromDeclarations dt
131 | htmlPreamble : String -> String -> String -> String
132 | htmlPreamble title root class =
133 | let title = htmlEscape title in
134 | let cssID = "preferredStyle" in
135 | let cssSelectID = "selectPreferredStyle" in
136 | let cssDefault = "default" in
137 | let cssLocalKey = "stylefile" in
139 | <!DOCTYPE html><html lang="en">
142 | <meta charset="utf-8">
143 | <title>\{title}</title>
144 | <link rel="stylesheet" type="text/css" id="\{cssID}" href="\{root}\{cssDefault}.css">
146 | /* Updates the stylesheet to use the preferred one.
147 | Note that we set the link to root ++ sourceLoc because the config
148 | is shared across the whole website, so the root may differ from
151 | function setStyleSource (sourceLoc) {
152 | document.getElementById("\{cssID}").href = "\{root}" + sourceLoc + ".css";
153 | document.getElementById("\{cssSelectID}").value = sourceLoc;
155 | /* Initialises the preferred style sheet:
156 | 1. if there is a stored value then use that
157 | otherwise select the default
158 | 2. set both the css link href & the drop down menu selected option
160 | function initStyleSource () {
161 | var preferredStyle = localStorage.getItem("\{cssLocalKey}");
162 | if (preferredStyle !== null) {
163 | setStyleSource(preferredStyle);
165 | setStyleSource("\{cssDefault}");
168 | function saveStyleSource (preferredStyle) {
169 | localStorage.\{cssLocalKey} = preferredStyle;
174 | <body class="\{class}">
176 | <strong>Idris2Doc</strong> : \{title}
177 | <nav><a href="\{root}index.html">Index</a>
179 | <select id="\{cssSelectID}">
180 | \{unlines $ flip map cssFiles $ \ css =>
181 | #"<option value="\#{css.filename}">\#{css.stylename}</option>"#
187 | /* We start by initialising the style source */
190 | /* This listens for changes on the drop down menu and updates the
191 | css used for the current page when a selection is made.
193 | document.getElementById("\{cssSelectID}").addEventListener("change", function(){
194 | var selected = this.options[this.selectedIndex].value; /* the option chosen */
195 | setStyleSource (selected);
196 | saveStyleSource (selected);
201 | <div class="container">
204 | htmlFooter : String
205 | htmlFooter = "</div><footer>Produced by Idris 2 version " ++ (showVersion True version) ++ "</footer></body></html>"
208 | renderDocIndex : PkgDesc -> SortedMap ModuleIdent String -> String
209 | renderDocIndex pkg moddocstrs = fastConcat $
210 | [ htmlPreamble (name pkg) "" "index"
211 | , "<h1>Package ", name pkg, " - Namespaces</h1>"
212 | , "<ul class=\"names\">"] ++
213 | (map (\x => moduleLink x moddocstrs) $
(modules pkg)) ++
218 | moduleLink : (ModuleIdent, String) -> SortedMap ModuleIdent String -> String
219 | moduleLink (mod, filename) moddocstrs =
220 | let cmoddocstr = case lookup mod moddocstrs of
222 | Just cmoddocstr' => unlines $
takeWhile (/= "") $
lines $
cmoddocstr'
225 | <div class="index-wrapper">
226 | <div class="index-namespace-url">
227 | <a class="code" href="docs/\{show mod}.html">\{show mod}</a>
229 | <div class="index-namespace-doc">
236 | preserveLayout : String -> String
237 | preserveLayout d = "<pre>" ++ d ++ "</pre>"
240 | renderModuleDoc : {auto c : Ref Ctxt Defs} ->
243 | Maybe (List (Doc IdrisDocAnn)) ->
244 | Maybe (Doc IdrisDocAnn) ->
246 | renderModuleDoc mod modDoc modReexports allModuleDocs =
247 | let mdoc = maybe "" (preserveLayout . htmlEscape) modDoc
248 | mexp = maybe "" vcat modReexports
249 | in pure $
fastConcat
250 | [ htmlPreamble (show mod) "../" "namespace"
251 | , "<div id=\"module-header\">"
252 | , "<h1>", show mod, "</h1>"
255 | , maybe "" (const "<h2>Reexports</h2>") modReexports
256 | , "<code>", !(docDocToHtml mexp), "</code>"
257 | , maybe "" (const "<h2>Definitions</h2>") allModuleDocs
258 | , !(docDocToHtml $
fromMaybe "" allModuleDocs)