Commit 7dd1cf26f9

Loris Cro <kappaloris@gmail.com>
2023-07-14 19:11:55
autodoc: improved linking for declrefs
1 parent a187141
Changed files (1)
lib
docs
lib/docs/main.js
@@ -281,7 +281,8 @@ const NAV_MODES = {
   //     return null;
   // }
 
-  function resolveValue(value) {
+  function resolveValue(value, trackDecls) {
+    let seenDecls = [];
     let i = 0;
     while (true) {
       i += 1;
@@ -295,6 +296,7 @@ const NAV_MODES = {
       }
 
       if ("declRef" in value.expr) {
+        seenDecls.push(value.expr.declRef);
         value = getDecl(value.expr.declRef).value;
         continue;
       }
@@ -307,6 +309,7 @@ const NAV_MODES = {
         continue;
       }
 
+      if (trackDecls) return { value, seenDecls };
       return value;
     }
   }
@@ -1134,9 +1137,8 @@ Happy writing!
       }
       case "declRef": {
         const name = getDecl(expr.declRef).name;
-        const canonPath = getCanonDeclPath(expr.declRef);
-        if (canonPath) {
-          const link = navLink(canonPath.modNames, canonPath.declNames);
+        const link = declLinkOrSrcLink(expr.declRef);
+        if (link) {
           yield { src: name, tag: Tag.identifier, link };
         } else {
           yield { src: name, tag: Tag.identifier };
@@ -2028,7 +2030,6 @@ Happy writing!
             let linkFnNameDecl = opts.linkFnNameDecl;
             opts.fnDecl = null;
             opts.linkFnNameDecl = null;
-            let payloadHtml = "";
             if (opts.addParensIfFnSignature && fnObj.src == 0) {
               yield Tok.l_paren;
             }
@@ -2108,6 +2109,7 @@ Happy writing!
                   }
                 }
 
+                // TODO: most of this seems redundant
                 if (isVarArgs && i === fnObj.params.length - 1) {
                   yield Tok.period;
                   yield Tok.period;
@@ -3234,7 +3236,7 @@ Happy writing!
   }
 
   function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
-    let declVal = resolveValue(decl.value);
+    let {value: declVal, seenDecls} = resolveValue(decl.value, true);
     let declNames = item.declNames.concat([decl.name]);
     let declIndexes = item.declIndexes.concat([declIndex]);
 
@@ -3245,6 +3247,15 @@ Happy writing!
       declIndexes: declIndexes,
     };
 
+    for (let sd of seenDecls) {
+      if (list[sd] != null) continue;
+      list[sd] = {
+        modNames: modNames,
+        declNames: declNames,
+        declIndexes: declIndexes,
+      };
+    }
+
     // add to search index
     {
       declSearchIndex.add(decl.name, { declIndex });
@@ -3282,12 +3293,60 @@ Happy writing!
     }
   }
 
+  function declLinkOrSrcLink(index) {
+    
+    let match = getCanonDeclPath(index);
+    if (match) return navLink(match.modNames, match.declNames);
+
+    // could not find a precomputed decl path
+    const decl = getDecl(index);
+    
+    // try to find a public decl by scanning declRefs and declPaths
+    let value = decl.value;    
+    let i = 0;
+    while (true) {
+      i += 1;
+      if (i >= 10000) {
+        throw "getCanonDeclPath quota exceeded"
+      }
+
+      if ("refPath" in value.expr) {
+        value = { expr: value.expr.refPath[value.expr.refPath.length - 1] };
+        continue;
+      }
+
+      if ("declRef" in value.expr) {
+        let cp = canonDeclPaths[value.expr.declRef];
+        if (cp) return navLink(cp.modNames, cp.declNames);
+        
+        value = getDecl(value.expr.declRef).value;
+        continue;
+      }
+
+      if ("as" in value.expr) {
+        value = {
+          typeRef: zigAnalysis.exprs[value.expr.as.typeRefArg],
+          expr: zigAnalysis.exprs[value.expr.as.exprArg],
+        };
+        continue;
+      }
+
+      // if we got here it means that we failed 
+      // produce a link to source code instead
+      return sourceFileLink(decl);
+
+    }
+    
+  }
+
   function getCanonDeclPath(index) {
     if (canonDeclPaths == null) {
       canonDeclPaths = computeCanonDeclPaths();
     }
-    //let cd = (canonDeclPaths);
+    
     return canonDeclPaths[index];
+
+      
   }
 
   function getCanonTypeDecl(index) {
@@ -3395,6 +3454,8 @@ Happy writing!
 
   }
 
