diffstalker 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/.dependency-cruiser.cjs +2 -2
  2. package/dist/App.js +299 -664
  3. package/dist/KeyBindings.js +125 -39
  4. package/dist/ModalController.js +166 -0
  5. package/dist/MouseHandlers.js +43 -25
  6. package/dist/NavigationController.js +290 -0
  7. package/dist/StagingOperations.js +199 -0
  8. package/dist/config.js +39 -0
  9. package/dist/core/CompareManager.js +134 -0
  10. package/dist/core/ExplorerStateManager.js +27 -40
  11. package/dist/core/GitStateManager.js +28 -630
  12. package/dist/core/HistoryManager.js +72 -0
  13. package/dist/core/RemoteOperationManager.js +109 -0
  14. package/dist/core/WorkingTreeManager.js +412 -0
  15. package/dist/git/status.js +95 -0
  16. package/dist/index.js +59 -54
  17. package/dist/state/FocusRing.js +40 -0
  18. package/dist/state/UIState.js +82 -48
  19. package/dist/types/remote.js +5 -0
  20. package/dist/ui/PaneRenderers.js +11 -4
  21. package/dist/ui/modals/BaseBranchPicker.js +4 -7
  22. package/dist/ui/modals/CommitActionConfirm.js +66 -0
  23. package/dist/ui/modals/DiscardConfirm.js +4 -7
  24. package/dist/ui/modals/FileFinder.js +33 -27
  25. package/dist/ui/modals/HotkeysModal.js +32 -13
  26. package/dist/ui/modals/Modal.js +1 -0
  27. package/dist/ui/modals/RepoPicker.js +109 -0
  28. package/dist/ui/modals/ThemePicker.js +4 -7
  29. package/dist/ui/widgets/CommitPanel.js +52 -14
  30. package/dist/ui/widgets/CompareListView.js +1 -11
  31. package/dist/ui/widgets/DiffView.js +2 -27
  32. package/dist/ui/widgets/ExplorerContent.js +1 -4
  33. package/dist/ui/widgets/ExplorerView.js +1 -11
  34. package/dist/ui/widgets/FileList.js +2 -8
  35. package/dist/ui/widgets/Footer.js +1 -0
  36. package/dist/ui/widgets/Header.js +37 -3
  37. package/dist/utils/ansi.js +38 -0
  38. package/dist/utils/ansiTruncate.js +1 -5
  39. package/dist/utils/displayRows.js +72 -59
  40. package/dist/utils/fileCategories.js +7 -0
  41. package/dist/utils/fileResolution.js +23 -0
  42. package/dist/utils/languageDetection.js +3 -2
  43. package/dist/utils/logger.js +32 -0
  44. package/metrics/v0.2.3.json +243 -0
  45. package/metrics/v0.2.4.json +236 -0
  46. package/package.json +5 -2
  47. package/dist/utils/layoutCalculations.js +0 -100
@@ -2,6 +2,8 @@ import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
3
  import { EventEmitter } from 'node:events';
4
4
  import { getIgnoredFiles } from '../git/ignoreUtils.js';
5
+ import { listAllFiles } from '../git/status.js';
6
+ import * as logger from '../utils/logger.js';
5
7
  const MAX_FILE_SIZE = 1024 * 1024; // 1MB
6
8
  const WARN_FILE_SIZE = 100 * 1024; // 100KB
7
9
  /**
@@ -25,6 +27,7 @@ export class ExplorerStateManager extends EventEmitter {
25
27
  options;
26
28
  expandedPaths = new Set();
27
29
  gitStatusMap = { files: new Map(), directories: new Set() };
30
+ _cachedFilePaths = null;
28
31
  _state = {
29
32
  currentPath: '',
30
33
  tree: null,
@@ -61,9 +64,12 @@ export class ExplorerStateManager extends EventEmitter {
61
64
  }
62
65
  /**
63
66
  * Update git status map and refresh display.
67
+ * Also invalidates the file path cache so the next file finder open gets fresh data.
64
68
  */
65
69
  setGitStatus(statusMap) {
66
70
  this.gitStatusMap = statusMap;
71
+ // Invalidate file path cache — reload in background
72
+ this.loadFilePaths();
67
73
  // Refresh display to show updated status
68
74
  if (this._state.tree) {
69
75
  this.applyGitStatusToTree(this._state.tree);
@@ -153,7 +159,8 @@ export class ExplorerStateManager extends EventEmitter {
153
159
  }
154
160
  return node;
155
161
  }
156
- catch {
162
+ catch (err) {
163
+ logger.warn(`Failed to build tree node for ${relativePath}: ${err instanceof Error ? err.message : err}`);
157
164
  return null;
158
165
  }
159
166
  }
@@ -211,7 +218,8 @@ export class ExplorerStateManager extends EventEmitter {
211
218
  this.collapseNode(node, children);
212
219
  node.childrenLoaded = true;
213
220
  }
214
- catch {
221
+ catch (err) {
222
+ logger.warn(`Failed to read directory ${node.name}: ${err instanceof Error ? err.message : err}`);
215
223
  node.childrenLoaded = true;
216
224
  node.children = [];
217
225
  }
@@ -538,45 +546,24 @@ export class ExplorerStateManager extends EventEmitter {
538
546
  return search(this._state.tree);
539
547
  }
540
548
  /**
541
- * Get all file paths in the repo (for file finder).
542
- * Scans the filesystem directly to get all files, not just expanded ones.
549
+ * Load all file paths using git ls-files (fast, single git command).
550
+ * Stores result in cache for instant access by FileFinder.
543
551
  */
544
- async getAllFilePaths() {
545
- const paths = [];
546
- const scanDir = async (dirPath) => {
547
- try {
548
- const fullPath = path.join(this.repoPath, dirPath);
549
- const entries = await fs.promises.readdir(fullPath, { withFileTypes: true });
550
- // Build list of paths for gitignore check
551
- const pathsToCheck = entries.map((e) => (dirPath ? path.join(dirPath, e.name) : e.name));
552
- // Get ignored files
553
- const ignoredFiles = this.options.hideGitignored
554
- ? await getIgnoredFiles(this.repoPath, pathsToCheck)
555
- : new Set();
556
- for (const entry of entries) {
557
- // Filter dot-prefixed hidden files
558
- if (this.options.hideHidden && entry.name.startsWith('.')) {
559
- continue;
560
- }
561
- const entryPath = dirPath ? path.join(dirPath, entry.name) : entry.name;
562
- // Filter gitignored files
563
- if (this.options.hideGitignored && ignoredFiles.has(entryPath)) {
564
- continue;
565
- }
566
- if (entry.isDirectory()) {
567
- await scanDir(entryPath);
568
- }
569
- else {
570
- paths.push(entryPath);
571
- }
572
- }
573
- }
574
- catch {
575
- // Ignore errors for individual directories
576
- }
577
- };
578
- await scanDir('');
579
- return paths;
552
+ async loadFilePaths() {
553
+ try {
554
+ this._cachedFilePaths = await listAllFiles(this.repoPath);
555
+ }
556
+ catch (err) {
557
+ logger.warn(`Failed to load file paths: ${err instanceof Error ? err.message : err}`);
558
+ this._cachedFilePaths = [];
559
+ }
560
+ }
561
+ /**
562
+ * Get cached file paths (for file finder).
563
+ * Returns empty array if not yet loaded.
564
+ */
565
+ getCachedFilePaths() {
566
+ return this._cachedFilePaths ?? [];
580
567
  }
581
568
  /**
582
569
  * Navigate to a specific file path in the tree.