autodoc: improved linking for declrefs

This commit is contained in:
Loris Cro 2023-07-14 19:11:55 +02:00
parent a187141056
commit 7dd1cf26f9

View File

@ -281,7 +281,8 @@ const NAV_MODES = {
// return null; // return null;
// } // }
function resolveValue(value) { function resolveValue(value, trackDecls) {
let seenDecls = [];
let i = 0; let i = 0;
while (true) { while (true) {
i += 1; i += 1;
@ -295,6 +296,7 @@ const NAV_MODES = {
} }
if ("declRef" in value.expr) { if ("declRef" in value.expr) {
seenDecls.push(value.expr.declRef);
value = getDecl(value.expr.declRef).value; value = getDecl(value.expr.declRef).value;
continue; continue;
} }
@ -307,6 +309,7 @@ const NAV_MODES = {
continue; continue;
} }
if (trackDecls) return { value, seenDecls };
return value; return value;
} }
} }
@ -1134,9 +1137,8 @@ Happy writing!
} }
case "declRef": { case "declRef": {
const name = getDecl(expr.declRef).name; const name = getDecl(expr.declRef).name;
const canonPath = getCanonDeclPath(expr.declRef); const link = declLinkOrSrcLink(expr.declRef);
if (canonPath) { if (link) {
const link = navLink(canonPath.modNames, canonPath.declNames);
yield { src: name, tag: Tag.identifier, link }; yield { src: name, tag: Tag.identifier, link };
} else { } else {
yield { src: name, tag: Tag.identifier }; yield { src: name, tag: Tag.identifier };
@ -2028,7 +2030,6 @@ Happy writing!
let linkFnNameDecl = opts.linkFnNameDecl; let linkFnNameDecl = opts.linkFnNameDecl;
opts.fnDecl = null; opts.fnDecl = null;
opts.linkFnNameDecl = null; opts.linkFnNameDecl = null;
let payloadHtml = "";
if (opts.addParensIfFnSignature && fnObj.src == 0) { if (opts.addParensIfFnSignature && fnObj.src == 0) {
yield Tok.l_paren; yield Tok.l_paren;
} }
@ -2108,6 +2109,7 @@ Happy writing!
} }
} }
// TODO: most of this seems redundant
if (isVarArgs && i === fnObj.params.length - 1) { if (isVarArgs && i === fnObj.params.length - 1) {
yield Tok.period; yield Tok.period;
yield Tok.period; yield Tok.period;
@ -3234,7 +3236,7 @@ Happy writing!
} }
function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) { 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 declNames = item.declNames.concat([decl.name]);
let declIndexes = item.declIndexes.concat([declIndex]); let declIndexes = item.declIndexes.concat([declIndex]);
@ -3245,6 +3247,15 @@ Happy writing!
declIndexes: declIndexes, declIndexes: declIndexes,
}; };
for (let sd of seenDecls) {
if (list[sd] != null) continue;
list[sd] = {
modNames: modNames,
declNames: declNames,
declIndexes: declIndexes,
};
}
// add to search index // add to search index
{ {
declSearchIndex.add(decl.name, { declIndex }); 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) { function getCanonDeclPath(index) {
if (canonDeclPaths == null) { if (canonDeclPaths == null) {
canonDeclPaths = computeCanonDeclPaths(); canonDeclPaths = computeCanonDeclPaths();
} }
//let cd = (canonDeclPaths);
return canonDeclPaths[index]; return canonDeclPaths[index];
} }
function getCanonTypeDecl(index) { function getCanonTypeDecl(index) {
@ -3395,6 +3454,8 @@ Happy writing!
} }
function detectDeclPath(text, context) { function detectDeclPath(text, context) {
let result = ""; let result = "";
let separator = ":"; let separator = ":";
@ -3888,109 +3949,7 @@ Happy writing!
domSectSearchResults.classList.remove("hidden"); 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() { function renderSearchCursor() {
for (let i = 0; i < domListSearchResults.children.length; i += 1) { for (let i = 0; i < domListSearchResults.children.length; i += 1) {