+
+
   function detectDeclPath(text, context) {
     let result = "";
     let separator = ":";
@@ -3888,109 +3949,7 @@ Happy writing!
     domSectSearchResults.classList.remove("hidden");
   }
 
-  function renderSearchAPIOld() {
-    let matchedItems = [];
-    let ignoreCase = curNavSearch.toLowerCase() === curNavSearch;
-    let terms = getSearchTerms();
-
-    decl_loop: for (
-      let declIndex = 0;
-      declIndex < zigAnalysis.decls.length;
-      declIndex += 1
-    ) {
-      let canonPath = getCanonDeclPath(declIndex);
-      if (canonPath == null) continue;
-
-      let decl = getDecl(declIndex);
-      let lastModName = canonPath.modNames[canonPath.modNames.length - 1];
-      let fullPathSearchText =
-        lastModName + "." + canonPath.declNames.join(".");
-      let astNode = getAstNode(decl.src);
-      let fileAndDocs = ""; //zigAnalysis.files[astNode.file];
-      // TODO: understand what this piece of code is trying to achieve
-      //       also right now `files` are expressed as a hashmap.
-      if (astNode.docs != null) {
-        fileAndDocs += "\n" + astNode.docs;
-      }
-      let fullPathSearchTextLower = fullPathSearchText;
-      if (ignoreCase) {
-        fullPathSearchTextLower = fullPathSearchTextLower.toLowerCase();
-        fileAndDocs = fileAndDocs.toLowerCase();
-      }
-
-      let points = 0;
-      for (let termIndex = 0; termIndex < terms.length; termIndex += 1) {
-        let term = terms[termIndex];
-
-        // exact, case sensitive match of full decl path
-        if (fullPathSearchText === term) {
-          points += 4;
-          continue;
-        }
-        // exact, case sensitive match of just decl name
-        if (decl.name == term) {
-          points += 3;
-          continue;
-        }
-        // substring, case insensitive match of full decl path
-        if (fullPathSearchTextLower.indexOf(term) >= 0) {
-          points += 2;
-          continue;
-        }
-        if (fileAndDocs.indexOf(term) >= 0) {
-          points += 1;
-          continue;
-        }
-
-        continue decl_loop;
-      }
-
-      matchedItems.push({
-        decl: decl,
-        path: canonPath,
-        points: points,
-      });
-    }
-
-    if (matchedItems.length !== 0) {
-      matchedItems.sort(function(a, b) {
-        let cmp = operatorCompare(b.points, a.points);
-        if (cmp != 0) return cmp;
-        return operatorCompare(a.decl.name, b.decl.name);
-      });
-
-      let searchTrimmed = false;
-      const searchTrimResultsMaxItems = 60;
-      if (searchTrimResults && matchedItems.length > searchTrimResultsMaxItems) {
-        matchedItems = matchedItems.slice(0, searchTrimResultsMaxItems);
-        searchTrimmed = true;
-      }
-
-      // Build up the list of search results
-      let matchedItemsHTML = "";
-
-      for (let i = 0; i < matchedItems.length; i += 1) {
-        const match = matchedItems[i];
-        const lastModName = match.path.modNames[match.path.modNames.length - 1];
-
-        const text = lastModName + "." + match.path.declNames.join(".");
-        const href = navLink(match.path.modNames, match.path.declNames);
-
-        matchedItemsHTML += "<li><a href=\"" + href + "\">" + text + "</a></li>";
-      }
-
-      // Replace the search results using our newly constructed HTML string
-      domListSearchResults.innerHTML = matchedItemsHTML;
-      if (searchTrimmed) {
-        domSectSearchAllResultsLink.classList.remove("hidden");
-      }
-      renderSearchCursor();
-
-      domSectSearchResults.classList.remove("hidden");
-    } else {
-      domSectSearchNoResults.classList.remove("hidden");
-    }
-  }
+  
 
   function renderSearchCursor() {
     for (let i = 0; i < domListSearchResults.children.length; i += 1) {