From cb7a11c7aa5479f6f1c6f5ba223a3109560d38c6 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Tue, 26 Apr 2022 21:50:05 +0200 Subject: [PATCH] #25 - quoted expressions for Vault search ok --- src/components/ModalInFile.svelte | 6 ++--- src/components/ModalVault.svelte | 6 ++--- src/search.ts | 29 ++++++++++++++++++----- src/utils.ts | 39 +++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 12 deletions(-) diff --git a/src/components/ModalInFile.svelte b/src/components/ModalInFile.svelte index 309e2a9..a7ae6f9 100644 --- a/src/components/ModalInFile.svelte +++ b/src/components/ModalInFile.svelte @@ -40,14 +40,14 @@ onDestroy(() => { eventBus.enable("vault") }) -$: { +$: (async () => { if (searchQuery) { - note = getSuggestions(searchQuery, { singleFilePath })[0] ?? null + note = (await getSuggestions(searchQuery, { singleFilePath }))[0] ?? null lastSearch = searchQuery } selectedIndex = 0 scrollIntoView() -} +})() $: { if (note) { diff --git a/src/components/ModalVault.svelte b/src/components/ModalVault.svelte index 3e792ed..a22c65c 100644 --- a/src/components/ModalVault.svelte +++ b/src/components/ModalVault.svelte @@ -20,14 +20,14 @@ let searchQuery: string let resultNotes: ResultNote[] = [] $: selectedNote = resultNotes[selectedIndex] -$: { +$: (async() => { if (searchQuery) { - resultNotes = getSuggestions(searchQuery) + resultNotes = await getSuggestions(searchQuery) lastSearch = searchQuery } selectedIndex = 0 scrollIntoView() -} +})() onMount(() => { searchQuery = lastSearch diff --git a/src/search.ts b/src/search.ts index 94cb4de..4166c34 100644 --- a/src/search.ts +++ b/src/search.ts @@ -6,7 +6,13 @@ import { type ResultNote, type SearchMatch, } from './globals' -import { extractHeadingsFromCache, stringsToRegex, wait } from './utils' +import { + extractHeadingsFromCache, + splitQuotes, + stringsToRegex, + stripMarkdownCharacters, + wait, +} from './utils' let minisearchInstance: MiniSearch @@ -57,9 +63,9 @@ export async function initGlobalSearchIndex(): Promise { * @param query * @returns */ -function search(query: string): SearchResult[] { +async function search(query: string): Promise { if (!query) return [] - return minisearchInstance.search(query, { + let results = minisearchInstance.search(query, { prefix: true, fuzzy: term => (term.length > 4 ? 0.2 : false), combineWith: 'AND', @@ -70,6 +76,17 @@ function search(query: string): SearchResult[] { headings3: 1.1, }, }) + const quoted = splitQuotes(query.toLowerCase()) + + if (quoted.length) { + results = results.filter(r => { + const content = stripMarkdownCharacters( + indexedNotes[r.id]?.content ?? '', + ).toLowerCase() + return quoted.every(q => content.includes(q)) + }) + } + return results } /** @@ -96,12 +113,12 @@ export function getMatches(text: string, reg: RegExp): SearchMatch[] { * @param options * @returns */ -export function getSuggestions( +export async function getSuggestions( query: string, options?: Partial<{ singleFilePath: string | null }>, -): ResultNote[] { +): Promise { // Get the raw results - let results = search(query) + let results = await search(query) if (!results.length) return [] // Either keep the 50 first results, diff --git a/src/utils.ts b/src/utils.ts index f152f9a..ed655c3 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -97,3 +97,42 @@ export function makeExcerpt(content: string, offset: number): string { } return escapeHTML(content) } + +/** + * splits a string in words or "expressions in quotes" + * @param str + * @returns + */ +export function splitQuotes(str: string): string[] { + return str.match(/"(.*?)"/g)?.map(s => s.replace(/"/g, '')) ?? [] +} + +function mapAsync( + array: T[], + callbackfn: (value: T, index: number, array: T[]) => Promise, +): Promise { + return Promise.all(array.map(callbackfn)) +} + +/** + * https://stackoverflow.com/a/53508547 + * @param arr + * @param callback + * @returns + */ +export async function filterAsync( + array: T[], + callbackfn: (value: T, index: number, array: T[]) => Promise, +): Promise { + const filterMap = await mapAsync(array, callbackfn) + return array.filter((value, index) => filterMap[index]) +} + +/** + * A simple function to strip bold and italic markdown chars from a string + * @param text + * @returns + */ +export function stripMarkdownCharacters(text: string): string { + return text.replace(/(\*|\_)+(.+?)(\*|\_)+/g, (match, p1, p2) => p2) +}