import { TFile, Vault } from 'obsidian'; import { IndexingQueue } from './indexQueue'; export class FileWatcher { private vault: Vault; private indexingQueue: IndexingQueue; private debounceTimeout: number | null = null; private debounceDelay = 300; // 300ms debounce private pendingFiles: Set = new Set(); constructor(vault: Vault, indexingQueue: IndexingQueue) { this.vault = vault; this.indexingQueue = indexingQueue; } /** * Start watching for file changes */ startWatching(): void { // Watch for file creation this.vault.on('create', (file) => { if (file instanceof TFile) { this.handleFileChange(file, 'create'); } }); // Watch for file modification this.vault.on('modify', (file) => { if (file instanceof TFile) { this.handleFileChange(file, 'update'); } }); // Watch for file deletion this.vault.on('delete', (file) => { if (file instanceof TFile) { this.handleFileChange(file, 'delete'); } }); // Watch for file renaming this.vault.on('rename', (file, oldPath) => { if (file instanceof TFile) { // Handle the old file as deleted this.handleFileChange(file, 'delete', oldPath); // Handle the new file as created this.handleFileChange(file, 'create'); } }); } /** * Stop watching for file changes */ stopWatching(): void { if (this.debounceTimeout) { clearTimeout(this.debounceTimeout); this.debounceTimeout = null; } this.pendingFiles.clear(); } /** * Handle file change with debouncing */ private handleFileChange(file: TFile, action: 'create' | 'update' | 'delete', oldPath?: string): void { const filePath = oldPath || file.path; // Add to pending files this.pendingFiles.add(filePath); // Clear existing timeout if (this.debounceTimeout) { clearTimeout(this.debounceTimeout); } // Set new timeout this.debounceTimeout = window.setTimeout(() => { this.processPendingFiles(); }, this.debounceDelay); } /** * Process all pending file changes */ private processPendingFiles(): void { if (this.pendingFiles.size === 0) { return; } const filesToProcess: TFile[] = []; for (const filePath of this.pendingFiles) { const file = this.vault.getAbstractFileByPath(filePath); if (file instanceof TFile) { filesToProcess.push(file); } } if (filesToProcess.length > 0) { // Add files to indexing queue this.indexingQueue.addFiles(filesToProcess, 'update'); // Start processing if not already running this.indexingQueue.startProcessing(); } // Clear pending files this.pendingFiles.clear(); } /** * Manually trigger indexing for specific files */ triggerIndexing(files: TFile[], action: 'create' | 'update' | 'delete' = 'update'): void { this.indexingQueue.addFiles(files, action); this.indexingQueue.startProcessing(); } /** * Get pending files count */ getPendingFilesCount(): number { return this.pendingFiles.size; } /** * Get pending files list */ getPendingFiles(): string[] { return Array.from(this.pendingFiles); } /** * Clear pending files */ clearPendingFiles(): void { this.pendingFiles.clear(); if (this.debounceTimeout) { clearTimeout(this.debounceTimeout); this.debounceTimeout = null; } } /** * Set debounce delay */ setDebounceDelay(delay: number): void { this.debounceDelay = delay; } /** * Get current debounce delay */ getDebounceDelay(): number { return this.debounceDelay; } }