Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
keyboardHotkeys.ts141 linesDownload Raw Back to services
1import { Notificar } from 'notificar';2import { FileEntry, Directory, FileType } from 'react-aspen';3import { FileTreeXEvent, IFileTreeXHandle } from '../types';4 5export class KeyboardHotkeys {6  private hotkeyActions = {7    'ArrowUp': () => this.jumpToPrevItem(),8    'ArrowDown': () => this.jumpToNextItem(),9    'ArrowRight': () => this.expandOrJumpToFirstChild(),10    'ArrowLeft': () => this.collapseOrJumpToFirstParent(),11    'Space': () => this.toggleDirectoryExpand(),12    'Enter': () => this.selectFileOrToggleDirState(),13    'Home': () => this.jumpToFirstItem(),14    'End': () => this.jumpToLastItem(),15    'Escape': () => this.resetSteppedOrSelectedItem(),16    'Ctrl+KeyC': () => this.copyEntry(),17  };18 19  constructor(private readonly fileTreeX: IFileTreeXHandle, private readonly events: Notificar<FileTreeXEvent>) { }20 21  public handleKeyDown = (ev: React.KeyboardEvent) => {22    if (!this.fileTreeX.hasDirectFocus()) {23      return false;24    }25    let { code } = ev.nativeEvent;26 27    if((ev.nativeEvent.ctrlKey || ev.nativeEvent.metaKey) && ev.nativeEvent.key !== 'Control') {28      code = `Ctrl+${code}`;29    }30    if (code in this.hotkeyActions) {31      ev.preventDefault();32      this.hotkeyActions[code]();33      return true;34    }35  };36 37  private jumpToFirstItem = (): void => {38    const { root } = this.fileTreeX.getModel();39    this.fileTreeX.setActiveFile(root.getFileEntryAtIndex(0), true);40  };41 42  private jumpToLastItem = (): void => {43    const { root } = this.fileTreeX.getModel();44    this.fileTreeX.setActiveFile(root.getFileEntryAtIndex(root.branchSize - 1), true);45  };46 47  private jumpToNextItem = (): void => {48    const { root } = this.fileTreeX.getModel();49    let currentPseudoActive = this.fileTreeX.getActiveFile();50    if (!currentPseudoActive) {51      const selectedFile = this.fileTreeX.getActiveFile();52      if (selectedFile) {53        currentPseudoActive = selectedFile;54      } else {55        return this.jumpToFirstItem();56      }57    }58    const idx = root.getIndexAtFileEntry(currentPseudoActive);59    if (idx + 1 > root.branchSize) {60      return this.jumpToFirstItem();61    } else if (idx > -1) {62      this.fileTreeX.setActiveFile(root.getFileEntryAtIndex(idx + 1), true);63    }64  };65 66  private jumpToPrevItem = (): void => {67    const { root } = this.fileTreeX.getModel();68    let currentPseudoActive = this.fileTreeX.getActiveFile();69    if (!currentPseudoActive) {70      const selectedFile = this.fileTreeX.getActiveFile();71      if (selectedFile) {72        currentPseudoActive = selectedFile;73      } else {74        return this.jumpToLastItem();75      }76    }77    const idx = root.getIndexAtFileEntry(currentPseudoActive);78    if (idx - 1 < 0) {79      return this.jumpToLastItem();80    } else if (idx > -1) {81      this.fileTreeX.setActiveFile(root.getFileEntryAtIndex(idx - 1), true);82    }83  };84 85  private expandOrJumpToFirstChild(): void {86    const currentPseudoActive = this.fileTreeX.getActiveFile();87    if (currentPseudoActive && currentPseudoActive.type === FileType.Directory) {88      if ((currentPseudoActive as Directory).expanded) {89        return this.jumpToNextItem();90      } else {91        this.fileTreeX.openDirectory(currentPseudoActive as Directory);92      }93    }94  }95 96  private collapseOrJumpToFirstParent(): void {97    const currentPseudoActive = this.fileTreeX.getActiveFile();98    if (currentPseudoActive) {99      if (currentPseudoActive.type === FileType.Directory && (currentPseudoActive as Directory).expanded) {100        return this.fileTreeX.closeDirectory(currentPseudoActive as Directory);101      }102      this.fileTreeX.setActiveFile(currentPseudoActive.parent, true);103    }104  }105 106  private selectFileOrToggleDirState = (): void => {107    const currentPseudoActive = this.fileTreeX.getActiveFile();108    if (!currentPseudoActive) { return; }109    if (currentPseudoActive.type === FileType.Directory) {110      this.fileTreeX.toggleDirectory(currentPseudoActive as Directory);111    } else if (currentPseudoActive.type === FileType.File) {112      this.fileTreeX.setActiveFile(currentPseudoActive as FileEntry, true);113    }114  };115 116  private toggleDirectoryExpand = (): void => {117    const currentPseudoActive = this.fileTreeX.getActiveFile();118    if (!currentPseudoActive) { return; }119    if (currentPseudoActive.type === FileType.Directory) {120      this.fileTreeX.toggleDirectory(currentPseudoActive as Directory);121    }122  };123 124  private resetSteppedOrSelectedItem = (): void => {125    const currentPseudoActive = this.fileTreeX.getActiveFile();126    if (currentPseudoActive) {127      return this.resetSteppedItem();128    }129    this.fileTreeX.setActiveFile(null);130  };131 132  private resetSteppedItem = () => {133    this.fileTreeX.setActiveFile(null);134  };135 136  private copyEntry = () => {137    const currentPseudoActive = this.fileTreeX.getActiveFile();138    this.events.dispatch(FileTreeXEvent.onTreeEvents, null, 'copied', currentPseudoActive);139  };140}141 
codekingpro/portable-devtools · Team Ai