Add filters for search results based on kind.

This allows you to search defs, theorems, etc independently.
main
Jeremy Salwen 2023-01-31 14:31:27 -05:00 committed by Henrik Böving
parent 1c44e861be
commit 1cb84f6d74
4 changed files with 58 additions and 13 deletions

View File

@ -15,7 +15,28 @@ def search : BaseHtmlM Html := do templateExtends (baseHtml "Search") <|
pure <| pure <|
<main> <main>
<h1> Search Results </h1> <h1> Search Results </h1>
<label for="search_page_query">Query:</label><input id="search_page_query" /> <label for="search_page_query">Query:</label>
<input id="search_page_query" />
<div id="kinds">
Allowed Kinds:
<input type="checkbox" id="def_checkbox" class="kind_checkbox" value="def" checked="checked" />
<label for="def_checkbox">def</label>
<input type="checkbox" id="theorem_checkbox" class="kind_checkbox" value="theorem" checked="checked" />
<label for="theorem_checkbox">theorem</label>
<input type="checkbox" id="inductive_checkbox" class="kind_checkbox" value="inductive" checked="checked" />
<label for="inductive_checkbox">inductive</label>
<input type="checkbox" id="structure_checkbox" class="kind_checkbox" value="structure" checked="checked" />
<label for="structure_checkbox">structure</label>
<input type="checkbox" id="class_checkbox" class="kind_checkbox" value="class" checked="checked" />
<label for="class_checkbox">class</label>
<input type="checkbox" id="instance_checkbox" class="kind_checkbox" value="instance" checked="checked" />
<label for="instance_checkbox">instance</label>
<input type="checkbox" id="axiom_checkbox" class="axiom_checkbox" value="axiom" checked="checked" />
<label for="axiom_checkbox">axiom</label>
<input type="checkbox" id="opaque_checkbox" class="kind_checkbox" value="opaque" checked="checked" />
<label for="opaque_checkbox">opaque</label>
</div>
<script> <script>
document.getElementById("search_page_query").value = new URL(window.location.href).searchParams.get("q") document.getElementById("search_page_query").value = new URL(window.location.href).searchParams.get("q")
</script> </script>

View File

@ -9,6 +9,7 @@ open Lean
structure JsonDeclaration where structure JsonDeclaration where
name : String name : String
kind : String
doc : String doc : String
docLink : String docLink : String
sourceLink : String sourceLink : String
@ -76,10 +77,11 @@ def JsonIndex.addModule (index : JsonIndex) (module : JsonModule) : BaseHtmlM Js
def DocInfo.toJson (module : Name) (info : Process.DocInfo) : HtmlM JsonDeclaration := do def DocInfo.toJson (module : Name) (info : Process.DocInfo) : HtmlM JsonDeclaration := do
let name := info.getName.toString let name := info.getName.toString
let kind := info.getKind
let doc := info.getDocString.getD "" let doc := info.getDocString.getD ""
let docLink ← declNameToLink info.getName let docLink ← declNameToLink info.getName
let sourceLink ← getSourceUrl module info.getDeclarationRange let sourceLink ← getSourceUrl module info.getDeclarationRange
return { name, doc, docLink, sourceLink } return { name, kind, doc, docLink, sourceLink }
def Process.Module.toJson (module : Process.Module) : HtmlM Json := do def Process.Module.toJson (module : Process.Module) : HtmlM Json := do
let mut jsonDecls := [] let mut jsonDecls := []

View File

