├── .gitignore ├── LICENSE ├── Makefile.doc ├── README.md ├── example ├── .gitignore ├── Makefile ├── Makefile.coq.local ├── README.md ├── _CoqProject ├── a.v └── coqdocjs │ ├── Makefile.doc │ └── extra └── extra ├── footer.html ├── header.html └── resources ├── config.js ├── coqdoc.css ├── coqdocjs.css └── coqdocjs.js /.gitignore: -------------------------------------------------------------------------------- 1 | .*.aux 2 | .*.d 3 | *.a 4 | *.cma 5 | *.cmi 6 | *.cmo 7 | *.cmx 8 | *.cmxa 9 | *.cmxs 10 | *.glob 11 | *.ml.d 12 | *.ml4.d 13 | *.mli.d 14 | *.mllib.d 15 | *.mlpack.d 16 | *.native 17 | *.o 18 | *.v.d 19 | *.vio 20 | *.vo 21 | *.vok 22 | *.vos 23 | .DS_Store 24 | .coq-native/ 25 | .csdp.cache 26 | .lia.cache 27 | .nia.cache 28 | .nlia.cache 29 | .nra.cache 30 | csdp.cache 31 | lia.cache 32 | nia.cache 33 | nlia.cache 34 | nra.cache 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Tobias Tebbi 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 16 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | -------------------------------------------------------------------------------- /Makefile.doc: -------------------------------------------------------------------------------- 1 | COQDOCJS_DIR ?= coqdocjs 2 | EXTRA_DIR = $(COQDOCJS_DIR)/extra 3 | COQDOCFLAGS ?= \ 4 | --toc --toc-depth 2 --html --interpolate \ 5 | --index indexpage --no-lib-name --parse-comments \ 6 | --with-header $(EXTRA_DIR)/header.html --with-footer $(EXTRA_DIR)/footer.html 7 | export COQDOCFLAGS 8 | COQMAKEFILE ?= Makefile.coq 9 | COQDOCJS_LN ?= false 10 | 11 | coqdoc: $(COQMAKEFILE) 12 | $(MAKE) -f $^ html 13 | ifeq ($(COQDOCJS_LN),true) 14 | ln -sf ../$(EXTRA_DIR)/resources html 15 | else 16 | cp -R $(EXTRA_DIR)/resources html 17 | endif 18 | 19 | .PHONY: coqdoc 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CoqdocJS 2 | 3 | CoqdocJS is a little script to dynamically improve the coqdoc output. 4 | The result can be seen here: 5 | 6 | https://www.ps.uni-saarland.de/autosubst/doc/Ssr.POPLmark.html 7 | 8 | It offers the following features: 9 | - Customizable Unicode display: 10 | It only changes the display, copy-paste from the website produces pure ASCII. 11 | It only replaces complete identifiers or notation tokens, possibly terminated by numbers or apostrophes. 12 | It does not replace randomly, like in "omega." or "tauto." 13 | To add new symbols, edit [config.js](extra/resources/config.js). 14 | - Proof hiding: 15 | All proofs longer than one line are hidden by default. They can be uncovered by clicking on "Proof...". 16 | 17 | All of this works with the ordinary coqdoc, by asking coqdoc to use a header file including the javascript files and some custom CSS. 18 | 19 | ## Usage 20 | 21 | 1. Clone this repository as a subdirectory or submodule; 22 | 2. Include [Makefile.doc] in your `Makefile`, or copy it as, e.g., `Makefile.coq.local`; 23 | 3. Run `make coqdoc` to build documentations. 24 | 25 | A minimal example is shown [here](example). 26 | 27 | ### Environment Variables 28 | Name | Usage | Default 29 | ---|---|--- 30 | `COQDOCFLAGS` | Override the flags passed to `coqdoc` | see [Makefile.doc] 31 | `COQDOCEXTRAFLAGS` | Extend the flags passed to `coqdoc` | empty 32 | `COQDOCJS_LN` | If set to `true` then symlink resource files; otherwise copy | `false` 33 | `COQDOCJS_DIR` | Folder containing CoqdocJS | `coqdocjs` 34 | `COQMAKEFILE` | Makefile generated by `coq_makefile` | `Makefile.coq` 35 | 36 | ## Files 37 | 38 | - [Makefile.doc]: a generic Makefile setup that calls coqc and coqdoc with the right parameters 39 | - [config.js](extra/resources/config.js): contains the unicode replacement table 40 | - [coqdoc.css](extra/resources/coqdoc.css): a replacement for the default Coqdoc CSS style. Can be removed to use the default style 41 | - [coqdocjs.js](extra/resources/coqdocjs.js) and [coqdocjs.css](extra/resources/coqdocjs.css): the script rewriting the DOM and adding the dynamic features with a corresponding CSS style 42 | - [header.html](extra/header.html) and [footer.html](extra/footer.html): custom header and footer files used in every generated html file 43 | 44 | [Makefile.doc]: Makefile.doc 45 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | Makefile.coq 2 | Makefile.coq.conf 3 | html/ 4 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | COQMAKEFILE ?= Makefile.coq 2 | COQDOCEXTRAFLAGS = -s 3 | COQDOCJS_LN = true 4 | COQ_PROJ ?= _CoqProject 5 | 6 | all: $(COQMAKEFILE) 7 | $(MAKE) -f $^ $@ 8 | 9 | clean: $(COQMAKEFILE) 10 | $(MAKE) -f $^ cleanall 11 | $(RM) $^ $^.conf 12 | 13 | $(COQMAKEFILE): $(COQ_PROJ) 14 | $(COQBIN)coq_makefile -f $^ -o $@ 15 | 16 | force $(COQ_PROJ) Makefile: ; 17 | 18 | %: $(COQMAKEFILE) force 19 | @+$(MAKE) -f $< $@ 20 | 21 | .PHONY: clean all force 22 | -------------------------------------------------------------------------------- /example/Makefile.coq.local: -------------------------------------------------------------------------------- 1 | coqdocjs/Makefile.doc -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # CoqdocJS Usage Example 2 | This folder contains a minimal example to use CoqdocJS in your project. 3 | 4 | You can build the docs with `make coqdoc`. 5 | -------------------------------------------------------------------------------- /example/_CoqProject: -------------------------------------------------------------------------------- 1 | -Q ./ MyProjectName 2 | a.v 3 | -------------------------------------------------------------------------------- /example/a.v: -------------------------------------------------------------------------------- 1 | (** * Section *) 2 | Variant foo := bar. (* comments *) 3 | 4 | (** ** Subsection *) 5 | (** Documentations. *) 6 | Example baz : forall f : foo, f = bar. 7 | Proof. 8 | intros []. 9 | reflexivity. 10 | Qed. 11 | -------------------------------------------------------------------------------- /example/coqdocjs/Makefile.doc: -------------------------------------------------------------------------------- 1 | ../../Makefile.doc -------------------------------------------------------------------------------- /example/coqdocjs/extra: -------------------------------------------------------------------------------- 1 | ../../extra -------------------------------------------------------------------------------- /extra/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /extra/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 26 |
27 |
28 | -------------------------------------------------------------------------------- /extra/resources/config.js: -------------------------------------------------------------------------------- 1 | var coqdocjs = coqdocjs || {}; 2 | 3 | coqdocjs.repl = { 4 | "forall": "∀", 5 | "exists": "∃", 6 | "~": "¬", 7 | "/\\": "∧", 8 | "\\/": "∨", 9 | "->": "→", 10 | "<-": "←", 11 | "<->": "↔", 12 | "=>": "⇒", 13 | "<>": "≠", 14 | "<=": "≤", 15 | ">=": "≥", 16 | "el": "∈", 17 | "nel": "∉", 18 | "<<=": "⊆", 19 | "|-": "⊢", 20 | ">>": "»", 21 | "<<": "⊆", 22 | "++": "⧺", 23 | "===": "≡", 24 | "=/=": "≢", 25 | "=~=": "≅", 26 | "==>": "⟹", 27 | "lhd": "⊲", 28 | "rhd": "⊳", 29 | "nat": "ℕ", 30 | "alpha": "α", 31 | "beta": "β", 32 | "gamma": "γ", 33 | "delta": "δ", 34 | "epsilon": "ε", 35 | "eta": "η", 36 | "iota": "ι", 37 | "kappa": "κ", 38 | "lambda": "λ", 39 | "mu": "μ", 40 | "nu": "ν", 41 | "omega": "ω", 42 | "phi": "ϕ", 43 | "pi": "π", 44 | "psi": "ψ", 45 | "rho": "ρ", 46 | "sigma": "σ", 47 | "tau": "τ", 48 | "theta": "θ", 49 | "xi": "ξ", 50 | "zeta": "ζ", 51 | "Delta": "Δ", 52 | "Gamma": "Γ", 53 | "Pi": "Π", 54 | "Sigma": "Σ", 55 | "Omega": "Ω", 56 | "Xi": "Ξ" 57 | }; 58 | 59 | coqdocjs.subscr = { 60 | "0" : "₀", 61 | "1" : "₁", 62 | "2" : "₂", 63 | "3" : "₃", 64 | "4" : "₄", 65 | "5" : "₅", 66 | "6" : "₆", 67 | "7" : "₇", 68 | "8" : "₈", 69 | "9" : "₉", 70 | }; 71 | 72 | coqdocjs.replInText = ["==>","<=>", "=>", "->", "<-", ":="]; 73 | -------------------------------------------------------------------------------- /extra/resources/coqdoc.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700); 2 | 3 | body{ 4 | font-family: 'Open Sans', sans-serif; 5 | font-size: 14px; 6 | color: #2D2D2D 7 | } 8 | 9 | a { 10 | text-decoration: none; 11 | border-radius: 3px; 12 | padding-left: 3px; 13 | padding-right: 3px; 14 | margin-left: -3px; 15 | margin-right: -3px; 16 | color: inherit; 17 | font-weight: bold; 18 | } 19 | 20 | #main .code a, #main .inlinecode a, #toc a { 21 | font-weight: inherit; 22 | } 23 | 24 | a[href]:hover, [clickable]:hover{ 25 | background-color: rgba(0,0,0,0.1); 26 | cursor: pointer; 27 | } 28 | 29 | h, h1, h2, h3, h4, h5 { 30 | line-height: 1; 31 | color: black; 32 | text-rendering: optimizeLegibility; 33 | font-weight: normal; 34 | letter-spacing: 0.1em; 35 | text-align: left; 36 | } 37 | 38 | div + br { 39 | display: none; 40 | } 41 | 42 | div:empty{ display: none;} 43 | 44 | #main h1 { 45 | font-size: 2em; 46 | } 47 | 48 | #main h2 { 49 | font-size: 1.667rem; 50 | } 51 | 52 | #main h3 { 53 | font-size: 1.333em; 54 | } 55 | 56 | #main h4, #main h5, #main h6 { 57 | font-size: 1em; 58 | } 59 | 60 | #toc h2 { 61 | padding-bottom: 0; 62 | } 63 | 64 | #main .doc { 65 | margin: 0; 66 | text-align: justify; 67 | } 68 | 69 | .inlinecode, .code, #main pre { 70 | font-family: monospace; 71 | } 72 | 73 | .code > br:first-child { 74 | display: none; 75 | } 76 | 77 | .doc + .code{ 78 | margin-top:0.5em; 79 | } 80 | 81 | .block{ 82 | display: block; 83 | margin-top: 5px; 84 | margin-bottom: 5px; 85 | padding: 10px; 86 | text-align: center; 87 | } 88 | 89 | .block img{ 90 | margin: 15px; 91 | } 92 | 93 | table.infrule { 94 | border: 0px; 95 | margin-left: 50px; 96 | margin-top: 10px; 97 | margin-bottom: 10px; 98 | } 99 | 100 | td.infrule { 101 | font-family: "Droid Sans Mono", "DejaVu Sans Mono", monospace; 102 | text-align: center; 103 | padding: 0; 104 | line-height: 1; 105 | } 106 | 107 | tr.infrulemiddle hr { 108 | margin: 1px 0 1px 0; 109 | } 110 | 111 | .infrulenamecol { 112 | color: rgb(60%,60%,60%); 113 | padding-left: 1em; 114 | padding-bottom: 0.1em 115 | } 116 | 117 | .id[type="constructor"], .id[type="projection"], .id[type="method"], 118 | .id[title="constructor"], .id[title="projection"], .id[title="method"] { 119 | color: #A30E16; 120 | } 121 | 122 | .id[type="var"], .id[type="variable"], 123 | .id[title="var"], .id[title="variable"] { 124 | color: inherit; 125 | } 126 | 127 | .id[type="definition"], .id[type="record"], .id[type="class"], .id[type="instance"], .id[type="inductive"], .id[type="library"], 128 | .id[title="definition"], .id[title="record"], .id[title="class"], .id[title="instance"], .id[title="inductive"], .id[title="library"] { 129 | color: #A6650F; 130 | } 131 | 132 | .id[type="lemma"], 133 | .id[title="lemma"]{ 134 | color: #188B0C; 135 | } 136 | 137 | .id[type="keyword"], .id[type="notation"], .id[type="abbreviation"], 138 | .id[title="keyword"], .id[title="notation"], .id[title="abbreviation"]{ 139 | color : #2874AE; 140 | } 141 | 142 | .comment { 143 | color: #808080; 144 | } 145 | 146 | /* TOC */ 147 | 148 | #toc h2{ 149 | letter-spacing: 0; 150 | font-size: 1.333em; 151 | } 152 | 153 | /* Index */ 154 | 155 | #index { 156 | margin: 0; 157 | padding: 0; 158 | width: 100%; 159 | } 160 | 161 | #index #frontispiece { 162 | margin: 1em auto; 163 | padding: 1em; 164 | width: 60%; 165 | } 166 | 167 | .booktitle { font-size : 140% } 168 | .authors { font-size : 90%; 169 | line-height: 115%; } 170 | .moreauthors { font-size : 60% } 171 | 172 | #index #entrance { 173 | text-align: center; 174 | } 175 | 176 | #index #entrance .spacer { 177 | margin: 0 30px 0 30px; 178 | } 179 | 180 | ul.doclist { 181 | margin-top: 0em; 182 | margin-bottom: 0em; 183 | } 184 | 185 | #toc > * { 186 | clear: both; 187 | } 188 | 189 | #toc > a { 190 | display: block; 191 | float: left; 192 | margin-top: 1em; 193 | } 194 | 195 | #toc a h2{ 196 | display: inline; 197 | } 198 | -------------------------------------------------------------------------------- /extra/resources/coqdocjs.css: -------------------------------------------------------------------------------- 1 | /* replace unicode */ 2 | 3 | .id[repl] .hidden { 4 | font-size: 0; 5 | } 6 | 7 | .id[repl]:before{ 8 | content: attr(repl); 9 | } 10 | 11 | /* folding proofs */ 12 | 13 | @keyframes show-proof { 14 | 0% { 15 | max-height: 1.2em; 16 | opacity: 1; 17 | } 18 | 99% { 19 | max-height: 1000em; 20 | } 21 | 100%{ 22 | } 23 | } 24 | 25 | @keyframes hide-proof { 26 | from { 27 | visibility: visible; 28 | max-height: 10em; 29 | opacity: 1; 30 | } 31 | to { 32 | max-height: 1.2em; 33 | } 34 | } 35 | 36 | .proof { 37 | cursor: pointer; 38 | } 39 | .proof * { 40 | cursor: pointer; 41 | } 42 | 43 | .proof { 44 | overflow: hidden; 45 | position: relative; 46 | transition: opacity 1s; 47 | display: inline-block; 48 | } 49 | 50 | .proof[show="false"] { 51 | max-height: 1.2em; 52 | visibility: visible; 53 | opacity: 0.3; 54 | } 55 | 56 | .proof[show="false"][animate] { 57 | animation-name: hide-proof; 58 | animation-duration: 0.25s; 59 | } 60 | 61 | .proof[show=true] { 62 | animation-name: show-proof; 63 | animation-duration: 10s; 64 | } 65 | 66 | .proof[show="false"]:before { 67 | position: absolute; 68 | visibility: visible; 69 | width: 100%; 70 | height: 100%; 71 | display: block; 72 | opacity: 0; 73 | content: "M"; 74 | } 75 | .proof[show="false"]:hover:before { 76 | content: ""; 77 | } 78 | 79 | .proof[show="false"] + br + br { 80 | display: none; 81 | } 82 | 83 | .proof[show="false"]:hover { 84 | visibility: visible; 85 | opacity: 0.5; 86 | } 87 | 88 | #toggle-proofs[proof-status="no-proofs"] { 89 | display: none; 90 | } 91 | 92 | #toggle-proofs[proof-status="some-hidden"]:before { 93 | content: "Show Proofs"; 94 | } 95 | 96 | #toggle-proofs[proof-status="all-shown"]:before { 97 | content: "Hide Proofs"; 98 | } 99 | 100 | 101 | /* page layout */ 102 | 103 | html, body { 104 | height: 100%; 105 | margin:0; 106 | padding:0; 107 | } 108 | 109 | @media only screen { /* no div with internal scrolling to allow printing of whole content */ 110 | body { 111 | display: flex; 112 | flex-direction: column 113 | } 114 | 115 | #content { 116 | flex: 1; 117 | overflow: auto; 118 | display: flex; 119 | flex-direction: column; 120 | } 121 | } 122 | 123 | #content:focus { 124 | outline: none; /* prevent glow in OS X */ 125 | } 126 | 127 | #main { 128 | display: block; 129 | padding: 16px; 130 | padding-top: 1em; 131 | padding-bottom: 2em; 132 | margin-left: auto; 133 | margin-right: auto; 134 | max-width: 60em; 135 | flex: 1 0 auto; 136 | } 137 | 138 | .libtitle { 139 | display: none; 140 | } 141 | 142 | /* header */ 143 | #header { 144 | width:100%; 145 | padding: 0; 146 | margin: 0; 147 | display: flex; 148 | align-items: center; 149 | background-color: rgb(21,57,105); 150 | color: white; 151 | font-weight: bold; 152 | overflow: hidden; 153 | } 154 | 155 | 156 | .button { 157 | cursor: pointer; 158 | } 159 | 160 | #header * { 161 | text-decoration: none; 162 | vertical-align: middle; 163 | margin-left: 15px; 164 | margin-right: 15px; 165 | } 166 | 167 | #header > .right, #header > .left { 168 | display: flex; 169 | flex: 1; 170 | align-items: center; 171 | } 172 | #header > .left { 173 | text-align: left; 174 | } 175 | #header > .right { 176 | flex-direction: row-reverse; 177 | } 178 | 179 | #header a, #header .button { 180 | color: white; 181 | box-sizing: border-box; 182 | } 183 | 184 | #header a { 185 | border-radius: 0; 186 | padding: 0.2em; 187 | } 188 | 189 | #header .button { 190 | background-color: rgb(63, 103, 156); 191 | border-radius: 1em; 192 | padding-left: 0.5em; 193 | padding-right: 0.5em; 194 | margin: 0.2em; 195 | } 196 | 197 | #header a:hover, #header .button:hover { 198 | background-color: rgb(181, 213, 255); 199 | color: black; 200 | } 201 | 202 | #header h1 { padding: 0; 203 | margin: 0;} 204 | 205 | /* footer */ 206 | #footer { 207 | text-align: center; 208 | opacity: 0.5; 209 | font-size: 75%; 210 | } 211 | 212 | /* hyperlinks */ 213 | 214 | @keyframes highlight { 215 | 50%{ 216 | background-color: black; 217 | } 218 | } 219 | 220 | :target * { 221 | animation-name: highlight; 222 | animation-duration: 1s; 223 | } 224 | 225 | a[name]:empty { 226 | float: right; 227 | } 228 | 229 | /* Proviola */ 230 | 231 | div.code { 232 | width: auto; 233 | float: none; 234 | } 235 | 236 | div.goal { 237 | position: fixed; 238 | left: 75%; 239 | width: 25%; 240 | top: 3em; 241 | } 242 | 243 | div.doc { 244 | clear: both; 245 | } 246 | 247 | span.command:hover { 248 | background-color: inherit; 249 | } 250 | -------------------------------------------------------------------------------- /extra/resources/coqdocjs.js: -------------------------------------------------------------------------------- 1 | var coqdocjs = coqdocjs || {}; 2 | (function(){ 3 | 4 | function replace(s){ 5 | var m; 6 | if (m = s.match(/^(.+)'/)) { 7 | return replace(m[1])+"'"; 8 | } else if (m = s.match(/^([A-Za-z]+)_?(\d+)$/)) { 9 | return replace(m[1])+m[2].replace(/\d/g, function(d){ 10 | if (coqdocjs.subscr.hasOwnProperty(d)) { 11 | return coqdocjs.subscr[d]; 12 | } else { 13 | return d; 14 | } 15 | }); 16 | } else if (coqdocjs.repl.hasOwnProperty(s)){ 17 | return coqdocjs.repl[s] 18 | } else { 19 | return s; 20 | } 21 | } 22 | 23 | function toArray(nl){ 24 | return Array.prototype.slice.call(nl); 25 | } 26 | 27 | function replInTextNodes() { 28 | coqdocjs.replInText.forEach(function(toReplace){ 29 | toArray(document.getElementsByClassName("code")).concat(toArray(document.getElementsByClassName("inlinecode"))).forEach(function(elem){ 30 | toArray(elem.childNodes).forEach(function(node){ 31 | if (node.nodeType != Node.TEXT_NODE) return; 32 | var fragments = node.textContent.split(toReplace); 33 | node.textContent = fragments[fragments.length-1]; 34 | for (var k = 0; k < fragments.length - 1; ++k) { 35 | node.parentNode.insertBefore(document.createTextNode(fragments[k]),node); 36 | var replacement = document.createElement("span"); 37 | replacement.appendChild(document.createTextNode(toReplace)); 38 | replacement.setAttribute("class", "id"); 39 | replacement.setAttribute("type", "keyword"); 40 | node.parentNode.insertBefore(replacement, node); 41 | } 42 | }); 43 | }); 44 | }); 45 | } 46 | 47 | function replNodes() { 48 | toArray(document.getElementsByClassName("id")).forEach(function(node){ 49 | if (["var", "variable", "keyword", "notation", "definition", "inductive"].indexOf(node.getAttribute("type"))>=0){ 50 | var text = node.textContent; 51 | var replText = replace(text); 52 | if(text != replText) { 53 | node.setAttribute("repl", replText); 54 | node.setAttribute("title", text); 55 | var hidden = document.createElement("span"); 56 | hidden.setAttribute("class", "hidden"); 57 | while (node.firstChild) { 58 | hidden.appendChild(node.firstChild); 59 | } 60 | node.appendChild(hidden); 61 | } 62 | } 63 | }); 64 | } 65 | 66 | function isVernacStart(l, t){ 67 | t = t.trim(); 68 | for(var s of l){ 69 | if (t == s || t.startsWith(s+" ") || t.startsWith(s+".")){ 70 | return true; 71 | } 72 | } 73 | return false; 74 | } 75 | 76 | function isProofStart(n){ 77 | return isVernacStart(["Proof"], n.textContent) && !isVernacStart(["Default", "Suggest"], n.previousSibling.previousSibling.textContent) || 78 | (isVernacStart(["Next"], n.textContent) && isVernacStart(["Obligation"], n.nextSibling.nextSibling.textContent)); 79 | } 80 | 81 | function isProofEnd(s){ 82 | return isVernacStart(["Qed", "Admitted", "Defined", "Abort"], s); 83 | } 84 | 85 | function proofStatus(){ 86 | var proofs = toArray(document.getElementsByClassName("proof")); 87 | if(proofs.length) { 88 | for(var proof of proofs) { 89 | if (proof.getAttribute("show") === "false") { 90 | return "some-hidden"; 91 | } 92 | } 93 | return "all-shown"; 94 | } 95 | else { 96 | return "no-proofs"; 97 | } 98 | } 99 | 100 | function updateView(){ 101 | document.getElementById("toggle-proofs").setAttribute("proof-status", proofStatus()); 102 | } 103 | 104 | function foldProofs() { 105 | var hasCommands = true; 106 | var nodes = document.getElementsByClassName("command"); 107 | if(nodes.length == 0) { 108 | hasCommands = false; 109 | console.log("no command tags found") 110 | nodes = document.getElementsByClassName("id"); 111 | } 112 | toArray(nodes).forEach(function(node){ 113 | if(isProofStart(node)) { 114 | var proof = document.createElement("span"); 115 | proof.setAttribute("class", "proof"); 116 | 117 | node.parentNode.insertBefore(proof, node); 118 | if(proof.previousSibling.nodeType === Node.TEXT_NODE) 119 | proof.appendChild(proof.previousSibling); 120 | while(node && !isProofEnd(node.textContent)) { 121 | proof.appendChild(node); 122 | node = proof.nextSibling; 123 | } 124 | if (proof.nextSibling) proof.appendChild(proof.nextSibling); // the Qed 125 | if (!hasCommands && proof.nextSibling) proof.appendChild(proof.nextSibling); // the dot after the Qed 126 | 127 | proof.addEventListener("click", function(proof){return function(e){ 128 | if (e.target.parentNode.tagName.toLowerCase() === "a") 129 | return; 130 | proof.setAttribute("show", proof.getAttribute("show") === "true" ? "false" : "true"); 131 | proof.setAttribute("animate", ""); 132 | updateView(); 133 | };}(proof)); 134 | proof.setAttribute("show", "false"); 135 | } 136 | }); 137 | } 138 | 139 | function toggleProofs(){ 140 | var someProofsHidden = proofStatus() === "some-hidden"; 141 | toArray(document.getElementsByClassName("proof")).forEach(function(proof){ 142 | proof.setAttribute("show", someProofsHidden); 143 | proof.setAttribute("animate", ""); 144 | }); 145 | updateView(); 146 | } 147 | 148 | function repairDom(){ 149 | // pull whitespace out of command 150 | toArray(document.getElementsByClassName("command")).forEach(function(node){ 151 | while(node.firstChild && node.firstChild.textContent.trim() == ""){ 152 | console.log("try move"); 153 | node.parentNode.insertBefore(node.firstChild, node); 154 | } 155 | }); 156 | toArray(document.getElementsByClassName("id")).forEach(function(node){ 157 | node.setAttribute("type", node.getAttribute("title")); 158 | }); 159 | toArray(document.getElementsByClassName("idref")).forEach(function(ref){ 160 | toArray(ref.childNodes).forEach(function(child){ 161 | if (["var", "variable"].indexOf(child.getAttribute("type")) > -1) 162 | ref.removeAttribute("href"); 163 | }); 164 | }); 165 | 166 | } 167 | 168 | function fixTitle(){ 169 | var url = "/" + window.location.pathname; 170 | var basename = url.substring(url.lastIndexOf('/')+1, url.lastIndexOf('.')); 171 | if (basename === "toc") {document.title = "Table of Contents";} 172 | else if (basename === "indexpage") {document.title = "Index";} 173 | else {document.title = basename;} 174 | } 175 | 176 | function postprocess(){ 177 | repairDom(); 178 | replInTextNodes() 179 | replNodes(); 180 | foldProofs(); 181 | document.getElementById("toggle-proofs").addEventListener("click", toggleProofs); 182 | updateView(); 183 | } 184 | 185 | fixTitle(); 186 | document.addEventListener('DOMContentLoaded', postprocess); 187 | 188 | coqdocjs.toggleProofs = toggleProofs; 189 | })(); 190 | --------------------------------------------------------------------------------