Commit 4a97558ae8

Andrew Kelley <andrew@ziglang.org>
2019-10-07 23:46:22
generated docs: navigable search results
1 parent d46234e
Changed files (2)
lib
std
special
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;
+        }
       }
     </style>
   </head>
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();
+        }
+    }
+
+    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;
         }
-        ev.stopPropagation();
-        startAsyncSearch();
+        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, '<li></li>');
+        if (matchedItems.length !== 0) {
+            resizeDomList(domListSearchResults, matchedItems.length, '<li><a href="#"></a></li>');
 
-            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");
+            }
+        }
+    }
 })();