Theia filesystem extension providing comprehensive file operations, tree widgets, dialogs, and file system integration for IDE environments.
—
User preference management for file operations, encoding, watching, exclusions, and behavior customization. Provides comprehensive configuration options for tailoring filesystem behavior to user needs and system requirements.
Complete configuration schema for all filesystem-related user preferences with sensible defaults and validation.
/**
* User preferences schema for filesystem behavior
*/
interface FileSystemConfiguration {
/** Glob patterns to exclude from file watching */
'files.watcherExclude': { [globPattern: string]: boolean };
/** Glob patterns to exclude from file listings */
'files.exclude': { [key: string]: boolean };
/** Enable trash/recycle bin for delete operations */
'files.enableTrash': boolean;
/** File pattern to language associations */
'files.associations': { [filepattern: string]: string };
/** Default character encoding for files */
'files.encoding': string;
/** Automatically detect file encoding */
'files.autoGuessEncoding': boolean;
/** Timeout for file operation participants (milliseconds) */
'files.participants.timeout': number;
/** Maximum file size to open in MB */
'files.maxFileSizeMB': number;
/** Trim trailing whitespace on save */
'files.trimTrailingWhitespace': boolean;
/** Insert final newline on save */
'files.insertFinalNewline': boolean;
/** Maximum concurrent file uploads */
'files.maxConcurrentUploads': number;
}Platform-specific constants and default values for filesystem preferences.
/** Windows file size limit (300 MB) */
const WIN32_MAX_FILE_SIZE_MB: number = 300;
/** General file size limit (16 GB) */
const GENERAL_MAX_FILE_SIZE_MB: number = 16 * 1024;
/** Platform-dependent file size limit */
const MAX_FILE_SIZE_MB: number = isWindows ? WIN32_MAX_FILE_SIZE_MB : GENERAL_MAX_FILE_SIZE_MB;
/** Default encoding for text files */
const DEFAULT_ENCODING: string = 'utf8';
/** Default watcher excludes */
const DEFAULT_WATCHER_EXCLUDES: { [pattern: string]: boolean } = {
'**/.git/**': true,
'**/node_modules/**': true,
'**/.DS_Store': true,
'**/Thumbs.db': true
};
/** Default file excludes */
const DEFAULT_FILE_EXCLUDES: { [pattern: string]: boolean } = {
'**/.git': true,
'**/.svn': true,
'**/.hg': true,
'**/CVS': true,
'**/.DS_Store': true,
'**/Thumbs.db': true
};Type-safe preference accessor providing strongly-typed access to filesystem configuration values.
/**
* Type-safe filesystem preferences accessor
*/
type FileSystemPreferences = {
/** Get watcher exclude patterns */
'files.watcherExclude': PreferenceProxy<{ [globPattern: string]: boolean }>;
/** Get file exclude patterns */
'files.exclude': PreferenceProxy<{ [key: string]: boolean }>;
/** Get trash enabled setting */
'files.enableTrash': PreferenceProxy<boolean>;
/** Get file associations */
'files.associations': PreferenceProxy<{ [filepattern: string]: string }>;
/** Get default encoding */
'files.encoding': PreferenceProxy<string>;
/** Get auto-guess encoding setting */
'files.autoGuessEncoding': PreferenceProxy<boolean>;
/** Get participants timeout */
'files.participants.timeout': PreferenceProxy<number>;
/** Get max file size */
'files.maxFileSizeMB': PreferenceProxy<number>;
/** Get trim whitespace setting */
'files.trimTrailingWhitespace': PreferenceProxy<boolean>;
/** Get insert final newline setting */
'files.insertFinalNewline': PreferenceProxy<boolean>;
/** Get max concurrent uploads */
'files.maxConcurrentUploads': PreferenceProxy<number>;
};
/**
* Preference proxy for reactive value access
*/
interface PreferenceProxy<T> {
/** Current preference value */
readonly value: T;
/** Event fired when preference changes */
readonly onDidChange: Event<PreferenceChange>;
/** Get preference value with fallback */
get(fallback?: T): T;
/** Set preference value */
set(value: T): Promise<void>;
/** Reset preference to default */
reset(): Promise<void>;
}Utility functions for creating and managing filesystem preferences with proper dependency injection integration.
/**
* Create filesystem preferences from preference service
*/
function createFileSystemPreferences(
preferences: PreferenceService,
schema?: PreferenceSchema
): FileSystemPreferences;
/**
* Bind filesystem preferences to dependency injection container
*/
function bindFileSystemPreferences(bind: interfaces.Bind): void;
/**
* Get filesystem preference schema definition
*/
function getFileSystemPreferenceSchema(): PreferenceSchema;
/**
* Validate filesystem preferences
*/
function validateFileSystemPreferences(config: Partial<FileSystemConfiguration>): ValidationResult;
interface ValidationResult {
/** Whether configuration is valid */
valid: boolean;
/** Validation errors */
errors: string[];
/** Sanitized configuration */
sanitized: FileSystemConfiguration;
}Event system for reacting to preference changes with detailed change information.
/**
* Preference change event
*/
interface PreferenceChange {
/** Preference key that changed */
readonly key: string;
/** New preference value */
readonly newValue: any;
/** Previous preference value */
readonly oldValue: any;
/** Configuration scope (user, workspace, etc.) */
readonly scope: PreferenceScope;
}
enum PreferenceScope {
User = 'user',
Workspace = 'workspace',
Folder = 'folder'
}Usage Examples:
import {
FileSystemPreferences,
createFileSystemPreferences,
bindFileSystemPreferences
} from "@theia/filesystem/lib/browser";
import { PreferenceService } from "@theia/core/lib/browser/preferences";
// Get preferences instance
const preferenceService = container.get(PreferenceService);
const fsPreferences = createFileSystemPreferences(preferenceService);
// Access preference values
const encoding = fsPreferences['files.encoding'].value;
console.log(`Default encoding: ${encoding}`);
const maxFileSize = fsPreferences['files.maxFileSizeMB'].value;
console.log(`Max file size: ${maxFileSize} MB`);
const trashEnabled = fsPreferences['files.enableTrash'].value;
console.log(`Trash enabled: ${trashEnabled}`);
// Get with fallback
const timeout = fsPreferences['files.participants.timeout'].get(30000);
// React to preference changes
fsPreferences['files.encoding'].onDidChange(change => {
console.log(`Encoding changed from ${change.oldValue} to ${change.newValue}`);
});
fsPreferences['files.watcherExclude'].onDidChange(change => {
console.log('Watcher excludes updated:', change.newValue);
// Update file watchers with new excludes
updateFileWatchers(change.newValue);
});
// Set preference values
await fsPreferences['files.encoding'].set('utf16le');
await fsPreferences['files.trimTrailingWhitespace'].set(true);
await fsPreferences['files.insertFinalNewline'].set(true);
// Working with complex preferences
const watcherExcludes = fsPreferences['files.watcherExclude'].value;
console.log('Current watcher excludes:');
for (const [pattern, enabled] of Object.entries(watcherExcludes)) {
if (enabled) {
console.log(` ${pattern}`);
}
}
// Update complex preferences
const newExcludes = {
...watcherExcludes,
'**/coverage/**': true,
'**/dist/**': true
};
await fsPreferences['files.watcherExclude'].set(newExcludes);
// File associations
const associations = fsPreferences['files.associations'].value;
console.log('File associations:', associations);
// Add new association
const newAssociations = {
...associations,
'*.config': 'json',
'*.log': 'plaintext'
};
await fsPreferences['files.associations'].set(newAssociations);
// Reset preference to default
await fsPreferences['files.maxFileSizeMB'].reset();
// Check if file should be excluded
function isFileExcluded(filePath: string): boolean {
const excludes = fsPreferences['files.exclude'].value;
for (const [pattern, enabled] of Object.entries(excludes)) {
if (enabled && minimatch(filePath, pattern)) {
return true;
}
}
return false;
}
// Check if path should be watched
function shouldWatchPath(filePath: string): boolean {
const excludes = fsPreferences['files.watcherExclude'].value;
for (const [pattern, enabled] of Object.entries(excludes)) {
if (enabled && minimatch(filePath, pattern)) {
return false;
}
}
return true;
}import { ContainerModule } from 'inversify';
import { bindFileSystemPreferences } from "@theia/filesystem/lib/browser";
// In your Theia extension module
export default new ContainerModule(bind => {
// Bind filesystem preferences
bindFileSystemPreferences(bind);
// Other bindings...
});
// Usage in a service
@injectable()
class FileService {
constructor(
@inject(FileSystemPreferences) private readonly preferences: FileSystemPreferences
) {}
async readFile(uri: URI): Promise<string> {
const encoding = this.preferences['files.encoding'].value;
const maxSize = this.preferences['files.maxFileSizeMB'].value * 1024 * 1024;
// Use preferences in file operations
// ...
}
}// Custom preference validation
class FileSystemPreferenceValidator {
validate(config: Partial<FileSystemConfiguration>): ValidationResult {
const errors: string[] = [];
// Validate encoding
if (config['files.encoding'] && !this.isValidEncoding(config['files.encoding'])) {
errors.push(`Invalid encoding: ${config['files.encoding']}`);
}
// Validate file size
if (config['files.maxFileSizeMB'] && config['files.maxFileSizeMB'] <= 0) {
errors.push('Max file size must be positive');
}
// Validate timeout
if (config['files.participants.timeout'] && config['files.participants.timeout'] < 0) {
errors.push('Timeout cannot be negative');
}
return {
valid: errors.length === 0,
errors,
sanitized: this.sanitize(config)
};
}
private isValidEncoding(encoding: string): boolean {
const validEncodings = ['utf8', 'utf16le', 'utf16be', 'ascii', 'latin1'];
return validEncodings.includes(encoding.toLowerCase());
}
private sanitize(config: Partial<FileSystemConfiguration>): FileSystemConfiguration {
// Return sanitized configuration with defaults
return {
'files.watcherExclude': config['files.watcherExclude'] || DEFAULT_WATCHER_EXCLUDES,
'files.exclude': config['files.exclude'] || DEFAULT_FILE_EXCLUDES,
'files.enableTrash': config['files.enableTrash'] ?? true,
'files.associations': config['files.associations'] || {},
'files.encoding': config['files.encoding'] || DEFAULT_ENCODING,
'files.autoGuessEncoding': config['files.autoGuessEncoding'] ?? false,
'files.participants.timeout': config['files.participants.timeout'] || 60000,
'files.maxFileSizeMB': config['files.maxFileSizeMB'] || MAX_FILE_SIZE_MB,
'files.trimTrailingWhitespace': config['files.trimTrailingWhitespace'] ?? false,
'files.insertFinalNewline': config['files.insertFinalNewline'] ?? false,
'files.maxConcurrentUploads': config['files.maxConcurrentUploads'] || 5
};
}
}
// Preference migration
class FileSystemPreferenceMigrator {
migrate(oldPreferences: any): FileSystemConfiguration {
// Migrate old preference format to new format
return {
'files.watcherExclude': this.migrateExcludes(oldPreferences.watcherExclude),
'files.exclude': this.migrateExcludes(oldPreferences.exclude),
// ... other migrations
};
}
private migrateExcludes(oldExcludes: string[] | { [key: string]: boolean }): { [key: string]: boolean } {
if (Array.isArray(oldExcludes)) {
// Convert array format to object format
return oldExcludes.reduce((obj, pattern) => {
obj[pattern] = true;
return obj;
}, {} as { [key: string]: boolean });
}
return oldExcludes || {};
}
}Install with Tessl CLI
npx tessl i tessl/npm-theia--filesystem