diff --git a/src/components/FileView.tsx b/src/components/FileView.tsx index 58b6a62c..04e1feb6 100644 --- a/src/components/FileView.tsx +++ b/src/components/FileView.tsx @@ -92,10 +92,47 @@ const FileView = observer(({ hide }: Props) => { } console.log('render!', { cursorIndex, cursor }) + const searchStringRef = React.useRef('') + const timeStampRef = React.useRef(0) + + // quick select + useKeyDown( + React.useCallback( + (event: KeyboardEvent) => { + let searchString = searchStringRef.current + // we only want to catch printable keys + if ( + !viewState.isActive || + !appState.isExplorer || + event.key.length !== 1 || + event.ctrlKey || + event.altKey || + event.metaKey + ) { + return + } + + // previous keyevent > 1sec ? + if (event.timeStamp - timeStampRef.current > 1000) searchString = '' + + // search_string += key + searchString += event.key + + // call select file marching search_string + if (searchString.length) cache.selectMatchingFile(searchString) + + searchStringRef.current = searchString + timeStampRef.current = event.timeStamp + }, + [cursor, cache, rowCount], + ), + ['*'], + ) + useKeyDown( React.useCallback( (event: KeyboardEvent) => { - if (!viewState.isActive) { + if (!viewState.isActive || !appState.isExplorer) { return } @@ -232,7 +269,7 @@ const FileView = observer(({ hide }: Props) => { global: true, combo: 'mod + i', label: t('SHORTCUT.ACTIVE_VIEW.SELECT_INVERT'), - onKeyDown: () => onInvertSelection(cache), + onKeyDown: () => isViewActive && onInvertSelection(cache), group: t('SHORTCUT.GROUP.ACTIVE_VIEW'), }, ...(!isMac || window.ENV.CY diff --git a/src/hooks/useKeyDown.ts b/src/hooks/useKeyDown.ts index 3c8e52cb..70bf298d 100644 --- a/src/hooks/useKeyDown.ts +++ b/src/hooks/useKeyDown.ts @@ -1,30 +1,9 @@ import { shouldCatchEvent } from '$src/utils/dom' import React from 'react' -// export const useKeyDown = (callback: (ev: KeyboardEvent) => void, keys: string[]) => { -// const onKeyDown = React.useCallback( -// (event: KeyboardEvent) => { -// const wasAnyKeyPressed = keys.some((key) => event.key === key) -// if (wasAnyKeyPressed && shouldCatchEvent(event)) { -// callback(event) -// } -// }, -// [callback, keys], -// ) - -// React.useEffect(() => { -// document.addEventListener('keydown', onKeyDown) -// return () => { -// document.removeEventListener('keydown', onKeyDown) -// debugger -// console.log('removing event listener') -// } -// }, [onKeyDown]) -// } - export function useKeyDown(callback: (ev: KeyboardEvent) => void, keys: string[]) { function handleKeyDown(event: KeyboardEvent) { - if (keys.includes(event.key) && shouldCatchEvent(event)) { + if ((keys.includes(event.key) || keys.includes('*')) && shouldCatchEvent(event)) { callback(event) } } diff --git a/src/state/fileState.ts b/src/state/fileState.ts index 13b288cd..3aafdf41 100644 --- a/src/state/fileState.ts +++ b/src/state/fileState.ts @@ -197,6 +197,7 @@ export class FileState { doLogin: action, clearSelection: action, invertSelection: action, + selectMatchingFile: action, reset: action, setSort: action, refreshSelection: action, @@ -472,6 +473,15 @@ export class FileState { } } + selectMatchingFile(str: string) { + // find first matching file (could be the same, we don't care) + const file = this.files.find((file) => file.name.toLowerCase().startsWith(str.toLowerCase())) + if (file) { + this.selected.replace([file]) + this.setCursor(this.selected[0]) + } + } + invertSelection() { if (this.selected.length === this.files.length) { this.selected.clear()