diff --git a/src/components/Highlight.tsx b/src/components/Highlight.tsx
index 083630d..820a294 100644
--- a/src/components/Highlight.tsx
+++ b/src/components/Highlight.tsx
@@ -1,18 +1,23 @@
import * as React from 'react'
-export function Highlight(props: { text: string; match?: RegExp }) {
+export function Highlight(props: { text: string; match?: RegExp | string }) {
const { text, match } = props
const $match = React.useMemo(() => {
- if (match instanceof RegExp) {
- if (match.flags.includes('g')) return match
- return new RegExp(match.source, 'g' + match.flags)
+ if (match) {
+ if (match instanceof RegExp) {
+ if (match.flags.includes('g')) return match
+ return new RegExp(match.source, 'g' + match.flags)
+ }
+ return new RegExp(match, 'g')
}
return null
}, [match])
- if (!($match instanceof RegExp) || typeof text !== 'string') return <>{text}>
+ if (!$match) return <>{text}>
- const matchedPieces = Array.from(text.matchAll($match)).map(([text]) => text)
+ const matchedPieces = Array.from(text.matchAll($match)).map(
+ ([text, highlightText = text]) => highlightText,
+ )
const preservedPieces = text.split($match)
const content = []
diff --git a/src/components/searchModes/fuzzyMode.tsx b/src/components/searchModes/fuzzyMode.tsx
index 9aa7f8d..1bcbe9a 100644
--- a/src/components/searchModes/fuzzyMode.tsx
+++ b/src/components/searchModes/fuzzyMode.tsx
@@ -2,7 +2,6 @@ import * as React from 'react'
import { cx } from 'utils/cx'
import { hasUpperCase } from 'utils/general'
import { ModeShape } from '.'
-import { Highlight } from '../Highlight'
export const fuzzyMode: ModeShape = {
getSearchParams(searchKey) {
@@ -26,13 +25,13 @@ export const fuzzyMode: ModeShape = {
let progress = 0
return chunks.map((chunk, index, chunks) => {
const chunkIndexes = indexes.filter(i => i >= progress && i < chunk.length + progress)
- const regexp = chunkIndexes.length
- ? new RegExp(chunkIndexes.map(i => `(?<=^.{${i - progress}}).`).join('|'))
- : undefined
+
+ const $indexes = chunkIndexes.length ? chunkIndexes.map(i => i - progress) : undefined
+
progress += chunk.length + 1
return (
-
+
)
})
@@ -61,3 +60,19 @@ function fuzzyMatchIndexes(input: string, sample: string, shift: number = 0) {
}
return indexes
}
+
+function Highlight(props: { text: string; match?: number[] }) {
+ const { text, match } = props
+
+ if (!match?.length) return <>{text}>
+
+ return (
+ <>
+ {text
+ .split('')
+ .map((char, i) =>
+ match.includes(i) ? {char} : {char},
+ )}
+ >
+ )
+}
diff --git a/src/components/searchModes/regexMode.tsx b/src/components/searchModes/regexMode.tsx
index 6de1b3b..bfd3b39 100644
--- a/src/components/searchModes/regexMode.tsx
+++ b/src/components/searchModes/regexMode.tsx
@@ -1,29 +1,22 @@
import * as React from 'react'
import { cx } from 'utils/cx'
-import { hasUpperCase, isValidRegexpSource, searchKeyToRegexp } from 'utils/general'
+import { searchKeyToRegexp } from 'utils/general'
import { ModeShape } from '.'
import { Highlight } from '../Highlight'
export const regexMode: ModeShape = {
getSearchParams(searchKey) {
- if (!searchKey) return null
-
const regexp = searchKeyToRegexp(searchKey)
if (regexp) {
- const matchNode = (node: TreeNode) => regexp.test(node.name)
-
return {
- matchNode,
+ matchNode: node => regexp.test(node.name),
}
}
return null
},
renderNodeLabelText(node, searchKey) {
- const regex =
- searchKey && isValidRegexpSource(searchKey)
- ? new RegExp(searchKey, 'g' + (hasUpperCase(searchKey) ? '' : 'i'))
- : undefined
+ const regex = searchKeyToRegexp(searchKey) || undefined
const { name } = node
return name.includes('/') ? (
name.split('/').map((chunk, index, chunks) => (
diff --git a/src/utils/general.ts b/src/utils/general.ts
index 9bafe4e..9d31607 100644
--- a/src/utils/general.ts
+++ b/src/utils/general.ts
@@ -146,13 +146,7 @@ export async function JSONRequest(url: string, data: any, extra: RequestInit = {
export function searchKeyToRegexp(searchKey: string) {
if (!searchKey) return null
- try {
- const flags = hasUpperCase(searchKey) ? '' : 'i'
- // case-sensitive when searchKey contains uppercase char
- return new RegExp(searchKey, flags)
- } catch (err) {
- return null // matching nothing if failed transforming regexp
- }
+ return safeRegexp(searchKey, hasUpperCase(searchKey) ? 'g' : 'gi')
}
export function hasUpperCase(input: string) {
@@ -168,15 +162,18 @@ export async function renderReact(element: ReactElement) {
})
}
-export function isValidRegexpSource(source: string) {
+export function safeRegexp(pattern: string | RegExp, flags?: string | undefined) {
try {
- new RegExp(source)
- return true
+ return new RegExp(pattern, flags)
} catch (err) {
- return false
+ return null
}
}
+export function isValidRegexpSource(source: string) {
+ return Boolean(safeRegexp(source))
+}
+
export function withEffect any>(
method: Method,
effect: (payload: ReturnType) => void,