mirror of
https://github.com/EnixCoda/Gitako.git
synced 2026-03-11 08:54:44 +00:00
feat: search modes
This commit is contained in:
parent
e6a0e0a139
commit
e87fec8f30
3 changed files with 99 additions and 0 deletions
48
src/components/searchModes/fuzzyMode.tsx
Normal file
48
src/components/searchModes/fuzzyMode.tsx
Normal 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
|
||||
}
|
||||
16
src/components/searchModes/index.tsx
Normal file
16
src/components/searchModes/index.tsx
Normal 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,
|
||||
}
|
||||
35
src/components/searchModes/regexMode.tsx
Normal file
35
src/components/searchModes/regexMode.tsx
Normal 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} />
|
||||
)
|
||||
},
|
||||
}
|
||||
Loading…
Reference in a new issue