feat: search modes

This commit is contained in:
EnixCoda 2021-02-02 22:56:44 +08:00
parent e6a0e0a139
commit e87fec8f30
No known key found for this signature in database
GPG key ID: 0C1A07377913A1DD
3 changed files with 99 additions and 0 deletions

View file

@ -0,0 +1,48 @@
import * as React from 'react'
import { ModeShape } from '.'
import { Highlight } from '../Highlight'
export const fuzzyMode: ModeShape = {
getSearchParams(searchKey) {
const matchNode = (node: TreeNode) => fuzzyMatch(searchKey, node.path)
return {
matchNode,
}
},
renderNodeLabelText(node, searchKey) {
const { name, path } = node
const indexes = fuzzyMatchIndexes(searchKey, path, path.length - name.length)
return (
<span>
<Highlight
match={new RegExp(indexes.map(i => (i === 0 ? `^.` : `(?<=^.{${i}}).`)).join('|'))}
text={name}
/>
</span>
)
},
}
function fuzzyMatch(input: string, sample: string) {
let i = 0,
j = 0
while (i < input.length && j < sample.length) {
if (input[i] === sample[j]) i++
j++
}
return i === input.length
}
function fuzzyMatchIndexes(input: string, sample: string, shift: number = 0) {
const r: number[] = []
let i = 0,
j = 0
while (i < input.length && j < sample.length) {
if (input[i] === sample[j]) {
if (j >= shift) r.push(j - shift)
i++
}
j++
}
return r
}

View file

@ -0,0 +1,16 @@
import { ReactNode } from 'react'
import { SearchParams } from 'utils/VisibleNodesGenerator'
import { fuzzyMode } from './fuzzyMode'
import { regexMode } from './regexMode'
export type SearchMode = 'regex' | 'fuzzy'
export type ModeShape = {
getSearchParams(searchKey: string): Pick<SearchParams, 'matchNode'> | null
renderNodeLabelText(node: TreeNode, searchKey: string): ReactNode
}
export const searchModes: Record<SearchMode, ModeShape> = {
regex: regexMode,
fuzzy: fuzzyMode,
}

View file

@ -0,0 +1,35 @@
import * as React from 'react'
import { cx } from 'utils/cx'
import { isValidRegexpSource, searchKeyToRegexp } from 'utils/general'
import { ModeShape } from '.'
import { Highlight } from '../Highlight'
export const regexMode: ModeShape = {
getSearchParams(searchKey) {
const regexp = searchKeyToRegexp(searchKey)
if (regexp) {
const matchNode = (node: TreeNode) => regexp.test(node.name)
return {
matchNode,
}
}
return null
},
renderNodeLabelText(node, searchKey) {
const regex =
searchKey && isValidRegexpSource(searchKey) ? new RegExp(searchKey, 'gi') : undefined
const { name } = node
return name.includes('/') ? (
name.split('/').map((chunk, index, arr) => (
<span key={chunk} className={cx({ prefix: index + 1 !== arr.length })}>
<Highlight match={regex} text={chunk} />
{index + 1 !== arr.length && '/'}
</span>
))
) : (
<Highlight match={regex} text={name} />
)
},
}