From 4a97558ae86f802d2bb2d9e7517fdd5d9101a2c6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 7 Oct 2019 17:46:22 -0400 Subject: [PATCH] generated docs: navigable search results --- lib/std/special/docs/index.html | 16 ++++ lib/std/special/docs/main.js | 142 +++++++++++++++++++++++++++++--- 2 files changed, 146 insertions(+), 12 deletions(-) diff --git a/lib/std/special/docs/index.html b/lib/std/special/docs/index.html index 0fb3673bbb..020e90f9a8 100644 --- a/lib/std/special/docs/index.html +++ b/lib/std/special/docs/index.html @@ -139,6 +139,10 @@ cursor: default; } + #listSearchResults li.selected { + background-color: #93e196; + } + @media (prefers-color-scheme: dark) { body{ background-color: #111; @@ -150,6 +154,12 @@ pre{ background-color:#2A2A2A; } + #listNav li a:hover { + background-color: #000; + } + #listNav li a.active { + background-color: #4CAF50; + } #listPkgs { background-color: #333; } @@ -160,6 +170,12 @@ background-color: #555; color: #fff; } + #listSearchResults li.selected { + background-color: #000; + } + #listSearchResults li.selected a { + color: #fff; + } } diff --git a/lib/std/special/docs/main.js b/lib/std/special/docs/main.js index 1d062dc02a..094c485c8c 100644 --- a/lib/std/special/docs/main.js +++ b/lib/std/special/docs/main.js @@ -31,6 +31,7 @@ // for each package, is an array with packages to get to this one var canonPkgPaths = computeCanonicalPackagePaths(); + var canonDeclPaths = null; // lazy; use getCanonDeclPath var curNav = { // each element is a package name, e.g. @import("a") then within there @import("b") @@ -45,6 +46,7 @@ declObjs: [], }; var curNavSearch = ""; + var curSearchIndex = -1; var rootIsStd = detectRootIsStd(); var typeTypeId = findTypeTypeId(); @@ -78,6 +80,7 @@ domSectSearchNoResults.classList.add("hidden"); domSectInfo.classList.add("hidden"); domHdrName.classList.add("hidden"); + domSectNav.classList.add("hidden"); renderTitle(); renderInfo(); @@ -413,7 +416,7 @@ pkg: rootPkg, }]; while (stack.length !== 0) { - var item = stack.pop(); + var item = stack.shift(); for (var key in item.pkg.table) { var childPkgIndex = item.pkg.table[key]; if (list[childPkgIndex] != null) continue; @@ -430,6 +433,51 @@ return list; } + function computeCanonDeclPaths() { + var list = new Array(zigAnalysis.decls.length); + + for (var pkgI = 0; pkgI < zigAnalysis.packages.length; pkgI += 1) { + var pkg = zigAnalysis.packages[pkgI]; + var pkgNames = canonPkgPaths[pkgI]; + var stack = [{ + declNames: [], + type: zigAnalysis.types[pkg.main], + }]; + while (stack.length !== 0) { + var item = stack.shift(); + + if (item.type.pubDecls != null) { + for (var declI = 0; declI < item.type.pubDecls.length; declI += 1) { + var mainDeclIndex = item.type.pubDecls[declI]; + if (list[mainDeclIndex] != null) continue; + + var decl = zigAnalysis.decls[mainDeclIndex]; + var declNames = item.declNames.concat([decl.name]); + list[mainDeclIndex] = { + pkgNames: pkgNames, + declNames: declNames, + }; + var containerType = getDeclContainerType(decl); + if (containerType != null) { + stack.push({ + declNames: declNames, + type: containerType, + }); + } + } + } + } + } + return list; + } + + function getCanonDeclPath(index) { + if (canonDeclPaths == null) { + canonDeclPaths = computeCanonDeclPaths(); + } + return canonDeclPaths[index]; + } + function markdown(mdText) { return mdText.replace(/[&"<>]/g, function (m) { return escapeHtmlReplacements[m]; @@ -438,14 +486,63 @@ function onSearchKeyDown(ev) { switch (ev.which) { + case 13: + var liDom = null; + if (domListSearchResults.children.length === 1) { + liDom = domListSearchResults.children[0]; + } else { + liDom = domListSearchResults.children[curSearchIndex]; + } + if (liDom != null) { + var aDom = liDom.children[0]; + location.href = aDom.getAttribute("href"); + curSearchIndex = -1; + ev.preventDefault(); + ev.stopPropagation(); + return; + } case 27: domSearch.value = ""; domSearch.blur(); + curSearchIndex = -1; ev.preventDefault(); - break; + ev.stopPropagation(); + startSearch(); + return; + case 38: + moveSearchCursor(-1); + ev.preventDefault(); + ev.stopPropagation(); + return; + case 40: + moveSearchCursor(1); + ev.preventDefault(); + ev.stopPropagation(); + return; + default: + curSearchIndex = -1; + ev.stopPropagation(); + startAsyncSearch(); } - ev.stopPropagation(); - startAsyncSearch(); + } + + function moveSearchCursor(dir) { + if (curSearchIndex < 0 || curSearchIndex >= domListSearchResults.children.length) { + if (dir > 0) { + curSearchIndex = -1 + dir; + } else if (dir < 0) { + curSearchIndex = domListSearchResults.children.length + dir; + } + } else { + curSearchIndex += dir; + } + if (curSearchIndex < 0) { + curSearchIndex = 0; + } + if (curSearchIndex >= domListSearchResults.children.length) { + curSearchIndex = domListSearchResults.children.length - 1; + } + renderSearchCursor(); } function onWindowKeyDown(ev) { @@ -496,16 +593,20 @@ } } function renderSearch() { - var matchedDecls = []; + var matchedItems = []; var terms = curNavSearch.split(/[ \r\n\t]+/); + decl_loop: for (var declIndex = 0; declIndex < zigAnalysis.decls.length; declIndex += 1) { + var canonPath = getCanonDeclPath(declIndex); + if (canonPath == null) continue; + var decl = zigAnalysis.decls[declIndex]; for (var termIndex = 0; termIndex < terms.length; termIndex += 1) { var term = terms[termIndex]; if (decl.name.indexOf(term) >= 0) { continue; } - var astNode = zigAnalysis.astNodes[decl.src] + var astNode = zigAnalysis.astNodes[decl.src]; if (astNode.docs != null && astNode.docs.indexOf(term) >= 0) { continue; } @@ -517,21 +618,38 @@ continue decl_loop; } - matchedDecls.push(decl); + matchedItems.push({ + decl: decl, + path: canonPath, + }); } - if (matchedDecls.length !== 0) { - resizeDomList(domListSearchResults, matchedDecls.length, '
  • '); + if (matchedItems.length !== 0) { + resizeDomList(domListSearchResults, matchedItems.length, '
  • '); - for (var i = 0; i < matchedDecls.length; i += 1) { + for (var i = 0; i < matchedItems.length; i += 1) { var liDom = domListSearchResults.children[i]; - var decl = matchedDecls[i]; - liDom.textContent = decl.name; + var aDom = liDom.children[0]; + var match = matchedItems[i]; + aDom.textContent = match.path.declNames.join('.'); + aDom.setAttribute('href', navLink(match.path.pkgNames, match.path.declNames)); } + renderSearchCursor(); domSectSearchResults.classList.remove("hidden"); } else { domSectSearchNoResults.classList.remove("hidden"); } } + + function renderSearchCursor() { + for (var i = 0; i < domListSearchResults.children.length; i += 1) { + var liDom = domListSearchResults.children[i]; + if (curSearchIndex === i) { + liDom.classList.add("selected"); + } else { + liDom.classList.remove("selected"); + } + } + } })();