zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

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