WIP better matching
This commit is contained in:
@@ -24,8 +24,10 @@ function moveNoteSelection(ev: KeyboardEvent): void {
|
|||||||
selectedNote.previous()
|
selectedNote.previous()
|
||||||
break
|
break
|
||||||
case "ArrowLeft":
|
case "ArrowLeft":
|
||||||
|
ev.preventDefault()
|
||||||
break
|
break
|
||||||
case "ArrowRight":
|
case "ArrowRight":
|
||||||
|
ev.preventDefault()
|
||||||
break
|
break
|
||||||
|
|
||||||
case "Enter":
|
case "Enter":
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ async function createOrOpenNote(item: ResultNote): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onInputEnter(event: CustomEvent<ResultNote>): void {
|
function onInputEnter(event: CustomEvent<ResultNote>): void {
|
||||||
|
console.log(event.detail)
|
||||||
openNote(event.detail)
|
openNote(event.detail)
|
||||||
$modal.close()
|
$modal.close()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,17 +2,30 @@
|
|||||||
import type { ResultNote } from "./globals"
|
import type { ResultNote } from "./globals"
|
||||||
import { openNote } from "./notes"
|
import { openNote } from "./notes"
|
||||||
import { modal, selectedNote } from "./stores"
|
import { modal, selectedNote } from "./stores"
|
||||||
import { escapeHTML } from "./utils"
|
import { escapeHTML, escapeRegex, getAllIndices, highlighter } from "./utils"
|
||||||
|
|
||||||
export let selected = false
|
export let selected = false
|
||||||
export let note: ResultNote
|
export let note: ResultNote
|
||||||
|
|
||||||
$: cleanContent = (() => {
|
function cleanContent(content: string): string {
|
||||||
const content = escapeHTML(note.content)
|
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")
|
const tmp = document.createElement("div")
|
||||||
tmp.innerHTML = content
|
tmp.innerHTML = escapeHTML(content)
|
||||||
return tmp.textContent
|
|
||||||
})()
|
return tmp.textContent ?? ''
|
||||||
|
}
|
||||||
|
$: reg = new RegExp(note.searchResult.terms.map(escapeRegex).join('|'), 'gi')
|
||||||
|
|
||||||
|
$: cleanedContent = cleanContent(note.content)
|
||||||
|
|
||||||
function onHover() {
|
function onHover() {
|
||||||
$selectedNote = note
|
$selectedNote = note
|
||||||
@@ -32,12 +45,12 @@ function onClick() {
|
|||||||
on:click={onClick}
|
on:click={onClick}
|
||||||
>
|
>
|
||||||
<span class="omnisearch-result__title">
|
<span class="omnisearch-result__title">
|
||||||
{@html note.basename}
|
{@html note.basename.replace(reg, highlighter)}
|
||||||
</span>
|
</span>
|
||||||
<span class="omnisearch-result__counter">
|
<span class="omnisearch-result__counter">
|
||||||
{note.matches.length} {note.matches.length > 1 ? "matches" : "match"}
|
{note.matches.length} {note.matches.length > 1 ? "matches" : "match"}
|
||||||
</span>
|
</span>
|
||||||
<div class="omnisearch-result__body">
|
<div class="omnisearch-result__body">
|
||||||
{@html cleanContent}
|
{@html cleanedContent.replace(reg, highlighter)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import type { SearchResult } from 'minisearch'
|
||||||
|
|
||||||
// Matches a wikiling that begins a string
|
// Matches a wikiling that begins a string
|
||||||
export const regexWikilink = /^!?\[\[(?<name>.+?)(\|(?<alias>.+?))?\]\]/
|
export const regexWikilink = /^!?\[\[(?<name>.+?)(\|(?<alias>.+?))?\]\]/
|
||||||
export const regexLineSplit = /\r?\n|\r|((\.|\?|!)( |\r?\n|\r))/g
|
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 = {
|
export type ResultNote = {
|
||||||
|
searchResult: SearchResult
|
||||||
path: string
|
path: string
|
||||||
basename: string
|
basename: string
|
||||||
content: string
|
content: string
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ export async function openNote(
|
|||||||
newPane = false,
|
newPane = false,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const app = get(plugin).app
|
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)
|
// const fileCache = app.metadataCache.getFileCache(file)
|
||||||
// console.log(fileCache)
|
// 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(
|
const offset = content.indexOf(
|
||||||
item.matches[item.occurence].match.toLowerCase(),
|
item.matches[item.occurence].match.toLowerCase(),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,11 +4,9 @@ import type { IndexedNote, ResultNote } from './globals'
|
|||||||
import { indexedNotes, plugin } from './stores'
|
import { indexedNotes, plugin } from './stores'
|
||||||
import { get } from 'svelte/store'
|
import { get } from 'svelte/store'
|
||||||
import {
|
import {
|
||||||
escapeHTML,
|
|
||||||
escapeRegex,
|
escapeRegex,
|
||||||
extractHeadingsFromCache,
|
extractHeadingsFromCache,
|
||||||
getAllIndexes,
|
getAllIndices,
|
||||||
highlighter,
|
|
||||||
wait,
|
wait,
|
||||||
} from './utils'
|
} from './utils'
|
||||||
|
|
||||||
@@ -67,40 +65,21 @@ export function getSuggestions(query: string): ResultNote[] {
|
|||||||
if (!note) {
|
if (!note) {
|
||||||
throw new Error(`Note "${result.id}" not indexed`)
|
throw new Error(`Note "${result.id}" not indexed`)
|
||||||
}
|
}
|
||||||
let basename = escapeHTML(note.basename)
|
const reg = new RegExp(result.terms.map(escapeRegex).join('|'), 'gi')
|
||||||
let content = escapeHTML(note.content)
|
const matches = getAllIndices(note.content, reg)
|
||||||
|
|
||||||
// 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 resultNote: ResultNote = {
|
const resultNote: ResultNote = {
|
||||||
content,
|
searchResult: result,
|
||||||
basename,
|
|
||||||
path: note.path,
|
|
||||||
matches,
|
|
||||||
occurence: 0,
|
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
|
return resultNote
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
35
src/utils.ts
35
src/utils.ts
@@ -6,6 +6,7 @@ import {
|
|||||||
regexYaml,
|
regexYaml,
|
||||||
} from './globals'
|
} from './globals'
|
||||||
import type { SearchMatch } from './globals'
|
import type { SearchMatch } from './globals'
|
||||||
|
import { uniqBy } from 'lodash-es'
|
||||||
|
|
||||||
export function highlighter(str: string): string {
|
export function highlighter(str: string): string {
|
||||||
return '<span class="search-result-file-matched-text">' + str + '</span>'
|
return '<span class="search-result-file-matched-text">' + str + '</span>'
|
||||||
@@ -76,15 +77,43 @@ export function escapeRegex(str: string): string {
|
|||||||
* Returns the positions of all occurences of `val` inside of `text`
|
* Returns the positions of all occurences of `val` inside of `text`
|
||||||
* https://stackoverflow.com/a/58828841
|
* https://stackoverflow.com/a/58828841
|
||||||
* @param text
|
* @param text
|
||||||
* @param val
|
* @param regex
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function getAllIndexes(text: string, val: RegExp): SearchMatch[] {
|
export function getAllIndices(text: string, regex: RegExp): SearchMatch[] {
|
||||||
return [...text.matchAll(val)]
|
return [...text.matchAll(regex)]
|
||||||
.map(o => ({ match: o[0], index: o.index }))
|
.map(o => ({ match: o[0], index: o.index }))
|
||||||
.filter(isSearchMatch)
|
.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(
|
export function extractHeadingsFromCache(
|
||||||
cache: CachedMetadata,
|
cache: CachedMetadata,
|
||||||
level: number,
|
level: number,
|
||||||
|
|||||||
Reference in New Issue
Block a user