fix: go to file, highlighting

This commit is contained in:
EnixCoda 2021-02-04 21:09:09 +08:00
parent bf41fabac6
commit 66312dbc0f
No known key found for this signature in database
GPG key ID: 0C1A07377913A1DD
5 changed files with 48 additions and 35 deletions

View file

@ -49,11 +49,15 @@ const RawFileExplorer: React.FC<Props & ConnectorState> = function RawFileExplor
value: { accessToken, compressSingletonFolder, searchMode },
} = useConfigs()
React.useEffect(() => {
if (visibleNodesGenerator) {
visibleNodesGenerator.search(searchModes[searchMode].getSearchParams(searchKey))
}
}, [visibleNodesGenerator, searchKey, searchMode])
const onSearch = React.useCallback(
(searchKey: string) => {
updateSearchKey(searchKey)
if (visibleNodesGenerator) {
visibleNodesGenerator.search(searchModes[searchMode].getSearchParams(searchKey))
}
},
[updateSearchKey, visibleNodesGenerator, searchMode],
)
React.useEffect(() => {
if (treeRoot) {
@ -63,7 +67,6 @@ const RawFileExplorer: React.FC<Props & ConnectorState> = function RawFileExplor
config: {
compressSingletonFolder,
accessToken,
searchMode,
},
})
}
@ -95,7 +98,7 @@ const RawFileExplorer: React.FC<Props & ConnectorState> = function RawFileExplor
onClick={e => {
e.stopPropagation()
e.preventDefault()
updateSearchKey(node.path + '/')
onSearch(node.path + '/')
}}
>
<Icon type="search" />
@ -109,7 +112,7 @@ const RawFileExplorer: React.FC<Props & ConnectorState> = function RawFileExplor
return renders.length
? node => renders.map((render, i) => <React.Fragment key={i}>{render(node)}</React.Fragment>)
: undefined
}, [goTo, updateSearchKey, searched, searchMode])
}, [goTo, onSearch, searched, searchMode])
const renderLabelText = React.useCallback(
node => searchModes[searchMode].renderNodeLabelText(node, searchKey),
@ -147,11 +150,7 @@ const RawFileExplorer: React.FC<Props & ConnectorState> = function RawFileExplor
visibleNodes &&
renderNodeContext && (
<>
<SearchBar
value={searchKey}
onSearch={value => updateSearchKey(value)}
onFocus={onFocusSearchBar}
/>
<SearchBar value={searchKey} onSearch={onSearch} onFocus={onFocusSearchBar} />
{searched && visibleNodes.nodes.length === 0 && (
<>
<Text marginTop={6} textAlign="center" color="text.gray">

View file

@ -42,7 +42,7 @@ export function SearchBar({ onSearch, onFocus, value }: Props) {
configs.onChange({
searchMode: searchMode === 'regex' ? 'fuzzy' : 'regex',
})
onSearch('')
onSearch(value)
}}
aria-label="Toggle search mode"
>

View file

@ -7,7 +7,8 @@ export const fuzzyMode: ModeShape = {
getSearchParams(searchKey) {
if (!searchKey) return null
const matchNode = (node: TreeNode) => fuzzyMatch(searchKey, node.path)
const searchKeyInLowerCase = searchKey.toLowerCase()
const matchNode = (node: TreeNode) => fuzzyMatch(searchKeyInLowerCase, node.path.toLowerCase())
return {
matchNode,
}
@ -15,21 +16,25 @@ export const fuzzyMode: ModeShape = {
renderNodeLabelText(node, searchKey) {
const { name, path } = node
const result: React.ReactNode[] = []
const indexes = fuzzyMatchIndexes(
searchKey.toLowerCase(),
path.toLowerCase(),
path.length - name.length,
)
const chunks = name.split('/')
let renderedPath = path.slice(0, path.length - name.length)
chunks.forEach((chunk, index, chunks) => {
renderedPath += '/' + chunk
const indexes = fuzzyMatchIndexes(searchKey, renderedPath, renderedPath.length - chunk.length)
const regexp = new RegExp(indexes.map(i => `(?<=^.{${i}}).`).join('|'))
result.push(
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('|'), 'i')
: undefined
progress += chunk.length + 1
return (
<span key={chunk} className={cx({ prefix: index + 1 !== chunks.length })}>
<Highlight match={regexp} text={chunk} />
{index + 1 !== chunks.length && '/'}
</span>,
<Highlight match={regexp} text={index + 1 === chunks.length ? chunk : chunk + '/'} />
</span>
)
})
return result
},
}

View file

@ -1,4 +1,3 @@
import { searchModes } from 'components/searchModes'
import { GetCreatedMethod, MethodCreator } from 'driver/connect'
import { platform } from 'platforms'
import { Config } from 'utils/configHelper'
@ -47,7 +46,7 @@ type BoundMethodCreator<Args extends any[] = []> = MethodCreator<Props, Connecto
export const setUpTree: BoundMethodCreator<
[
Required<Pick<Props, 'treeRoot' | 'metaData'>> & {
config: Pick<Config, 'compressSingletonFolder' | 'accessToken' | 'searchMode'>
config: Pick<Config, 'compressSingletonFolder' | 'accessToken'>
},
]
> = dispatch => async ({ treeRoot, metaData, config }) => {
@ -71,11 +70,9 @@ export const setUpTree: BoundMethodCreator<
dispatch.call(toggleNodeExpansion, node, { recursive: true }),
)
})
visibleNodesGenerator.search(searchModes[config.searchMode].getSearchParams(''))
} else {
const targetPath = platform.getCurrentPath(metaData.branchName)
if (targetPath) dispatch.call(goTo, targetPath)
else visibleNodesGenerator.search(searchModes[config.searchMode].getSearchParams(''))
}
dispatch.set({ state: 'done' })
@ -192,15 +189,17 @@ export const updateSearchKey: BoundMethodCreator<[string]> = dispatch => searchK
dispatch.set({ searchKey, searched: searchKey !== '' })
}
export const goTo: BoundMethodCreator<[string[]]> = dispatch => currentPath => {
export const goTo: BoundMethodCreator<[string[]]> = dispatch => path => {
const {
state: { visibleNodesGenerator },
} = dispatch.get()
if (!visibleNodesGenerator) return
dispatch.set({ searchKey: '', searched: false })
dispatch.call(updateSearchKey, '')
visibleNodesGenerator.search(null)
dispatch.call(expandTo, currentPath)
visibleNodesGenerator.onNextUpdate(() => {
dispatch.call(expandTo, path)
})
}
export const setExpand: BoundMethodCreator<[TreeNode, boolean]> = dispatch => async (

View file

@ -120,7 +120,7 @@ class BaseLayer {
}
class ShakeLayer extends BaseLayer {
shackedRoot: TreeNode | null = null
shackedRoot: TreeNode | null = this.baseRoot
lastSearchParams: SearchParams | null = null
shakeHub = new EventHub<{ emit: TreeNode | null }>()
@ -134,7 +134,7 @@ class ShakeLayer extends BaseLayer {
(searchParams: ShakeLayer['lastSearchParams']) => {
this.lastSearchParams = searchParams
let root: TreeNode | null = this.baseRoot
let root: ShakeLayer['shackedRoot'] = this.baseRoot
if (searchParams) {
const { matchNode, onChildMatch } = searchParams
root = search(this.baseRoot, matchNode, onChildMatch)
@ -339,12 +339,22 @@ export class VisibleNodesGenerator extends FlattenLayer {
this.flattenHub.addEventListener('emit', () => this.update())
this.baseHub.addEventListener('loadingChange', () => this.update())
this.search(null)
}
onUpdate(callback: (visibleNodes: VisibleNodes) => void) {
return this.hub.addEventListener('emit', callback)
}
onNextUpdate(callback: (visibleNodes: VisibleNodes) => void) {
const oneTimeSubscription = (visibleNodes: VisibleNodes) => {
callback(visibleNodes)
this.hub.removeEventListener('emit', oneTimeSubscription)
}
return this.hub.addEventListener('emit', oneTimeSubscription)
}
update() {
this.hub.emit('emit', this.visibleNodes)
}