Full text search improvements

pull/109/head
Zef Hemel 2022-10-22 20:23:54 +02:00
parent 02dd2f17c7
commit 9164b57a3e
6 changed files with 55 additions and 15 deletions

View File

@ -8,6 +8,17 @@ export function fullTextDelete(key: string) {
return syscall("fulltext.delete", key); return syscall("fulltext.delete", key);
} }
export function fullTextSearch(phrase: string, limit = 100) { export type FullTextSearchOptions = {
return syscall("fulltext.search", phrase, limit); limit?: number;
highlightPrefix?: string;
highlightPostfix?: string;
highlightEllipsis?: string;
summaryMaxLength?: number;
};
export function fullTextSearch(
phrase: string,
options: FullTextSearchOptions = {},
) {
return syscall("fulltext.search", phrase, options);
} }

View File

@ -138,7 +138,7 @@ async function bundleRun(
console.error(`Error building ${manifestPath}:`, e); console.error(`Error building ${manifestPath}:`, e);
} }
} }
console.log("Done."); console.log("Done building plugs.");
building = false; building = false;
} }

View File

@ -1,3 +1,4 @@
import { FullTextSearchOptions } from "../../plug-api/plugos-syscall/fulltext.ts";
import { AsyncSQLite } from "../../plugos/sqlite/async_sqlite.ts"; import { AsyncSQLite } from "../../plugos/sqlite/async_sqlite.ts";
import { SysCallMapping } from "../system.ts"; import { SysCallMapping } from "../system.ts";
@ -34,15 +35,30 @@ export function fullTextSearchSyscalls(
"fulltext.delete": async (_ctx, key: string) => { "fulltext.delete": async (_ctx, key: string) => {
await db.execute(`DELETE FROM ${tableName} WHERE key = ?`, key); await db.execute(`DELETE FROM ${tableName} WHERE key = ?`, key);
}, },
"fulltext.search": async (_ctx, phrase: string, limit: number) => { "fulltext.search": async (
console.log("Got search query", phrase); _ctx,
phrase: string,
options: FullTextSearchOptions,
) => {
return ( return (
await db.query( await db.query(
`SELECT key, rank FROM ${tableName} WHERE value MATCH ? ORDER BY key, rank LIMIT ?`, `SELECT key, bm25(fts) AS score, snippet(fts, 1, ?, ?, ?, ?) as snippet
FROM ${tableName}
WHERE value
MATCH ?
ORDER BY score LIMIT ?`,
options.highlightPrefix || "",
options.highlightPostfix || "",
options.highlightEllipsis || "...",
options.summaryMaxLength || 50,
phrase, phrase,
limit, options.limit || 20,
) )
).map((item) => ({ name: item.key, rank: item.rank })); ).map((item) => ({
name: item.key,
score: item.score,
snippet: item.snippet,
}));
}, },
}; };
} }

View File

@ -1,6 +1,6 @@
import { fulltext } from "$sb/plugos-syscall/mod.ts"; import { fulltext } from "$sb/plugos-syscall/mod.ts";
import { renderToText } from "$sb/lib/tree.ts"; import { renderToText } from "$sb/lib/tree.ts";
import type { FileMeta, PageMeta } from "../../common/types.ts"; import type { FileMeta } from "../../common/types.ts";
import { editor, index } from "$sb/silverbullet-syscall/mod.ts"; import { editor, index } from "$sb/silverbullet-syscall/mod.ts";
import { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts"; import { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts";
import { applyQuery, removeQueries } from "$sb/lib/query.ts"; import { applyQuery, removeQueries } from "$sb/lib/query.ts";
@ -29,7 +29,10 @@ export async function queryProvider({
if (!phraseFilter) { if (!phraseFilter) {
throw Error("No 'phrase' filter specified, this is mandatory"); throw Error("No 'phrase' filter specified, this is mandatory");
} }
let results = await fulltext.fullTextSearch(phraseFilter.value, 100); let results = await fulltext.fullTextSearch(phraseFilter.value, {
highlightEllipsis: "...",
limit: 100,
});
const allPageMap: Map<string, any> = new Map( const allPageMap: Map<string, any> = new Map(
results.map((r: any) => [r.name, r]), results.map((r: any) => [r.name, r]),
@ -65,11 +68,20 @@ export async function readFileSearch(
searchPrefix.length, searchPrefix.length,
name.length - ".md".length, name.length - ".md".length,
); );
const results = await fulltext.fullTextSearch(phrase, 100); console.log("Here");
const results = await fulltext.fullTextSearch(phrase, {
highlightEllipsis: "...",
highlightPostfix: "==",
highlightPrefix: "==",
summaryMaxLength: 30,
limit: 100,
});
const text = `# Search results for "${phrase}"\n${ const text = `# Search results for "${phrase}"\n${
results results
.map((r: any) => `* [[${r.name}]] (score: ${r.rank})`) .map((r: any) =>
.join("\n") `[[${r.name}]]:\n> ${r.snippet.split("\n").join("\n> ")}`
)
.join("\n\n")
} }
`; `;

View File

@ -127,7 +127,7 @@ export async function updateMaterializedQueriesOnPage(
let newText = await updateTemplateInstantiations(text, pageName); let newText = await updateTemplateInstantiations(text, pageName);
const tree = await markdown.parseMarkdown(newText); const tree = await markdown.parseMarkdown(newText);
const metaData = extractMeta(tree, ["$disableDirectives"]); const metaData = extractMeta(tree, ["$disableDirectives"]);
console.log("Meta data", pageName, metaData); // console.log("Meta data", pageName, metaData);
if (metaData.$disableDirectives) { if (metaData.$disableDirectives) {
console.log("Directives disabled, skipping"); console.log("Directives disabled, skipping");
return false; return false;

View File

@ -278,7 +278,8 @@ export class Editor {
this.saveTimeout = setTimeout( this.saveTimeout = setTimeout(
() => { () => {
if (this.currentPage) { if (this.currentPage) {
if (!this.viewState.unsavedChanges) { if (!this.viewState.unsavedChanges || this.viewState.forcedROMode) {
// No unsaved changes, or read-only mode, not gonna save
return resolve(); return resolve();
} }
console.log("Saving page", this.currentPage); console.log("Saving page", this.currentPage);