The FileWatcher class monitors the workspace for changes to .NET source files and project files, automatically triggering updates when changes are detected.
Class Overview
Location: /workspace/source/src/fileWatcher.ts:20
export class FileWatcher implements vscode.Disposable {
private watchers: vscode.FileSystemWatcher[];
private projectManager: DotNetProjectManager;
private debounceTimer: NodeJS.Timeout | undefined;
constructor(projectManager: DotNetProjectManager);
public dispose(): void;
}
Constructor
new FileWatcher(projectManager)
Creates a new file watcher instance and sets up file system monitoring.
constructor(projectManager: DotNetProjectManager)
projectManager
DotNetProjectManager
required
Instance of DotNetProjectManager to trigger updates
Initialization:
- Reads watch and exclude patterns from configuration
- Creates file system watchers for source files
- Creates watcher for project and solution files
- Registers event handlers for file changes
Example:
import { FileWatcher } from './fileWatcher';
import { DotNetProjectManager } from './dotnetProjectManager';
const projectManager = new DotNetProjectManager();
const fileWatcher = new FileWatcher(projectManager);
Public Methods
dispose
Cleans up all file watchers and timers.
Called When:
- Extension is deactivated
- File watcher needs to be recreated
- Cleaning up resources
Example Usage:
This method is automatically called by VS Code when the extension deactivates if the watcher is registered in context.subscriptions.
Monitored File Patterns
Source Files
By default, the following patterns are watched:
watchPatterns
string[]
default:"[\"**/*.cs\", \"**/*.fs\", \"**/*.vb\"]"
File patterns to monitor for changes
Configurable via: dotnetBuildBuddy.watchPatterns
Watched Events:
- File created (
onDidCreate)
- File changed (
onDidChange)
- File deleted (
onDidDelete)
Project Files
Automatically watches all project and solution files:
**/*.csproj
**/*.fsproj
**/*.vbproj
**/*.sln
Excluded Patterns
Patterns to exclude from watching
Configurable via: dotnetBuildBuddy.excludePatterns
Common Exclusions:
- Build output directories (
bin/, obj/)
- Dependencies (
node_modules/)
- IDE directories (
.vs/, .idea/)
Event Handling
Source File Changes
When a source file is created, modified, or deleted:
- Checks if auto-update is enabled (
dotnetBuildBuddy.autoUpdate)
- Verifies the file is not in an excluded pattern
- Logs the change
- Triggers debounced update
Implementation:
private onFileChange(uri: vscode.Uri): void {
const config = vscode.workspace.getConfiguration('dotnetBuildBuddy');
const autoUpdate = config.get<boolean>('autoUpdate', true);
if (!autoUpdate) {
return;
}
if (this.shouldIgnoreFile(uri.fsPath)) {
return;
}
this.debounceUpdate();
}
Project File Changes
When a project or solution file is modified:
- Logs the change
- Triggers debounced update
Implementation:
private onProjectFileChange(uri: vscode.Uri): void {
console.log(`DotNET Build Buddy: Project file changed: ${uri.fsPath}`);
this.debounceUpdate();
}
Debouncing
Why Debouncing?
File system events can fire rapidly (e.g., saving multiple files, IDE operations). Debouncing prevents excessive updates by waiting for activity to settle.
Debounce Delay: 1000ms (1 second)
debounceUpdate
private debounceUpdate(): void {
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
}
this.debounceTimer = setTimeout(async () => {
await this.projectManager.updateAllProjectFiles();
await this.projectManager.generateSolutionFile();
}, 1000);
}
Behavior:
- Cancels any pending update
- Starts a 1-second timer
- Updates project files when timer expires
- Regenerates solution file
- Handles errors gracefully
Example Flow:
File saved at T+0ms → Timer started (1000ms)
File saved at T+500ms → Timer reset (1000ms)
File saved at T+800ms → Timer reset (1000ms)
[No more changes]
T+1800ms → Update triggered
Configuration
Enable/Disable Auto-Update
dotnetBuildBuddy.autoUpdate
Automatically update project files when changes are detected
Effect: When false, the file watcher ignores all file changes.
Custom Watch Patterns
dotnetBuildBuddy.watchPatterns
string[]
default:"[\"**/*.cs\", \"**/*.fs\", \"**/*.vb\"]"
File patterns to watch for changes
Example:
{
"dotnetBuildBuddy.watchPatterns": [
"**/*.cs",
"**/*.fs",
"**/*.vb",
"**/*.cshtml",
"**/*.razor"
]
}
Custom Exclude Patterns
dotnetBuildBuddy.excludePatterns
Patterns to exclude from watching
Example:
{
"dotnetBuildBuddy.excludePatterns": [
"**/bin/**",
"**/obj/**",
"**/node_modules/**",
"**/.vs/**",
"**/TestResults/**"
]
}
Logging
The file watcher provides console logging for debugging:
Initialization:
DotNET Build Buddy: Setting up file watchers for patterns: **/*.cs, **/*.fs, **/*.vb
DotNET Build Buddy: Excluding patterns: **/bin/**, **/obj/**, **/node_modules/**
DotNET Build Buddy: File watchers initialized successfully
File Changes:
DotNET Build Buddy: Detected change in .NET source file: /workspace/src/Program.cs
DotNET Build Buddy: Triggering project file update...
DotNET Build Buddy: Project files and solution updated successfully
Excluded Files:
DotNET Build Buddy: Ignoring excluded file /workspace/obj/Debug/Program.cs
Disabled Auto-Update:
DotNET Build Buddy: Auto-update disabled, ignoring change to /workspace/src/Program.cs
Integration Example
Extension Activation
import * as vscode from 'vscode';
import { DotNetProjectManager } from './dotnetProjectManager';
import { FileWatcher } from './fileWatcher';
let projectManager: DotNetProjectManager;
let fileWatcher: FileWatcher;
export function activate(context: vscode.ExtensionContext) {
projectManager = new DotNetProjectManager();
fileWatcher = new FileWatcher(projectManager);
// Register for cleanup
context.subscriptions.push(fileWatcher);
vscode.window.showInformationMessage(
'DotNET Build Buddy is watching for changes!'
);
}
export function deactivate() {
if (fileWatcher) {
fileWatcher.dispose();
}
}
Manual Control
// Temporarily disable watching
const config = vscode.workspace.getConfiguration('dotnetBuildBuddy');
await config.update('autoUpdate', false, vscode.ConfigurationTarget.Workspace);
// Perform operations...
// Re-enable watching
await config.update('autoUpdate', true, vscode.ConfigurationTarget.Workspace);
Error Handling
The file watcher includes error handling for update operations:
try {
await this.projectManager.updateAllProjectFiles();
await this.projectManager.generateSolutionFile();
console.log('Project files and solution updated successfully');
} catch (error) {
console.error('Error updating project files:', error);
vscode.window.showErrorMessage(
`DotNET Build Buddy: Failed to update project files: ${error}`
);
}
Error Scenarios:
- File system permission errors
- Malformed project files
- Network errors (NuGet API lookups)
- Invalid XML in project files
Best Practices for Large Projects:
- Add build directories to exclude patterns
- Increase debounce delay if needed
- Consider disabling auto-update during bulk operations
- Use specific watch patterns instead of broad globs
Memory Usage:
- Each file system watcher consumes minimal memory
- Debounce timer is cleaned up properly
- Watchers are disposed when no longer needed
CPU Usage:
- File events are asynchronous and non-blocking
- Updates only run after debounce period
- NuGet checks can be disabled if not needed
Lifecycle
- Creation (
constructor): Watchers are set up based on configuration
- Active Monitoring: File events trigger debounced updates
- Disposal (
dispose): All watchers and timers are cleaned up
const lifecycle = {
create: () => new FileWatcher(projectManager),
monitor: () => {
// Automatic - handled by VS Code
},
cleanup: (watcher) => watcher.dispose()
};
Always call dispose() when the file watcher is no longer needed to prevent memory leaks. Register the watcher in context.subscriptions for automatic cleanup.