diff --git a/src/components/FileView.tsx b/src/components/FileView.tsx index 58b6a62c..a9edc530 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 } 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()