refactor: use js for find

main
Xubai Wang 2022-02-21 01:12:49 +08:00
parent 5e93038023
commit 59707cda58
7 changed files with 69 additions and 42 deletions

View File

@ -65,6 +65,7 @@ def htmlOutput (result : AnalyzerResult) (root : String) : IO Unit := do
let config := { root := root, result := result, currentName := none, sourceLinker := ←sourceLinker}
let basePath := FilePath.mk "." / "build" / "doc"
let indexHtml := ReaderT.run index config
let findHtml := ReaderT.run find config
let notFoundHtml := ReaderT.run notFound config
FS.createDirAll basePath
FS.createDirAll (basePath / "find")
@ -72,12 +73,12 @@ def htmlOutput (result : AnalyzerResult) (root : String) : IO Unit := do
let mut declList := #[]
for (_, mod) in result.moduleInfo.toArray do
for decl in filterMapDocInfo mod.members do
let findHtml := ReaderT.run (findRedirectHtml decl.getName) config
let findDir := basePath / "find" / decl.getName.toString
FS.createDirAll findDir
FS.writeFile (findDir / "index.html") findHtml.toString
let obj := Json.mkObj [("name", decl.getName.toString), ("description", decl.getDocString.getD "")]
let name := decl.getName.toString
let description := decl.getDocString.getD ""
let link := Id.run <| ReaderT.run (declNameToLink decl.getName) config
let obj := Json.mkObj [("name", name), ("description", description), ("link", link)]
declList := declList.push obj
let json := Json.arr declList
FS.writeFile (basePath / "searchable_data.bmp") json.compress
@ -88,6 +89,11 @@ def htmlOutput (result : AnalyzerResult) (root : String) : IO Unit := do
FS.writeFile (basePath / "search.js") searchJs
FS.writeFile (basePath / "mathjax-config.js") mathjaxConfigJs
FS.writeFile (basePath / "site-root.js") s!"export const SITE_ROOT = \"{config.root}\";";
FS.writeFile (basePath / "find" / "index.html") findHtml.toString
FS.writeFile (basePath / "find" / "find.js") findJs
for (module, content) in result.moduleInfo.toArray do
let moduleHtml := ReaderT.run (moduleToHtml content) config
let path := moduleNameToFile basePath module

View File

@ -49,6 +49,7 @@ section Static
def styleCss : String := include_str "./static/style.css"
def navJs : String := include_str "./static/nav.js"
def searchJs : String := include_str "./static/search.js"
def findJs : String := include_str "./static/find/find.js"
def mathjaxConfigJs : String := include_str "./static/mathjax-config.js"
end Static

View File

@ -6,10 +6,16 @@ namespace Output
open scoped DocGen4.Jsx
open Lean
def findRedirectHtml (decl : Name) : HtmlM Html := do
let res ← getResult
let url ← declNameToLink decl
let contentString := s!"0;url={url}"
pure $ Html.element "meta" false #[("http-equiv", "refresh"), ("content", contentString)] #[]
def find : HtmlM Html := do
pure
<html lang="en">
<head>
<link rel="preload" href={s!"{←getRoot}searchable_data.bmp"}/>
<script type="module" async="true" src={s!"./find.js"}></script>
</head>
<body></body>
</html>
end Output
end DocGen4

View File

@ -26,13 +26,11 @@ def baseHtmlArray (title : String) (site : Array Html) : HtmlM Html := do
<link rel="shortcut icon" href={s!"{←getRoot}favicon.ico"}/>
<link rel="prefetch" href={s!"{←getRoot}searchable_data.bmp"}/>
<script type="module" src={s!"{←getRoot}site-root.js"}></script>
<script type="module" src={s!"{←getRoot}nav.js"}></script>
<script type="module" src={s!"{←getRoot}search.js"}></script>
<script defer="true" src={s!"{←getRoot}mathjax-config.js"}></script>
<script defer="true" src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script defer="true" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<script type="module" src={s!"{←getRoot}nav.js"}></script>
</head>

14
static/find/find.js Normal file
View File

