diff --git a/src/CmpInput.svelte b/src/CmpInput.svelte index 4304734..cf76fe4 100644 --- a/src/CmpInput.svelte +++ b/src/CmpInput.svelte @@ -24,8 +24,10 @@ function moveNoteSelection(ev: KeyboardEvent): void { selectedNote.previous() break case "ArrowLeft": + ev.preventDefault() break case "ArrowRight": + ev.preventDefault() break case "Enter": diff --git a/src/CmpModal.svelte b/src/CmpModal.svelte index 26d06f5..3f1f79d 100644 --- a/src/CmpModal.svelte +++ b/src/CmpModal.svelte @@ -40,6 +40,7 @@ async function createOrOpenNote(item: ResultNote): Promise { } function onInputEnter(event: CustomEvent): void { + console.log(event.detail) openNote(event.detail) $modal.close() } diff --git a/src/CmpNoteResult.svelte b/src/CmpNoteResult.svelte index 778113f..0a9957c 100644 --- a/src/CmpNoteResult.svelte +++ b/src/CmpNoteResult.svelte @@ -2,17 +2,30 @@ import type { ResultNote } from "./globals" import { openNote } from "./notes" import { modal, selectedNote } from "./stores" -import { escapeHTML } from "./utils" +import { escapeHTML, escapeRegex, getAllIndices, highlighter } from "./utils" export let selected = false export let note: ResultNote -$: cleanContent = (() => { - const content = escapeHTML(note.content) +function cleanContent(content: string): string { + const pos = content.toLowerCase().indexOf(note.searchResult.terms[0]) + const surroundLen = 180 + if (pos > -1) { + const from = Math.max(0, pos - surroundLen) + const to = Math.min(content.length - 1, pos + surroundLen) + content = + (from > 0 ? "…" : "") + + content.slice(from, to).trim() + + (to < content.length - 1 ? "…" : "") + } const tmp = document.createElement("div") - tmp.innerHTML = content - return tmp.textContent -})() + tmp.innerHTML = escapeHTML(content) + + return tmp.textContent ?? '' +} +$: reg = new RegExp(note.searchResult.terms.map(escapeRegex).join('|'), 'gi') + +$: cleanedContent = cleanContent(note.content) function onHover() { $selectedNote = note @@ -32,12 +45,12 @@ function onClick() { on:click={onClick} > - {@html note.basename} + {@html note.basename.replace(reg, highlighter)} {note.matches.length} {note.matches.length > 1 ? "matches" : "match"}
- {@html cleanContent} + {@html cleanedContent.replace(reg, highlighter)}
diff --git a/src/globals.ts b/src/globals.ts index e79ed75..f666aef 100644 --- a/src/globals.ts +++ b/src/globals.ts @@ -1,3 +1,5 @@ +import type { SearchResult } from 'minisearch' + // Matches a wikiling that begins a string export const regexWikilink = /^!?\[\[(?.+?)(\|(?.+?))?\]\]/ export const regexLineSplit = /\r?\n|\r|((\.|\?|!)( |\r?\n|\r))/g @@ -27,6 +29,7 @@ export const isSearchMatch = (o: { index?: number }): o is SearchMatch => { } export type ResultNote = { + searchResult: SearchResult path: string basename: string content: string diff --git a/src/notes.ts b/src/notes.ts index b45ac83..c165873 100644 --- a/src/notes.ts +++ b/src/notes.ts @@ -8,10 +8,10 @@ export async function openNote( newPane = false, ): Promise { const app = get(plugin).app - const file = app.vault.getAbstractFileByPath(item.path) as TFile + // const file = app.vault.getAbstractFileByPath(item.path) as TFile // const fileCache = app.metadataCache.getFileCache(file) // console.log(fileCache) - const content = (await app.vault.cachedRead(file)).toLowerCase() + const content = item.content// (await app.vault.cachedRead(file)).toLowerCase() const offset = content.indexOf( item.matches[item.occurence].match.toLowerCase(), ) diff --git a/src/search.ts b/src/search.ts index b0a78d9..87bcaeb 100644 --- a/src/search.ts +++ b/src/search.ts @@ -4,11 +4,9 @@ import type { IndexedNote, ResultNote } from './globals' import { indexedNotes, plugin } from './stores' import { get } from 'svelte/store' import { - escapeHTML, escapeRegex, extractHeadingsFromCache, - getAllIndexes, - highlighter, + getAllIndices, wait, } from './utils' @@ -67,40 +65,21 @@ export function getSuggestions(query: string): ResultNote[] { if (!note) { throw new Error(`Note "${result.id}" not indexed`) } - let basename = escapeHTML(note.basename) - let content = escapeHTML(note.content) - - // Sort the terms from smaller to larger - // and highlight them in the title and body - const terms = result.terms.sort((a, b) => a.length - b.length) - const reg = new RegExp(terms.map(escapeRegex).join('|'), 'gi') - const matches = getAllIndexes(content, reg) - - // If the body contains a searched term, find its position - // and trim the text around it - const pos = content.toLowerCase().indexOf(result.terms[0]) - const surroundLen = 180 - if (pos > -1) { - const from = Math.max(0, pos - surroundLen) - const to = Math.min(content.length - 1, pos + surroundLen) - content = - (from > 0 ? '…' : '') + - content.slice(from, to).trim() + - (to < content.length - 1 ? '…' : '') - } - - // console.log(matches) - content = content.replace(reg, highlighter) - basename = basename.replace(reg, highlighter) - + const reg = new RegExp(result.terms.map(escapeRegex).join('|'), 'gi') + const matches = getAllIndices(note.content, reg) const resultNote: ResultNote = { - content, - basename, - path: note.path, - matches, + searchResult: result, occurence: 0, + matches, + ...note, + } + if (note.basename === 'Search') { + console.log('=======') + // console.log([...note.content.matchAll(reg)]) + // console.log(reg) + console.log(result) + console.log(resultNote) } - return resultNote }) diff --git a/src/utils.ts b/src/utils.ts index c4b9be1..841e834 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -6,6 +6,7 @@ import { regexYaml, } from './globals' import type { SearchMatch } from './globals' +import { uniqBy } from 'lodash-es' export function highlighter(str: string): string { return '' + str + '' @@ -76,15 +77,43 @@ export function escapeRegex(str: string): string { * Returns the positions of all occurences of `val` inside of `text` * https://stackoverflow.com/a/58828841 * @param text - * @param val + * @param regex * @returns */ -export function getAllIndexes(text: string, val: RegExp): SearchMatch[] { - return [...text.matchAll(val)] +export function getAllIndices(text: string, regex: RegExp): SearchMatch[] { + return [...text.matchAll(regex)] .map(o => ({ match: o[0], index: o.index })) .filter(isSearchMatch) } +// export function getAllIndices(text: string, terms: string[]): SearchMatch[] { +// let matches: SearchMatch[] = [] +// for (const term of terms) { +// matches = [ +// ...matches, +// ...[...text.matchAll(new RegExp(escapeRegex(term), 'gi'))] +// .map(o => ({ match: o[0], index: o.index })) +// .filter(isSearchMatch), +// ] +// } +// return matches +// // matches.sort((a, b) => b.match.length - a.match.length) +// // return uniqBy(matches, 'index') +// } + +export function replaceAll( + text: string, + terms: string[], + cb: (t: string) => string, +): string { + terms.sort((a, b) => a.length - b.length) + const regs = terms.map(term => new RegExp(escapeRegex(term), 'gi')) + for (const reg of regs) { + text = text.replaceAll(reg, cb) + } + return text +} + export function extractHeadingsFromCache( cache: CachedMetadata, level: number,