main.js (34965B) - Raw
1 (function() { 2 const CAT_namespace = 0; 3 const CAT_container = 1; 4 const CAT_global_variable = 2; 5 const CAT_function = 3; 6 const CAT_primitive = 4; 7 const CAT_error_set = 5; 8 const CAT_global_const = 6; 9 const CAT_alias = 7; 10 const CAT_type = 8; 11 const CAT_type_type = 9; 12 const CAT_type_function = 10; 13 14 const LOG_err = 0; 15 const LOG_warn = 1; 16 const LOG_info = 2; 17 const LOG_debug = 3; 18 19 const domDocTestsCode = document.getElementById("docTestsCode"); 20 const domFnErrorsAnyError = document.getElementById("fnErrorsAnyError"); 21 const domFnProto = document.getElementById("fnProto"); 22 const domFnProtoCode = document.getElementById("fnProtoCode"); 23 const domHdrName = document.getElementById("hdrName"); 24 const domHelpModal = document.getElementById("helpDialog"); 25 const domListErrSets = document.getElementById("listErrSets"); 26 const domListFields = document.getElementById("listFields"); 27 const domListParams = document.getElementById("listParams"); 28 const domListFnErrors = document.getElementById("listFnErrors"); 29 const domListFns = document.getElementById("listFns"); 30 const domListGlobalVars = document.getElementById("listGlobalVars"); 31 const domListInfo = document.getElementById("listInfo"); 32 const domListNamespaces = document.getElementById("listNamespaces"); 33 const domListNav = document.getElementById("listNav"); 34 const domListSearchResults = document.getElementById("listSearchResults"); 35 const domListTypes = document.getElementById("listTypes"); 36 const domListValues = document.getElementById("listValues"); 37 const domSearch = document.getElementById("search"); 38 const domSectDocTests = document.getElementById("sectDocTests"); 39 const domSectErrSets = document.getElementById("sectErrSets"); 40 const domSectFields = document.getElementById("sectFields"); 41 const domSectParams = document.getElementById("sectParams"); 42 const domSectFnErrors = document.getElementById("sectFnErrors"); 43 const domSectFns = document.getElementById("sectFns"); 44 const domSectGlobalVars = document.getElementById("sectGlobalVars"); 45 const domSectNamespaces = document.getElementById("sectNamespaces"); 46 const domSectNav = document.getElementById("sectNav"); 47 const domSectSearchNoResults = document.getElementById("sectSearchNoResults"); 48 const domSectSearchResults = document.getElementById("sectSearchResults"); 49 const domSectSource = document.getElementById("sectSource"); 50 const domSectTypes = document.getElementById("sectTypes"); 51 const domSectValues = document.getElementById("sectValues"); 52 const domSourceText = document.getElementById("sourceText"); 53 const domStatus = document.getElementById("status"); 54 const domTableFnErrors = document.getElementById("tableFnErrors"); 55 const domTldDocs = document.getElementById("tldDocs"); 56 const domErrors = document.getElementById("errors"); 57 const domErrorsText = document.getElementById("errorsText"); 58 59 var searchTimer = null; 60 61 const curNav = { 62 // 0 = home 63 // 1 = decl (decl) 64 // 2 = source (path) 65 tag: 0, 66 // unsigned int: decl index 67 decl: null, 68 // string file name matching tarball path 69 path: null, 70 71 // when this is populated, pressing the "view source" command will 72 // navigate to this hash. 73 viewSourceHash: null, 74 }; 75 var curNavSearch = ""; 76 var curSearchIndex = -1; 77 var imFeelingLucky = false; 78 79 // names of modules in the same order as wasm 80 const moduleList = []; 81 82 let wasm_promise = fetch("main.wasm"); 83 let sources_promise = fetch("sources.tar").then(function(response) { 84 if (!response.ok) throw new Error("unable to download sources"); 85 return response.arrayBuffer(); 86 }); 87 var wasm_exports = null; 88 89 const text_decoder = new TextDecoder(); 90 const text_encoder = new TextEncoder(); 91 92 WebAssembly.instantiateStreaming(wasm_promise, { 93 js: { 94 log: function(level, ptr, len) { 95 const msg = decodeString(ptr, len); 96 switch (level) { 97 case LOG_err: 98 console.error(msg); 99 domErrorsText.textContent += msg + "\n"; 100 domErrors.classList.remove("hidden"); 101 break; 102 case LOG_warn: 103 console.warn(msg); 104 break; 105 case LOG_info: 106 console.info(msg); 107 break; 108 case LOG_debug: 109 console.debug(msg); 110 break; 111 } 112 }, 113 }, 114 }).then(function(obj) { 115 wasm_exports = obj.instance.exports; 116 window.wasm = obj; // for debugging 117 118 sources_promise.then(function(buffer) { 119 const js_array = new Uint8Array(buffer); 120 const ptr = wasm_exports.alloc(js_array.length); 121 const wasm_array = new Uint8Array(wasm_exports.memory.buffer, ptr, js_array.length); 122 wasm_array.set(js_array); 123 wasm_exports.unpack(ptr, js_array.length); 124 125 updateModuleList(); 126 127 window.addEventListener('popstate', onPopState, false); 128 domSearch.addEventListener('keydown', onSearchKeyDown, false); 129 domSearch.addEventListener('input', onSearchChange, false); 130 window.addEventListener('keydown', onWindowKeyDown, false); 131 onHashChange(null); 132 if (domSearch.value) { 133 // user started typing a search query while the page was loading 134 curSearchIndex = -1; 135 startAsyncSearch(); 136 } 137 }); 138 }); 139 140 function renderTitle() { 141 const suffix = " - Zig Documentation"; 142 if (curNavSearch.length > 0) { 143 document.title = curNavSearch + " - Search" + suffix; 144 } else if (curNav.decl != null) { 145 document.title = fullyQualifiedName(curNav.decl) + suffix; 146 } else if (curNav.path != null) { 147 document.title = curNav.path + suffix; 148 } else { 149 document.title = moduleList[0] + suffix; // Home 150 } 151 } 152 153 function render() { 154 domFnErrorsAnyError.classList.add("hidden"); 155 domFnProto.classList.add("hidden"); 156 domHdrName.classList.add("hidden"); 157 domHelpModal.classList.add("hidden"); 158 domSectErrSets.classList.add("hidden"); 159 domSectDocTests.classList.add("hidden"); 160 domSectFields.classList.add("hidden"); 161 domSectParams.classList.add("hidden"); 162 domSectFnErrors.classList.add("hidden"); 163 domSectFns.classList.add("hidden"); 164 domSectGlobalVars.classList.add("hidden"); 165 domSectNamespaces.classList.add("hidden"); 166 domSectNav.classList.add("hidden"); 167 domSectSearchNoResults.classList.add("hidden"); 168 domSectSearchResults.classList.add("hidden"); 169 domSectSource.classList.add("hidden"); 170 domSectTypes.classList.add("hidden"); 171 domSectValues.classList.add("hidden"); 172 domStatus.classList.add("hidden"); 173 domTableFnErrors.classList.add("hidden"); 174 domTldDocs.classList.add("hidden"); 175 176 renderTitle(); 177 178 if (curNavSearch !== "") return renderSearch(); 179 180 switch (curNav.tag) { 181 case 0: return renderHome(); 182 case 1: 183 if (curNav.decl == null) { 184 return renderNotFound(); 185 } else { 186 return renderDecl(curNav.decl); 187 } 188 case 2: return renderSource(curNav.path); 189 default: throw new Error("invalid navigation state"); 190 } 191 } 192 193 function renderHome() { 194 if (moduleList.length == 0) { 195 domStatus.textContent = "sources.tar contains no modules"; 196 domStatus.classList.remove("hidden"); 197 return; 198 } 199 return renderModule(0); 200 } 201 202 function renderModule(pkg_index) { 203 const root_decl = wasm_exports.find_module_root(pkg_index); 204 return renderDecl(root_decl); 205 } 206 207 function renderDecl(decl_index) { 208 const category = wasm_exports.categorize_decl(decl_index, 0); 209 switch (category) { 210 case CAT_namespace: 211 case CAT_container: 212 return renderNamespacePage(decl_index); 213 case CAT_global_variable: 214 case CAT_primitive: 215 case CAT_global_const: 216 case CAT_type: 217 case CAT_type_type: 218 return renderGlobal(decl_index); 219 case CAT_function: 220 return renderFunction(decl_index); 221 case CAT_type_function: 222 return renderTypeFunction(decl_index); 223 case CAT_error_set: 224 return renderErrorSetPage(decl_index); 225 case CAT_alias: 226 return renderDecl(wasm_exports.get_aliasee()); 227 default: 228 throw new Error("unrecognized category " + category); 229 } 230 } 231 232 function renderSource(path) { 233 const decl_index = findFileRoot(path); 234 if (decl_index == null) return renderNotFound(); 235 236 renderNavFancy(decl_index, [{ 237 name: "[src]", 238 href: location.hash, 239 }]); 240 241 domSourceText.innerHTML = declSourceHtml(decl_index); 242 243 domSectSource.classList.remove("hidden"); 244 } 245 246 function renderDeclHeading(decl_index) { 247 curNav.viewSourceHash = "#src/" + unwrapString(wasm_exports.decl_file_path(decl_index)); 248 249 const hdrNameSpan = domHdrName.children[0]; 250 const srcLink = domHdrName.children[1]; 251 hdrNameSpan.innerText = unwrapString(wasm_exports.decl_category_name(decl_index)); 252 srcLink.setAttribute('href', curNav.viewSourceHash); 253 domHdrName.classList.remove("hidden"); 254 255 renderTopLevelDocs(decl_index); 256 } 257 258 function renderTopLevelDocs(decl_index) { 259 const tld_docs_html = unwrapString(wasm_exports.decl_docs_html(decl_index, false)); 260 if (tld_docs_html.length > 0) { 261 domTldDocs.innerHTML = tld_docs_html; 262 domTldDocs.classList.remove("hidden"); 263 } 264 } 265 266 function renderNav(cur_nav_decl, list) { 267 return renderNavFancy(cur_nav_decl, []); 268 } 269 270 function renderNavFancy(cur_nav_decl, list) { 271 { 272 // First, walk backwards the decl parents within a file. 273 let decl_it = cur_nav_decl; 274 let prev_decl_it = null; 275 while (decl_it != null) { 276 list.push({ 277 name: declIndexName(decl_it), 278 href: navLinkDeclIndex(decl_it), 279 }); 280 prev_decl_it = decl_it; 281 decl_it = declParent(decl_it); 282 } 283 284 // Next, walk backwards the file path segments. 285 if (prev_decl_it != null) { 286 const file_path = fullyQualifiedName(prev_decl_it); 287 const parts = file_path.split("."); 288 parts.pop(); // skip last 289 for (;;) { 290 const href = navLinkFqn(parts.join(".")); 291 const part = parts.pop(); 292 if (!part) break; 293 list.push({ 294 name: part, 295 href: href, 296 }); 297 } 298 } 299 300 list.reverse(); 301 } 302 resizeDomList(domListNav, list.length, '<li><a href="#"></a></li>'); 303 304 for (let i = 0; i < list.length; i += 1) { 305 const liDom = domListNav.children[i]; 306 const aDom = liDom.children[0]; 307 aDom.textContent = list[i].name; 308 aDom.setAttribute('href', list[i].href); 309 if (i + 1 == list.length) { 310 aDom.classList.add("active"); 311 } else { 312 aDom.classList.remove("active"); 313 } 314 } 315 316 domSectNav.classList.remove("hidden"); 317 } 318 319 function renderNotFound() { 320 domStatus.textContent = "Declaration not found."; 321 domStatus.classList.remove("hidden"); 322 } 323 324 function navLinkFqn(full_name) { 325 return '#' + full_name; 326 } 327 328 function navLinkDeclIndex(decl_index) { 329 return navLinkFqn(fullyQualifiedName(decl_index)); 330 } 331 332 function resizeDomList(listDom, desiredLen, templateHtml) { 333 // add the missing dom entries 334 var i, ev; 335 for (i = listDom.childElementCount; i < desiredLen; i += 1) { 336 listDom.insertAdjacentHTML('beforeend', templateHtml); 337 } 338 // remove extra dom entries 339 while (desiredLen < listDom.childElementCount) { 340 listDom.removeChild(listDom.lastChild); 341 } 342 } 343 344 function renderErrorSetPage(decl_index) { 345 renderNav(decl_index); 346 renderDeclHeading(decl_index); 347 348 const errorSetList = declErrorSet(decl_index).slice(); 349 renderErrorSet(decl_index, errorSetList); 350 } 351 352 function renderErrorSet(base_decl, errorSetList) { 353 if (errorSetList == null) { 354 domFnErrorsAnyError.classList.remove("hidden"); 355 } else { 356 resizeDomList(domListFnErrors, errorSetList.length, '<div></div>'); 357 for (let i = 0; i < errorSetList.length; i += 1) { 358 const divDom = domListFnErrors.children[i]; 359 const html = unwrapString(wasm_exports.error_html(base_decl, errorSetList[i])); 360 divDom.innerHTML = html; 361 } 362 domTableFnErrors.classList.remove("hidden"); 363 } 364 domSectFnErrors.classList.remove("hidden"); 365 } 366 367 function renderParams(decl_index) { 368 // Prevent params from being emptied next time wasm calls memory.grow. 369 const params = declParams(decl_index).slice(); 370 if (params.length !== 0) { 371 resizeDomList(domListParams, params.length, '<div></div>'); 372 for (let i = 0; i < params.length; i += 1) { 373 const divDom = domListParams.children[i]; 374 divDom.innerHTML = unwrapString(wasm_exports.decl_param_html(decl_index, params[i])); 375 } 376 domSectParams.classList.remove("hidden"); 377 } 378 } 379 380 function renderTypeFunction(decl_index) { 381 renderNav(decl_index); 382 renderDeclHeading(decl_index); 383 renderTopLevelDocs(decl_index); 384 renderParams(decl_index); 385 renderDocTests(decl_index); 386 387 const members = unwrapSlice32(wasm_exports.type_fn_members(decl_index, false)).slice(); 388 const fields = unwrapSlice32(wasm_exports.type_fn_fields(decl_index)).slice(); 389 if (members.length !== 0 || fields.length !== 0) { 390 renderNamespace(decl_index, members, fields); 391 } else { 392 domSourceText.innerHTML = declSourceHtml(decl_index); 393 domSectSource.classList.remove("hidden"); 394 } 395 } 396 397 function renderDocTests(decl_index) { 398 const doctest_html = declDoctestHtml(decl_index); 399 if (doctest_html.length > 0) { 400 domDocTestsCode.innerHTML = doctest_html; 401 domSectDocTests.classList.remove("hidden"); 402 } 403 } 404 405 function renderFunction(decl_index) { 406 renderNav(decl_index); 407 renderDeclHeading(decl_index); 408 renderTopLevelDocs(decl_index); 409 renderParams(decl_index); 410 renderDocTests(decl_index); 411 412 domFnProtoCode.innerHTML = fnProtoHtml(decl_index, false); 413 domFnProto.classList.remove("hidden"); 414 415 416 const errorSetNode = fnErrorSet(decl_index); 417 if (errorSetNode != null) { 418 const base_decl = wasm_exports.fn_error_set_decl(decl_index, errorSetNode); 419 renderErrorSet(base_decl, errorSetNodeList(decl_index, errorSetNode)); 420 } 421 422 domSourceText.innerHTML = declSourceHtml(decl_index); 423 domSectSource.classList.remove("hidden"); 424 } 425 426 function renderGlobal(decl_index) { 427 renderNav(decl_index); 428 renderDeclHeading(decl_index); 429 430 const docs_html = declDocsHtmlShort(decl_index); 431 if (docs_html.length > 0) { 432 domTldDocs.innerHTML = docs_html; 433 domTldDocs.classList.remove("hidden"); 434 } 435 436 domSourceText.innerHTML = declSourceHtml(decl_index); 437 domSectSource.classList.remove("hidden"); 438 } 439 440 function renderNamespace(base_decl, members, fields) { 441 const typesList = []; 442 const namespacesList = []; 443 const errSetsList = []; 444 const fnsList = []; 445 const varsList = []; 446 const valsList = []; 447 448 member_loop: for (let i = 0; i < members.length; i += 1) { 449 let member = members[i]; 450 const original = member; 451 while (true) { 452 const member_category = wasm_exports.categorize_decl(member, 0); 453 switch (member_category) { 454 case CAT_namespace: 455 namespacesList.push({original: original, member: member}); 456 continue member_loop; 457 case CAT_container: 458 typesList.push({original: original, member: member}); 459 continue member_loop; 460 case CAT_global_variable: 461 varsList.push(member); 462 continue member_loop; 463 case CAT_function: 464 fnsList.push(member); 465 continue member_loop; 466 case CAT_type: 467 case CAT_type_type: 468 case CAT_type_function: 469 typesList.push({original: original, member: member}); 470 continue member_loop; 471 case CAT_error_set: 472 errSetsList.push({original: original, member: member}); 473 continue member_loop; 474 case CAT_global_const: 475 case CAT_primitive: 476 valsList.push({original: original, member: member}); 477 continue member_loop; 478 case CAT_alias: 479 member = wasm_exports.get_aliasee(); 480 continue; 481 default: 482 throw new Error("uknown category: " + member_category); 483 } 484 } 485 } 486 487 typesList.sort(byDeclIndexName2); 488 namespacesList.sort(byDeclIndexName2); 489 errSetsList.sort(byDeclIndexName2); 490 fnsList.sort(byDeclIndexName); 491 varsList.sort(byDeclIndexName); 492 valsList.sort(byDeclIndexName2); 493 494 if (typesList.length !== 0) { 495 resizeDomList(domListTypes, typesList.length, '<li><a href="#"></a></li>'); 496 for (let i = 0; i < typesList.length; i += 1) { 497 const liDom = domListTypes.children[i]; 498 const aDom = liDom.children[0]; 499 const original_decl = typesList[i].original; 500 const decl = typesList[i].member; 501 aDom.textContent = declIndexName(original_decl); 502 aDom.setAttribute('href', navLinkDeclIndex(decl)); 503 } 504 domSectTypes.classList.remove("hidden"); 505 } 506 if (namespacesList.length !== 0) { 507 resizeDomList(domListNamespaces, namespacesList.length, '<li><a href="#"></a></li>'); 508 for (let i = 0; i < namespacesList.length; i += 1) { 509 const liDom = domListNamespaces.children[i]; 510 const aDom = liDom.children[0]; 511 const original_decl = namespacesList[i].original; 512 const decl = namespacesList[i].member; 513 aDom.textContent = declIndexName(original_decl); 514 aDom.setAttribute('href', navLinkDeclIndex(decl)); 515 } 516 domSectNamespaces.classList.remove("hidden"); 517 } 518 519 if (errSetsList.length !== 0) { 520 resizeDomList(domListErrSets, errSetsList.length, '<li><a href="#"></a></li>'); 521 for (let i = 0; i < errSetsList.length; i += 1) { 522 const liDom = domListErrSets.children[i]; 523 const aDom = liDom.children[0]; 524 const original_decl = errSetsList[i].original; 525 const decl = errSetsList[i].member; 526 aDom.textContent = declIndexName(original_decl); 527 aDom.setAttribute('href', navLinkDeclIndex(decl)); 528 } 529 domSectErrSets.classList.remove("hidden"); 530 } 531 532 if (fnsList.length !== 0) { 533 resizeDomList(domListFns, fnsList.length, 534 '<div><dt><code></code></dt><dd></dd></div>'); 535 for (let i = 0; i < fnsList.length; i += 1) { 536 const decl = fnsList[i]; 537 const divDom = domListFns.children[i]; 538 539 const dtDom = divDom.children[0]; 540 const ddDocs = divDom.children[1]; 541 const protoCodeDom = dtDom.children[0]; 542 543 protoCodeDom.innerHTML = fnProtoHtml(decl, true); 544 ddDocs.innerHTML = declDocsHtmlShort(decl); 545 } 546 domSectFns.classList.remove("hidden"); 547 } 548 549 if (fields.length !== 0) { 550 resizeDomList(domListFields, fields.length, '<div></div>'); 551 for (let i = 0; i < fields.length; i += 1) { 552 const divDom = domListFields.children[i]; 553 divDom.innerHTML = unwrapString(wasm_exports.decl_field_html(base_decl, fields[i])); 554 } 555 domSectFields.classList.remove("hidden"); 556 } 557 558 if (varsList.length !== 0) { 559 resizeDomList(domListGlobalVars, varsList.length, 560 '<tr><td><a href="#"></a></td><td></td><td></td></tr>'); 561 for (let i = 0; i < varsList.length; i += 1) { 562 const decl = varsList[i]; 563 const trDom = domListGlobalVars.children[i]; 564 565 const tdName = trDom.children[0]; 566 const tdNameA = tdName.children[0]; 567 const tdType = trDom.children[1]; 568 const tdDesc = trDom.children[2]; 569 570 tdNameA.setAttribute('href', navLinkDeclIndex(decl)); 571 tdNameA.textContent = declIndexName(decl); 572 573 tdType.innerHTML = declTypeHtml(decl); 574 tdDesc.innerHTML = declDocsHtmlShort(decl); 575 } 576 domSectGlobalVars.classList.remove("hidden"); 577 } 578 579 if (valsList.length !== 0) { 580 resizeDomList(domListValues, valsList.length, 581 '<tr><td><a href="#"></a></td><td></td><td></td></tr>'); 582 for (let i = 0; i < valsList.length; i += 1) { 583 const trDom = domListValues.children[i]; 584 const tdName = trDom.children[0]; 585 const tdNameA = tdName.children[0]; 586 const tdType = trDom.children[1]; 587 const tdDesc = trDom.children[2]; 588 589 const original_decl = valsList[i].original; 590 const decl = valsList[i].member; 591 tdNameA.setAttribute('href', navLinkDeclIndex(decl)); 592 tdNameA.textContent = declIndexName(original_decl); 593 594 tdType.innerHTML = declTypeHtml(decl); 595 tdDesc.innerHTML = declDocsHtmlShort(decl); 596 } 597 domSectValues.classList.remove("hidden"); 598 } 599 } 600 601 function renderNamespacePage(decl_index) { 602 renderNav(decl_index); 603 renderDeclHeading(decl_index); 604 const members = namespaceMembers(decl_index, false).slice(); 605 const fields = declFields(decl_index).slice(); 606 renderNamespace(decl_index, members, fields); 607 } 608 609 function operatorCompare(a, b) { 610 if (a === b) { 611 return 0; 612 } else if (a < b) { 613 return -1; 614 } else { 615 return 1; 616 } 617 } 618 619 function updateCurNav(location_hash) { 620 curNav.tag = 0; 621 curNav.decl = null; 622 curNav.path = null; 623 curNav.viewSourceHash = null; 624 curNavSearch = ""; 625 626 if (location_hash.length > 1 && location_hash[0] === '#') { 627 const query = location_hash.substring(1); 628 const qpos = query.indexOf("?"); 629 let nonSearchPart; 630 if (qpos === -1) { 631 nonSearchPart = query; 632 } else { 633 nonSearchPart = query.substring(0, qpos); 634 curNavSearch = decodeURIComponent(query.substring(qpos + 1)); 635 } 636 637 if (nonSearchPart.length > 0) { 638 const source_mode = nonSearchPart.startsWith("src/"); 639 if (source_mode) { 640 curNav.tag = 2; 641 curNav.path = nonSearchPart.substring(4); 642 } else { 643 curNav.tag = 1; 644 curNav.decl = findDecl(nonSearchPart); 645 } 646 } 647 } 648 } 649 650 function onHashChange(state) { 651 // Use a non-null state value to prevent the window scrolling if the user goes back to this history entry. 652 history.replaceState({}, ""); 653 navigate(location.hash); 654 if (state == null) window.scrollTo({top: 0}); 655 } 656 657 function onPopState(ev) { 658 onHashChange(ev.state); 659 syncDomSearch(); 660 } 661 662 function navigate(location_hash) { 663 updateCurNav(location_hash); 664 render(); 665 if (imFeelingLucky) { 666 imFeelingLucky = false; 667 activateSelectedResult(); 668 } 669 } 670 671 function syncDomSearch() { 672 if (domSearch.value !== curNavSearch) { 673 domSearch.value = curNavSearch; 674 } 675 } 676 677 function activateSelectedResult() { 678 if (domSectSearchResults.classList.contains("hidden")) { 679 return; 680 } 681 682 var liDom = domListSearchResults.children[curSearchIndex]; 683 if (liDom == null && domListSearchResults.children.length !== 0) { 684 liDom = domListSearchResults.children[0]; 685 } 686 if (liDom != null) { 687 var aDom = liDom.children[0]; 688 location.href = aDom.getAttribute("href"); 689 curSearchIndex = -1; 690 } 691 domSearch.blur(); 692 } 693 694 function onSearchKeyDown(ev) { 695 switch (ev.code) { 696 case "Enter": 697 if (ev.shiftKey || ev.ctrlKey || ev.altKey) return; 698 699 clearAsyncSearch(); 700 imFeelingLucky = true; 701 location.hash = computeSearchHash(); 702 703 ev.preventDefault(); 704 ev.stopPropagation(); 705 return; 706 case "Escape": 707 if (ev.shiftKey || ev.ctrlKey || ev.altKey) return; 708 709 domSearch.value = ""; 710 domSearch.blur(); 711 curSearchIndex = -1; 712 ev.preventDefault(); 713 ev.stopPropagation(); 714 startSearch(); 715 return; 716 case "ArrowUp": 717 if (ev.shiftKey || ev.ctrlKey || ev.altKey) return; 718 719 moveSearchCursor(-1); 720 ev.preventDefault(); 721 ev.stopPropagation(); 722 return; 723 case "ArrowDown": 724 if (ev.shiftKey || ev.ctrlKey || ev.altKey) return; 725 726 moveSearchCursor(1); 727 ev.preventDefault(); 728 ev.stopPropagation(); 729 return; 730 default: 731 ev.stopPropagation(); // prevent keyboard shortcuts 732 return; 733 } 734 } 735 736 function onSearchChange(ev) { 737 curSearchIndex = -1; 738 startAsyncSearch(); 739 } 740 741 function moveSearchCursor(dir) { 742 if (curSearchIndex < 0 || curSearchIndex >= domListSearchResults.children.length) { 743 if (dir > 0) { 744 curSearchIndex = -1 + dir; 745 } else if (dir < 0) { 746 curSearchIndex = domListSearchResults.children.length + dir; 747 } 748 } else { 749 curSearchIndex += dir; 750 } 751 if (curSearchIndex < 0) { 752 curSearchIndex = 0; 753 } 754 if (curSearchIndex >= domListSearchResults.children.length) { 755 curSearchIndex = domListSearchResults.children.length - 1; 756 } 757 renderSearchCursor(); 758 } 759 760 function onWindowKeyDown(ev) { 761 switch (ev.code) { 762 case "Escape": 763 if (ev.shiftKey || ev.ctrlKey || ev.altKey) return; 764 if (!domHelpModal.classList.contains("hidden")) { 765 domHelpModal.classList.add("hidden"); 766 ev.preventDefault(); 767 ev.stopPropagation(); 768 } 769 break; 770 case "KeyS": 771 if (ev.shiftKey || ev.ctrlKey || ev.altKey) return; 772 domSearch.focus(); 773 domSearch.select(); 774 ev.preventDefault(); 775 ev.stopPropagation(); 776 startAsyncSearch(); 777 break; 778 case "KeyU": 779 if (ev.shiftKey || ev.ctrlKey || ev.altKey) return; 780 ev.preventDefault(); 781 ev.stopPropagation(); 782 navigateToSource(); 783 break; 784 case "Slash": 785 if (!ev.shiftKey || ev.ctrlKey || ev.altKey) return; 786 ev.preventDefault(); 787 ev.stopPropagation(); 788 showHelpModal(); 789 break; 790 } 791 } 792 793 function showHelpModal() { 794 domHelpModal.classList.remove("hidden"); 795 domHelpModal.style.left = (window.innerWidth / 2 - domHelpModal.clientWidth / 2) + "px"; 796 domHelpModal.style.top = (window.innerHeight / 2 - domHelpModal.clientHeight / 2) + "px"; 797 domHelpModal.focus(); 798 } 799 800 function navigateToSource() { 801 if (curNav.viewSourceHash != null) { 802 location.hash = curNav.viewSourceHash; 803 } 804 } 805 806 function clearAsyncSearch() { 807 if (searchTimer != null) { 808 clearTimeout(searchTimer); 809 searchTimer = null; 810 } 811 } 812 813 function startAsyncSearch() { 814 clearAsyncSearch(); 815 searchTimer = setTimeout(startSearch, 10); 816 } 817 function computeSearchHash() { 818 // How location.hash works: 819 // 1. http://example.com/ => "" 820 // 2. http://example.com/# => "" 821 // 3. http://example.com/#foo => "#foo" 822 // wat 823 const oldWatHash = location.hash; 824 const oldHash = oldWatHash.startsWith("#") ? oldWatHash : "#" + oldWatHash; 825 const parts = oldHash.split("?"); 826 const newPart2 = (domSearch.value === "") ? "" : ("?" + domSearch.value); 827 return parts[0] + newPart2; 828 } 829 function startSearch() { 830 clearAsyncSearch(); 831 navigate(computeSearchHash()); 832 } 833 function renderSearch() { 834 renderNav(curNav.decl); 835 836 const ignoreCase = (curNavSearch.toLowerCase() === curNavSearch); 837 const results = executeQuery(curNavSearch, ignoreCase); 838 839 if (results.length !== 0) { 840 resizeDomList(domListSearchResults, results.length, '<li><a href="#"></a></li>'); 841 842 for (let i = 0; i < results.length; i += 1) { 843 const liDom = domListSearchResults.children[i]; 844 const aDom = liDom.children[0]; 845 const match = results[i]; 846 const full_name = fullyQualifiedName(match); 847 aDom.textContent = full_name; 848 aDom.setAttribute('href', navLinkFqn(full_name)); 849 } 850 renderSearchCursor(); 851 852 domSectSearchResults.classList.remove("hidden"); 853 } else { 854 domSectSearchNoResults.classList.remove("hidden"); 855 } 856 } 857 858 function renderSearchCursor() { 859 for (let i = 0; i < domListSearchResults.children.length; i += 1) { 860 var liDom = domListSearchResults.children[i]; 861 if (curSearchIndex === i) { 862 liDom.classList.add("selected"); 863 } else { 864 liDom.classList.remove("selected"); 865 } 866 } 867 } 868 869 function updateModuleList() { 870 moduleList.length = 0; 871 for (let i = 0;; i += 1) { 872 const name = unwrapString(wasm_exports.module_name(i)); 873 if (name.length == 0) break; 874 moduleList.push(name); 875 } 876 } 877 878 function byDeclIndexName(a, b) { 879 const a_name = declIndexName(a); 880 const b_name = declIndexName(b); 881 return operatorCompare(a_name, b_name); 882 } 883 884 function byDeclIndexName2(a, b) { 885 const a_name = declIndexName(a.original); 886 const b_name = declIndexName(b.original); 887 return operatorCompare(a_name, b_name); 888 } 889 890 function decodeString(ptr, len) { 891 if (len === 0) return ""; 892 return text_decoder.decode(new Uint8Array(wasm_exports.memory.buffer, ptr, len)); 893 } 894 895 function unwrapString(bigint) { 896 const ptr = Number(bigint & 0xffffffffn); 897 const len = Number(bigint >> 32n); 898 return decodeString(ptr, len); 899 } 900 901 function declTypeHtml(decl_index) { 902 return unwrapString(wasm_exports.decl_type_html(decl_index)); 903 } 904 905 function declDocsHtmlShort(decl_index) { 906 return unwrapString(wasm_exports.decl_docs_html(decl_index, true)); 907 } 908 909 function fullyQualifiedName(decl_index) { 910 return unwrapString(wasm_exports.decl_fqn(decl_index)); 911 } 912 913 function declIndexName(decl_index) { 914 return unwrapString(wasm_exports.decl_name(decl_index)); 915 } 916 917 function declSourceHtml(decl_index) { 918 return unwrapString(wasm_exports.decl_source_html(decl_index)); 919 } 920 921 function declDoctestHtml(decl_index) { 922 return unwrapString(wasm_exports.decl_doctest_html(decl_index)); 923 } 924 925 function fnProtoHtml(decl_index, linkify_fn_name) { 926 return unwrapString(wasm_exports.decl_fn_proto_html(decl_index, linkify_fn_name)); 927 } 928 929 function setQueryString(s) { 930 const jsArray = text_encoder.encode(s); 931 const len = jsArray.length; 932 const ptr = wasm_exports.query_begin(len); 933 const wasmArray = new Uint8Array(wasm_exports.memory.buffer, ptr, len); 934 wasmArray.set(jsArray); 935 } 936 937 function executeQuery(query_string, ignore_case) { 938 setQueryString(query_string); 939 const ptr = wasm_exports.query_exec(ignore_case); 940 const head = new Uint32Array(wasm_exports.memory.buffer, ptr, 1); 941 const len = head[0]; 942 return new Uint32Array(wasm_exports.memory.buffer, ptr + 4, len); 943 } 944 945 function namespaceMembers(decl_index, include_private) { 946 return unwrapSlice32(wasm_exports.namespace_members(decl_index, include_private)); 947 } 948 949 function declFields(decl_index) { 950 return unwrapSlice32(wasm_exports.decl_fields(decl_index)); 951 } 952 953 function declParams(decl_index) { 954 return unwrapSlice32(wasm_exports.decl_params(decl_index)); 955 } 956 957 function declErrorSet(decl_index) { 958 return unwrapSlice64(wasm_exports.decl_error_set(decl_index)); 959 } 960 961 function errorSetNodeList(base_decl, err_set_node) { 962 return unwrapSlice64(wasm_exports.error_set_node_list(base_decl, err_set_node)); 963 } 964 965 function unwrapSlice32(bigint) { 966 const ptr = Number(bigint & 0xffffffffn); 967 const len = Number(bigint >> 32n); 968 if (len === 0) return []; 969 return new Uint32Array(wasm_exports.memory.buffer, ptr, len); 970 } 971 972 function unwrapSlice64(bigint) { 973 const ptr = Number(bigint & 0xffffffffn); 974 const len = Number(bigint >> 32n); 975 if (len === 0) return []; 976 return new BigUint64Array(wasm_exports.memory.buffer, ptr, len); 977 } 978 979 function findDecl(fqn) { 980 setInputString(fqn); 981 const result = wasm_exports.find_decl(); 982 if (result === -1) return null; 983 return result; 984 } 985 986 function findFileRoot(path) { 987 setInputString(path); 988 const result = wasm_exports.find_file_root(); 989 if (result === -1) return null; 990 return result; 991 } 992 993 function declParent(decl_index) { 994 const result = wasm_exports.decl_parent(decl_index); 995 if (result === -1) return null; 996 return result; 997 } 998 999 function fnErrorSet(decl_index) { 1000 const result = wasm_exports.fn_error_set(decl_index); 1001 if (result === 0) return null; 1002 return result; 1003 } 1004 1005 function setInputString(s) { 1006 const jsArray = text_encoder.encode(s); 1007 const len = jsArray.length; 1008 const ptr = wasm_exports.set_input_string(len); 1009 const wasmArray = new Uint8Array(wasm_exports.memory.buffer, ptr, len); 1010 wasmArray.set(jsArray); 1011 } 1012 })(); 1013