commit
7d43c83178
|
@ -9,6 +9,7 @@ import DocGen4.Output.Base
|
||||||
import DocGen4.Output.Index
|
import DocGen4.Output.Index
|
||||||
import DocGen4.Output.Module
|
import DocGen4.Output.Module
|
||||||
import DocGen4.Output.NotFound
|
import DocGen4.Output.NotFound
|
||||||
|
import DocGen4.Output.Find
|
||||||
|
|
||||||
namespace DocGen4
|
namespace DocGen4
|
||||||
|
|
||||||
|
@ -66,10 +67,25 @@ def htmlOutput (result : AnalyzerResult) (root : String) : IO Unit := do
|
||||||
let indexHtml := ReaderT.run index config
|
let indexHtml := ReaderT.run index config
|
||||||
let notFoundHtml := ReaderT.run notFound config
|
let notFoundHtml := ReaderT.run notFound config
|
||||||
FS.createDirAll basePath
|
FS.createDirAll basePath
|
||||||
|
FS.createDirAll (basePath / "find")
|
||||||
|
|
||||||
|
let mut declList := #[]
|
||||||
|
for (_, mod) in result.moduleInfo.toArray do
|
||||||
|
for decl in 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 "")]
|
||||||
|
declList := declList.push obj
|
||||||
|
let json := Json.arr declList
|
||||||
|
|
||||||
|
FS.writeFile (basePath / "searchable_data.bmp") json.compress
|
||||||
FS.writeFile (basePath / "index.html") indexHtml.toString
|
FS.writeFile (basePath / "index.html") indexHtml.toString
|
||||||
FS.writeFile (basePath / "style.css") styleCss
|
FS.writeFile (basePath / "style.css") styleCss
|
||||||
FS.writeFile (basePath / "404.html") notFoundHtml.toString
|
FS.writeFile (basePath / "404.html") notFoundHtml.toString
|
||||||
FS.writeFile (basePath / "nav.js") navJs
|
FS.writeFile (basePath / "nav.js") navJs
|
||||||
|
FS.writeFile (basePath / "search.js") searchJs
|
||||||
for (module, content) in result.moduleInfo.toArray do
|
for (module, content) in result.moduleInfo.toArray do
|
||||||
let moduleHtml := ReaderT.run (moduleToHtml content) config
|
let moduleHtml := ReaderT.run (moduleToHtml content) config
|
||||||
let path := moduleNameToFile basePath module
|
let path := moduleNameToFile basePath module
|
||||||
|
|
|
@ -48,6 +48,7 @@ def moduleNameToDirectory (basePath : FilePath) (n : Name) : FilePath :=
|
||||||
section Static
|
section Static
|
||||||
def styleCss : String := include_str "./static/style.css"
|
def styleCss : String := include_str "./static/style.css"
|
||||||
def navJs : String := include_str "./static/nav.js"
|
def navJs : String := include_str "./static/nav.js"
|
||||||
|
def searchJs : String := include_str "./static/search.js"
|
||||||
end Static
|
end Static
|
||||||
|
|
||||||
def declNameToLink (name : Name) : HtmlM String := do
|
def declNameToLink (name : Name) : HtmlM String := do
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
import DocGen4.Output.Template
|
||||||
|
|
||||||
|
namespace DocGen4
|
||||||
|
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)] #[]
|
||||||
|
end Output
|
||||||
|
end DocGen4
|
|
@ -49,6 +49,7 @@ def baseHtmlArray (title : String) (site : Array Html) : HtmlM Html := do
|
||||||
|
|
||||||
-- TODO Add more js stuff
|
-- TODO Add more js stuff
|
||||||
<script src={s!"{←getRoot}nav.js"}></script>
|
<script src={s!"{←getRoot}nav.js"}></script>
|
||||||
|
<script src={s!"{←getRoot}search.js"}></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
@ -206,7 +206,9 @@ def valueToEq (v : DefinitionVal) : MetaM Expr := withLCtx {} {} do
|
||||||
def computable? (defn : Name) : MetaM Bool := do
|
def computable? (defn : Name) : MetaM Bool := do
|
||||||
let cstage2Name := defn.append `_cstage2
|
let cstage2Name := defn.append `_cstage2
|
||||||
let env ← getEnv
|
let env ← getEnv
|
||||||
pure $ env.find? cstage2Name |>.isSome
|
let extern? := externAttr.getParam env defn |>.isSome
|
||||||
|
let cstage2? := env.find? cstage2Name |>.isSome
|
||||||
|
pure $ extern? ∨ cstage2?
|
||||||
|
|
||||||
def DefinitionInfo.ofDefinitionVal (v : DefinitionVal) : MetaM DefinitionInfo := do
|
def DefinitionInfo.ofDefinitionVal (v : DefinitionVal) : MetaM DefinitionInfo := do
|
||||||
let info ← Info.ofConstantVal v.toConstantVal
|
let info ← Info.ofConstantVal v.toConstantVal
|
||||||
|
@ -444,6 +446,17 @@ def getAttrs : DocInfo → Array String
|
||||||
| classInfo i => i.attrs
|
| classInfo i => i.attrs
|
||||||
| classInductiveInfo i => i.attrs
|
| classInductiveInfo i => i.attrs
|
||||||
|
|
||||||
|
def getDocString : DocInfo → Option String
|
||||||
|
| axiomInfo i => i.doc
|
||||||
|
| theoremInfo i => i.doc
|
||||||
|
| opaqueInfo i => i.doc
|
||||||
|
| definitionInfo i => i.doc
|
||||||
|
| instanceInfo i => i.doc
|
||||||
|
| inductiveInfo i => i.doc
|
||||||
|
| structureInfo i => i.doc
|
||||||
|
| classInfo i => i.doc
|
||||||
|
| classInductiveInfo i => i.doc
|
||||||
|
|
||||||
end DocInfo
|
end DocInfo
|
||||||
|
|
||||||
structure AnalyzerResult where
|
structure AnalyzerResult where
|
||||||
|
|
|
@ -106,14 +106,23 @@ if (tse != null) {
|
||||||
// Simple declaration search
|
// Simple declaration search
|
||||||
// -------------------------
|
// -------------------------
|
||||||
|
|
||||||
const searchWorkerURL = new URL(`${siteRoot}searchWorker.js`, window.location);
|
const declURL = new URL(`${siteRoot}searchable_data.bmp`, window.location);
|
||||||
const declSearch = (q) => new Promise((resolve, reject) => {
|
const getDecls = (() => {
|
||||||
const worker = new SharedWorker(searchWorkerURL);
|
let decls;
|
||||||
worker.port.start();
|
return () => {
|
||||||
worker.port.onmessage = ({data}) => resolve(data);
|
if (!decls) decls = new Promise((resolve, reject) => {
|
||||||
worker.port.onmessageerror = (e) => reject(e);
|
const req = new XMLHttpRequest();
|
||||||
worker.port.postMessage({q});
|
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';
|
const srId = 'search_results';
|
||||||
document.getElementById('search_form')
|
document.getElementById('search_form')
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
function isSep(c) {
|
||||||
|
return c === '.' || c === '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchCaseSensitive(declName, lowerDeclName, pat) {
|
||||||
|
let i = 0, j = 0, err = 0, lastMatch = 0
|
||||||
|
while (i < declName.length && j < pat.length) {
|
||||||
|
if (pat[j] === declName[i] || pat[j] === lowerDeclName[i]) {
|
||||||
|
err += (isSep(pat[j]) ? 0.125 : 1) * (i - lastMatch);
|
||||||
|
if (pat[j] !== declName[i]) err += 0.5;
|
||||||
|
lastMatch = i + 1;
|
||||||
|
j++;
|
||||||
|
} else if (isSep(declName[i])) {
|
||||||
|
err += 0.125 * (i + 1 - lastMatch);
|
||||||
|
lastMatch = i + 1;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
err += 0.125 * (declName.length - lastMatch);
|
||||||
|
if (j === pat.length) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadDecls(searchableDataCnt) {
|
||||||
|
return searchableDataCnt.map(({name, description}) => [name, name.toLowerCase(), description.toLowerCase()])
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
let err = matchCaseSensitive(decl, lowerDecl, patNoSpaces);
|
||||||
|
|
||||||
|
// match all words as substrings of docstring
|
||||||
|
if (!(err < 3) && pat.length > 3 && lowerPats.every(l => lowerDoc.indexOf(l) != -1)) {
|
||||||
|
err = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err !== undefined) {
|
||||||
|
results.push({decl, err});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results.sort(({err: a}, {err: b}) => a - b).slice(0, maxResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof process === 'object') { // NodeJS
|
||||||
|
const data = loadDecls(JSON.parse(require('fs').readFileSync('searchable_data.bmp').toString()));
|
||||||
|
console.log(getMatches(data, process.argv[2] || 'ltltle'));
|
||||||
|
}
|
Loading…
Reference in New Issue