master
   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