silverbullet/plugs/search/search.ts

103 lines
2.7 KiB
TypeScript
Raw Permalink Normal View History

2024-08-02 23:14:40 +08:00
import type {
IndexTreeEvent,
QueryProviderEvent,
} from "../../plug-api/types.ts";
import { renderToText } from "@silverbulletmd/silverbullet/lib/tree";
import {
applyQuery,
liftAttributeFilter,
} from "@silverbulletmd/silverbullet/lib/query";
import { editor } from "@silverbulletmd/silverbullet/syscalls";
2024-07-30 23:33:33 +08:00
import type { FileMeta } from "../../plug-api/types.ts";
2023-10-03 21:24:07 +08:00
import { ftsIndexPage, ftsSearch } from "./engine.ts";
import { evalQueryExpression } from "@silverbulletmd/silverbullet/lib/query_expression";
import { PromiseQueue } from "$lib/async.ts";
2022-05-16 21:09:36 +08:00
const searchPrefix = "🔍 ";
2023-08-30 03:17:29 +08:00
// Search indexing is prone to concurrency issues, so we queue all write operations
const promiseQueue = new PromiseQueue();
export function indexPage({ name, tree }: IndexTreeEvent) {
const text = renderToText(tree);
2023-08-30 03:17:29 +08:00
return promiseQueue.runInQueue(async () => {
// console.log("Now FTS indexing", name);
2023-10-03 21:24:07 +08:00
// await engine.deleteDocument(name);
await ftsIndexPage(name, text);
2023-08-30 03:17:29 +08:00
});
2022-06-28 20:14:15 +08:00
}
2022-05-16 21:09:36 +08:00
export async function queryProvider({
query,
}: QueryProviderEvent): Promise<any[]> {
const phraseFilter = liftAttributeFilter(query.filter, "phrase");
2022-05-16 21:09:36 +08:00
if (!phraseFilter) {
throw Error("No 'phrase' filter specified, this is mandatory");
}
const phrase = await evalQueryExpression(phraseFilter, {}, {}, {});
// console.log("Phrase", phrase);
2023-10-03 21:24:07 +08:00
let results: any[] = await ftsSearch(phrase);
// Patch the object to a format that users expect (translate id to name)
for (const r of results) {
r.name = r.id;
delete r.id;
}
2022-05-16 21:09:36 +08:00
results = await applyQuery(query, results, {}, {});
2022-05-16 21:09:36 +08:00
return results;
}
2022-05-17 17:53:17 +08:00
export async function searchCommand() {
2022-10-19 15:52:29 +08:00
const phrase = await editor.prompt("Search for: ");
2022-05-17 17:53:17 +08:00
if (phrase) {
await editor.navigate({ page: `${searchPrefix}${phrase}` });
2022-05-17 17:53:17 +08:00
}
}
2022-10-19 15:52:29 +08:00
export async function readFileSearch(
2022-10-12 17:47:13 +08:00
name: string,
): Promise<{ data: Uint8Array; meta: FileMeta }> {
2022-10-19 15:52:29 +08:00
const phrase = name.substring(
searchPrefix.length,
name.length - ".md".length,
);
2023-10-03 21:24:07 +08:00
const results = await ftsSearch(phrase);
2022-10-12 17:47:13 +08:00
const text = `# Search results for "${phrase}"\n${
results
.map((r) => `* [[${r.id}]] (score ${r.score})`)
.join("\n")
2022-10-12 17:47:13 +08:00
}
`;
2022-10-19 15:52:29 +08:00
2022-05-17 17:53:17 +08:00
return {
data: new TextEncoder().encode(text),
2022-05-17 17:53:17 +08:00
meta: {
name,
2022-10-19 15:52:29 +08:00
contentType: "text/markdown",
size: text.length,
created: 0,
2022-05-17 17:53:17 +08:00
lastModified: 0,
perm: "ro",
},
};
}
export function writeFileSearch(
name: string,
): FileMeta {
// Never actually writing this
return getFileMetaSearch(name);
}
2022-10-19 15:52:29 +08:00
export function getFileMetaSearch(name: string): FileMeta {
2022-05-17 17:53:17 +08:00
return {
name,
2022-10-19 15:52:29 +08:00
contentType: "text/markdown",
size: -1,
created: 0,
2022-05-17 17:53:17 +08:00
lastModified: 0,
perm: "ro",
};
}