@ -67,7 +67,7 @@ export class DeclarationDataCenter {
* Search for a declaration. * Search for a declaration.
* @returns {Array<any>} * @returns {Array<any>}
*/ */
search(pattern, strict = true, maxResults=undefined) { search(pattern, strict = true, allowedKinds=undefined, maxResults=undefined) {
if (!pattern) { if (!pattern) {
return []; return [];
} }
@ -75,7 +75,7 @@ export class DeclarationDataCenter {
let decl = this.declarationData.declarations[pattern]; let decl = this.declarationData.declarations[pattern];
return decl ? [decl] : []; return decl ? [decl] : [];
} else { } else {
return getMatches(this.declarationData.declarations, pattern, maxResults); return getMatches(this.declarationData.declarations, pattern, allowedKinds, maxResults);
} }
} }
@ -159,16 +159,23 @@ function matchCaseSensitive(declName, lowerDeclName, pattern) {
} }
} }
function getMatches(declarations, pattern, maxResults = undefined) { function getMatches(declarations, pattern, allowedKinds = undefined, maxResults = undefined) {
const lowerPats = pattern.toLowerCase().split(/\s/g); const lowerPats = pattern.toLowerCase().split(/\s/g);
const patNoSpaces = pattern.replace(/\s/g, ""); const patNoSpaces = pattern.replace(/\s/g, "");
const results = []; const results = [];
for (const [_, { for (const [_, {
name, name,
kind,
doc, doc,
docLink, docLink,
sourceLink, sourceLink,
}] of Object.entries(declarations)) { }] of Object.entries(declarations)) {
// Apply "kind" filter
if (allowedKinds !== undefined) {
if (!allowedKinds.has(kind)) {
continue;
}
}
const lowerName = name.toLowerCase(); const lowerName = name.toLowerCase();
const lowerDoc = doc.toLowerCase(); const lowerDoc = doc.toLowerCase();
let err = matchCaseSensitive(name, lowerName, patNoSpaces); let err = matchCaseSensitive(name, lowerName, patNoSpaces);
@ -183,6 +190,7 @@ function getMatches(declarations, pattern, maxResults = undefined) {
if (err !== undefined) { if (err !== undefined) {
results.push({ results.push({
name, name,
kind,
doc, doc,
err, err,
lowerName, lowerName,

View File

@ -80,7 +80,7 @@ function removeAllChildren(node) {
/** /**
* Handle user input and perform search. * Handle user input and perform search.
*/ */
function handleSearch(dataCenter, err, ev, sr, maxResults, includedoc=false) { function handleSearch(dataCenter, err, ev, sr, maxResults, autocomplete) {
const text = ev.target.value; const text = ev.target.value;
// If no input clear all. // If no input clear all.
@ -94,14 +94,25 @@ function handleSearch(dataCenter, err, ev, sr, maxResults, includedoc=false) {
sr.setAttribute("state", "loading"); sr.setAttribute("state", "loading");
if (dataCenter) { if (dataCenter) {
const result = dataCenter.search(text, false, maxResults); var allowedKinds;
if (!autocomplete) {
allowedKinds = new Set();
document.querySelectorAll(".kind_checkbox").forEach((checkbox) =>
{
if (checkbox.checked) {
allowedKinds.add(checkbox.value);
}
}
);
}
const result = dataCenter.search(text, false, allowedKinds, maxResults);
// in case user has updated the input. // in case user has updated the input.
if (ev.target.value != text) return; if (ev.target.value != text) return;
// update autocomplete results // update autocomplete results
removeAllChildren(sr); removeAllChildren(sr);
for (const { name, doc, docLink } of result) { for (const { name, kind, doc, docLink } of result) {
const row = sr.appendChild(document.createElement("div")); const row = sr.appendChild(document.createElement("div"));
row.classList.add("search_result") row.classList.add("search_result")
const linkdiv = row.appendChild(document.createElement("div")) const linkdiv = row.appendChild(document.createElement("div"))
@ -110,7 +121,7 @@ function handleSearch(dataCenter, err, ev, sr, maxResults, includedoc=false) {
link.innerText = name; link.innerText = name;
link.title = name; link.title = name;
link.href = SITE_ROOT + docLink; link.href = SITE_ROOT + docLink;
if (includedoc) { if (!autocomplete) {
const doctext = row.appendChild(document.createElement("div")); const doctext = row.appendChild(document.createElement("div"));
doctext.innerText = doc doctext.innerText = doc
doctext.classList.add("result_doc") doctext.classList.add("result_doc")
@ -129,15 +140,18 @@ function handleSearch(dataCenter, err, ev, sr, maxResults, includedoc=false) {
DeclarationDataCenter.init() DeclarationDataCenter.init()
.then((dataCenter) => { .then((dataCenter) => {
// Search autocompletion. // Search autocompletion.
SEARCH_INPUT.addEventListener("input", ev => handleSearch(dataCenter, null, ev, ac_results, AC_MAX_RESULTS)); SEARCH_INPUT.addEventListener("input", ev => handleSearch(dataCenter, null, ev, ac_results, AC_MAX_RESULTS, true));
if(SEARCH_PAGE_INPUT) { if(SEARCH_PAGE_INPUT) {
SEARCH_PAGE_INPUT.addEventListener("input", ev => handleSearch(dataCenter, null, ev, SEARCH_RESULTS, SEARCH_PAGE_MAX_RESULTS, true)) SEARCH_PAGE_INPUT.addEventListener("input", ev => handleSearch(dataCenter, null, ev, SEARCH_RESULTS, SEARCH_PAGE_MAX_RESULTS, false))
document.querySelectorAll(".kind_checkbox").forEach((checkbox) =>
checkbox.addEventListener("input", ev => SEARCH_PAGE_INPUT.dispatchEvent(new Event("input")))
);
SEARCH_PAGE_INPUT.dispatchEvent(new Event("input")) SEARCH_PAGE_INPUT.dispatchEvent(new Event("input"))
} }
}) })
.catch(e => { .catch(e => {
SEARCH_INPUT.addEventListener("input", ev => handleSearch(null, e, ev, ac_results, AC_MAX_RESULTS)); SEARCH_INPUT.addEventListener("input", ev => handleSearch(null, e, ev, ac_results, AC_MAX_RESULTS,true ));
if(SEARCH_PAGE_INPUT) { if(SEARCH_PAGE_INPUT) {
SEARCH_PAGE_INPUT.addEventListener("input", ev => handleSearch(null, e, ev, SEARCH_RESULTS, SEARCH_PAGE_MAX_RESULTS, true)); SEARCH_PAGE_INPUT.addEventListener("input", ev => handleSearch(null, e, ev, SEARCH_RESULTS, SEARCH_PAGE_MAX_RESULTS, false));
} }
}); });