diff --git a/plug-api/plugos-syscall/fulltext.ts b/plug-api/plugos-syscall/fulltext.ts index 229e822..95bd18e 100644 --- a/plug-api/plugos-syscall/fulltext.ts +++ b/plug-api/plugos-syscall/fulltext.ts @@ -8,6 +8,17 @@ export function fullTextDelete(key: string) { return syscall("fulltext.delete", key); } -export function fullTextSearch(phrase: string, limit = 100) { - return syscall("fulltext.search", phrase, limit); +export type FullTextSearchOptions = { + limit?: number; + highlightPrefix?: string; + highlightPostfix?: string; + highlightEllipsis?: string; + summaryMaxLength?: number; +}; + +export function fullTextSearch( + phrase: string, + options: FullTextSearchOptions = {}, +) { + return syscall("fulltext.search", phrase, options); } diff --git a/plugos/bin/plugos-bundle.ts b/plugos/bin/plugos-bundle.ts index 9b204b1..1c3acb7 100755 --- a/plugos/bin/plugos-bundle.ts +++ b/plugos/bin/plugos-bundle.ts @@ -138,7 +138,7 @@ async function bundleRun( console.error(`Error building ${manifestPath}:`, e); } } - console.log("Done."); + console.log("Done building plugs."); building = false; } diff --git a/plugos/syscalls/fulltext.sqlite.ts b/plugos/syscalls/fulltext.sqlite.ts index 37361fb..4a6346a 100644 --- a/plugos/syscalls/fulltext.sqlite.ts +++ b/plugos/syscalls/fulltext.sqlite.ts @@ -1,3 +1,4 @@ +import { FullTextSearchOptions } from "../../plug-api/plugos-syscall/fulltext.ts"; import { AsyncSQLite } from "../../plugos/sqlite/async_sqlite.ts"; import { SysCallMapping } from "../system.ts"; @@ -34,15 +35,30 @@ export function fullTextSearchSyscalls( "fulltext.delete": async (_ctx, key: string) => { await db.execute(`DELETE FROM ${tableName} WHERE key = ?`, key); }, - "fulltext.search": async (_ctx, phrase: string, limit: number) => { - console.log("Got search query", phrase); + "fulltext.search": async ( + _ctx, + phrase: string, + options: FullTextSearchOptions, + ) => { return ( 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, - limit, + options.limit || 20, ) - ).map((item) => ({ name: item.key, rank: item.rank })); + ).map((item) => ({ + name: item.key, + score: item.score, + snippet: item.snippet, + })); }, }; } diff --git a/plugs/core/search.ts b/plugs/core/search.ts index dc8a3a1..b4cd7ff 100644 --- a/plugs/core/search.ts +++ b/plugs/core/search.ts @@ -1,6 +1,6 @@ import { fulltext } from "$sb/plugos-syscall/mod.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 { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts"; import { applyQuery, removeQueries } from "$sb/lib/query.ts"; @@ -29,7 +29,10 @@ export async function queryProvider({ if (!phraseFilter) { 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 = new Map( results.map((r: any) => [r.name, r]), @@ -65,11 +68,20 @@ export async function readFileSearch( searchPrefix.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${ results - .map((r: any) => `* [[${r.name}]] (score: ${r.rank})`) - .join("\n") + .map((r: any) => + `[[${r.name}]]:\n> ${r.snippet.split("\n").join("\n> ")}` + ) + .join("\n\n") } `; diff --git a/plugs/query/materialized_queries.ts b/plugs/query/materialized_queries.ts index 5767915..a3a4dc7 100644 --- a/plugs/query/materialized_queries.ts +++ b/plugs/query/materialized_queries.ts @@ -127,7 +127,7 @@ export async function updateMaterializedQueriesOnPage( let newText = await updateTemplateInstantiations(text, pageName); const tree = await markdown.parseMarkdown(newText); const metaData = extractMeta(tree, ["$disableDirectives"]); - console.log("Meta data", pageName, metaData); + // console.log("Meta data", pageName, metaData); if (metaData.$disableDirectives) { console.log("Directives disabled, skipping"); return false; diff --git a/web/editor.tsx b/web/editor.tsx index 22c0dc8..a537cdc 100644 --- a/web/editor.tsx +++ b/web/editor.tsx @@ -278,7 +278,8 @@ export class Editor { this.saveTimeout = setTimeout( () => { 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(); } console.log("Saving page", this.currentPage);