From 66312dbc0ff341a3f2738cb10e602df9b06d7419 Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Thu, 4 Feb 2021 21:09:09 +0800 Subject: [PATCH] fix: go to file, highlighting --- src/components/FileExplorer.tsx | 25 ++++++++++---------- src/components/SearchBar.tsx | 2 +- src/components/searchModes/fuzzyMode.tsx | 29 ++++++++++++++---------- src/driver/core/FileExplorer.ts | 13 +++++------ src/utils/VisibleNodesGenerator.ts | 14 ++++++++++-- 5 files changed, 48 insertions(+), 35 deletions(-) diff --git a/src/components/FileExplorer.tsx b/src/components/FileExplorer.tsx index d6c0b98..dea1a9d 100644 --- a/src/components/FileExplorer.tsx +++ b/src/components/FileExplorer.tsx @@ -49,11 +49,15 @@ const RawFileExplorer: React.FC = 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 = function RawFileExplor config: { compressSingletonFolder, accessToken, - searchMode, }, }) } @@ -95,7 +98,7 @@ const RawFileExplorer: React.FC = function RawFileExplor onClick={e => { e.stopPropagation() e.preventDefault() - updateSearchKey(node.path + '/') + onSearch(node.path + '/') }} > @@ -109,7 +112,7 @@ const RawFileExplorer: React.FC = function RawFileExplor return renders.length ? node => renders.map((render, i) => {render(node)}) : 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 = function RawFileExplor visibleNodes && renderNodeContext && ( <> - updateSearchKey(value)} - onFocus={onFocusSearchBar} - /> + {searched && visibleNodes.nodes.length === 0 && ( <> diff --git a/src/components/SearchBar.tsx b/src/components/SearchBar.tsx index 5af0649..81e2e73 100644 --- a/src/components/SearchBar.tsx +++ b/src/components/SearchBar.tsx @@ -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" > diff --git a/src/components/searchModes/fuzzyMode.tsx b/src/components/searchModes/fuzzyMode.tsx index 6150485..efcb454 100644 --- a/src/components/searchModes/fuzzyMode.tsx +++ b/src/components/searchModes/fuzzyMode.tsx @@ -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 ( - - {index + 1 !== chunks.length && '/'} - , + + ) }) - return result }, } diff --git a/src/driver/core/FileExplorer.ts b/src/driver/core/FileExplorer.ts index c650eda..968affb 100644 --- a/src/driver/core/FileExplorer.ts +++ b/src/driver/core/FileExplorer.ts @@ -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 = MethodCreator> & { - config: Pick + config: Pick }, ] > = 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 ( diff --git a/src/utils/VisibleNodesGenerator.ts b/src/utils/VisibleNodesGenerator.ts index 96eafe4..c14c234 100644 --- a/src/utils/VisibleNodesGenerator.ts +++ b/src/utils/VisibleNodesGenerator.ts @@ -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) }