@ -0,0 +1,14 @@
import { SITE_ROOT } from "../site-root.js";
import { declSearch } from "../search.js";
let splits = window.location.href.split("#");
if (splits.length < 2) {
window.location.replace(`${SITE_ROOT}/404.html`);
}
declSearch(splits[1]).then((results) => {
window.location.replace(results[0].link);
}).catch(() => {
window.location.replace(`${SITE_ROOT}404.html`);
});

View File

@ -1,5 +1,4 @@
import { SITE_ROOT } from "./site-root.js";
import { loadDecls, getMatches } from "./search.js";
import { declSearch } from "./search.js";
// Persistent expansion cookie for the file tree
// ---------------------------------------------
@ -109,24 +108,6 @@ if (tse != null) {
// Simple declaration search
// -------------------------
const declURL = new URL(`${SITE_ROOT}searchable_data.bmp`, window.location);
const getDecls = (() => {
let decls;
return () => {
if (!decls) decls = new Promise((resolve, reject) => {
const req = new XMLHttpRequest();
req.responseType = 'json';
req.addEventListener('load', () => resolve(loadDecls(req.response)));
req.addEventListener('error', () => reject());
req.open('GET', declURL);
req.send();
})
return decls;
}
})()
const declSearch = async (q) => getMatches(await getDecls(), q);
const srId = 'search_results';
document.getElementById('search_form')
.appendChild(document.createElement('div'))
@ -191,11 +172,11 @@ searchInput.addEventListener('input', async (ev) => {
const oldSR = document.getElementById('search_results');
const sr = oldSR.cloneNode(false);
for (const {decl} of result) {
for (const {decl, link} of result) {
const d = sr.appendChild(document.createElement('a'));
d.innerText = decl;
d.title = decl;
d.href = `${SITE_ROOT}find/${decl}`;
d.href = link;
}
sr.setAttribute('state', 'done');
oldSR.replaceWith(sr);
@ -222,10 +203,10 @@ if (howabout) {
declSearch(query).then((results) => {
howabout.innerText = 'How about one of these instead:';
const ul = howabout.appendChild(document.createElement('ul'));
for (const {decl} of results) {
for (const {decl, link} of results) {
const li = ul.appendChild(document.createElement('li'));
const a = li.appendChild(document.createElement('a'));
a.href = `${SITE_ROOT}find/${decl}`;
a.href = link;
a.appendChild(document.createElement('code')).innerText = decl;
}
});

View File

@ -1,3 +1,5 @@
import { SITE_ROOT } from "./site-root.js";
function isSep(c) {
return c === '.' || c === '_';
}
@ -23,14 +25,14 @@ function matchCaseSensitive(declName, lowerDeclName, pat) {
}
export function loadDecls(searchableDataCnt) {
return searchableDataCnt.map(({name, description}) => [name, name.toLowerCase(), description.toLowerCase()])
return searchableDataCnt.map(({name, description, link}) => [name, name.toLowerCase(), description.toLowerCase(), link]);
}
export function getMatches(decls, pat, maxResults = 30) {
const lowerPats = pat.toLowerCase().split(/\s/g);
const patNoSpaces = pat.replace(/\s/g, '');
const results = [];
for (const [decl, lowerDecl, lowerDoc] of decls) {
for (const [decl, lowerDecl, lowerDoc, link] of decls) {
let err = matchCaseSensitive(decl, lowerDecl, patNoSpaces);
// match all words as substrings of docstring
@ -39,8 +41,27 @@ export function getMatches(decls, pat, maxResults = 30) {
}
if (err !== undefined) {
results.push({decl, err});
results.push({decl, err, link});
}
}
return results.sort(({err: a}, {err: b}) => a - b).slice(0, maxResults);
}
}
const declURL = new URL(`${SITE_ROOT}searchable_data.bmp`, window.location);
export const getDecls = (() => {
let decls;
return () => {
if (!decls) decls = new Promise((resolve, reject) => {
const req = new XMLHttpRequest();
req.responseType = 'json';
req.addEventListener('load', () => resolve(loadDecls(req.response)));
req.addEventListener('error', () => reject());
req.open('GET', declURL);
req.send();
})
return decls;
}
})()
export const declSearch = async (q) => getMatches(await getDecls(), q);