#287 - Fixed & improved highlightText() + a bit of cleaning (#288)

This commit is contained in:
Simon Cambier
2023-09-11 21:32:01 +02:00
committed by GitHub
parent d651278b43
commit 0558b9a328
3 changed files with 38 additions and 44 deletions

View File

@@ -75,6 +75,10 @@ export class Query {
return this.getTags().map(o => o.replace(/^#/, '')) return this.getTags().map(o => o.replace(/^#/, ''))
} }
/**
*
* @returns An array of strings that are in quotes
*/
public getExactTerms(): string[] { public getExactTerms(): string[] {
return [ return [
...new Set( ...new Set(

View File

@@ -10,9 +10,10 @@ import {
excerptBefore, excerptBefore,
} from 'src/globals' } from 'src/globals'
import { settings } from 'src/settings' import { settings } from 'src/settings'
import { escapeRegex, warnDebug } from './utils' import { warnDebug } from './utils'
import type { Query } from 'src/search/query' import type { Query } from 'src/search/query'
import { Notice } from 'obsidian' import { Notice } from 'obsidian'
import { escapeRegExp } from 'lodash-es'
export function highlighterGroups(_substring: string, ...args: any[]) { export function highlighterGroups(_substring: string, ...args: any[]) {
// args[0] is the single char preceding args[1], which is the word we want to highlight // args[0] is the single char preceding args[1], which is the word we want to highlight
@@ -21,39 +22,35 @@ export function highlighterGroups(_substring: string, ...args: any[]) {
return '<no content>' return '<no content>'
} }
/**
* Wraps the matches in the text with a <span> element and a highlight class
* @param text
* @param matches
* @returns The html string with the matches highlighted
*/
export function highlightText(text: string, matches: SearchMatch[]): string { export function highlightText(text: string, matches: SearchMatch[]): string {
matches.forEach(matchInfo => { try {
const matchRegex = new RegExp(`\\b${matchInfo.match}\\b`, 'giu') return text.replace(
const matchOffsets = [] new RegExp(
matches
let match .map(matchInfo => `\\b${escapeRegExp(matchInfo.match)}\\b`)
while ((match = matchRegex.exec(text)) !== null) { .join('|'),
matchOffsets.push({ index: match.index, text: match[0] }) 'giu'
} ),
match => {
if (!matchOffsets.length) { const matchInfo = matches.find(info =>
return text match.match(new RegExp(`\\b${escapeRegExp(info.match)}\\b`, 'giu'))
} )
if (matchInfo) {
const closestMatch = matchOffsets.reduce((prev, curr) => { return `<span class="${highlightClass}">${match}</span>`
return Math.abs(curr.index - matchInfo.offset) < }
Math.abs(prev.index - matchInfo.offset) return match
? curr }
: prev )
}) } catch (e) {
console.error('Omnisearch - Error in highlightText()', e)
if (matchOffsets.includes(closestMatch)) { return text
const originalMatch = closestMatch.text }
text =
text.substring(0, closestMatch.index) +
`<span class="${highlightClass}">` +
originalMatch +
'</span>' +
text.substring(closestMatch.index + originalMatch.length)
}
})
return text
} }
export function escapeHTML(html: string): string { export function escapeHTML(html: string): string {
@@ -94,10 +91,9 @@ export function stringsToRegex(strings: string[]): RegExp {
? `^|${SPACE_OR_PUNCTUATION_UNIQUE.source}|\-|[A-Z]` ? `^|${SPACE_OR_PUNCTUATION_UNIQUE.source}|\-|[A-Z]`
: `^|${SPACE_OR_PUNCTUATION_UNIQUE.source}|\-`) + : `^|${SPACE_OR_PUNCTUATION_UNIQUE.source}|\-`) +
')' + ')' +
`(${strings.map(s => escapeRegex(s)).join('|')})` `(${strings.map(s => escapeRegExp(s)).join('|')})`
const reg = new RegExp(`${joined}`, 'gu') return new RegExp(`${joined}`, 'gu')
return reg
} }
export function getMatches( export function getMatches(
@@ -122,8 +118,8 @@ export function getMatches(
} }
} }
// If the query can be found "as is" in the text, put this match first // If the query is more than 1 token and can be found "as is" in the text, put this match first
if (query) { if (query && query.query.text.length > 1) {
const best = text.indexOf(query.segmentsToStr()) const best = text.indexOf(query.segmentsToStr())
if (best > -1 && matches.find(m => m.offset === best)) { if (best > -1 && matches.find(m => m.offset === best)) {
matches = matches.filter(m => m.offset !== best) matches = matches.filter(m => m.offset !== best)

View File

@@ -25,12 +25,6 @@ export function wait(ms: number): Promise<void> {
}) })
} }
// https://stackoverflow.com/a/3561711
// but we enclose special chars in brackets to avoid them being interpreted as regex
export function escapeRegex(str: string): string {
return str.replace(/[-/\\^$*+?.()|[\]{}]/g, '[$&]')
}
/** /**
* 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