Theia filesystem extension providing comprehensive file operations, tree widgets, dialogs, and file system integration for IDE environments.
—
Resource abstraction for files providing content management, encoding detection, version control, and seamless integration with Theia's resource framework. Enables treating files as managed resources with automatic encoding handling and change tracking.
Core file resource implementation providing complete resource interface with file-specific functionality including encoding detection and conditional save operations.
/**
* File resource implementation with encoding and version management
*/
class FileResource implements Resource {
/** File URI */
readonly uri: URI;
/** Resource version information with encoding and timestamps */
readonly version: FileResourceVersion | undefined;
/** Detected or specified file encoding */
readonly encoding: string | undefined;
/** Whether file is read-only (boolean or MarkdownString with reason) */
readonly readOnly: boolean | MarkdownString;
/** Read entire file contents as string with encoding handling */
readContents(options?: { encoding?: string }): Promise<string>;
/** Read file contents as stream with encoding handling */
readStream(options?: { encoding?: string }): Promise<ReadableStream<string>>;
/** Detect file encoding using heuristics and BOM detection */
guessEncoding(): Promise<string>;
/** Save string content to file (available when not read-only) */
saveContents?: (content: string, options?: SaveOptions) => Promise<void>;
/** Save content stream to file (available when not read-only) */
saveStream?: (content: ReadableStream<string>, options?: SaveOptions) => Promise<void>;
/** Apply content changes to file (available when not read-only) */
saveContentChanges?: (changes: TextDocumentContentChangeEvent[], options?: SaveOptions) => Promise<void>;
/** Resource disposal for cleanup */
dispose(): void;
}Version information for file resources including encoding, modification time, and entity tags for change detection.
/**
* File resource version with encoding and timing information
*/
interface FileResourceVersion extends ResourceVersion {
/** Character encoding of the file */
readonly encoding: string;
/** Last modification time (Unix timestamp) */
readonly mtime: number;
/** Entity tag for change detection */
readonly etag: string;
}
interface ResourceVersion {
/** Unique version identifier */
readonly version: string;
}Service for resolving URIs to FileResource instances with proper lifecycle management and caching.
/**
* Resolver for creating FileResource instances from URIs
*/
@injectable()
class FileResourceResolver implements ResourceResolver {
/** Priority for this resolver (lower numbers = higher priority) */
readonly priority: number = -10;
/** Check if this resolver can handle the given URI */
canHandle(uri: URI): boolean;
/** Resolve URI to FileResource instance */
resolve(uri: URI): Promise<FileResource>;
/** Event fired when resources are created or disposed */
readonly onDidChangeContents: Event<URI>;
}Configuration options for save operations including encoding, backup, and formatting preferences.
/**
* Options for save operations
*/
interface SaveOptions {
/** Override encoding for this save operation */
encoding?: string;
/** Create backup before saving */
backup?: boolean;
/** Format document before saving */
format?: boolean;
/** Trim trailing whitespace */
trimTrailingWhitespace?: boolean;
/** Insert final newline if missing */
insertFinalNewline?: boolean;
/** Force save even if file hasn't changed */
force?: boolean;
}Change event types for incremental updates to file content.
/**
* Incremental content change event
*/
interface TextDocumentContentChangeEvent {
/** Range being replaced (undefined for full document changes) */
range?: Range;
/** Length of replaced text */
rangeLength?: number;
/** New text content */
text: string;
}
interface Range {
/** Starting position */
start: Position;
/** Ending position */
end: Position;
}
interface Position {
/** Line number (zero-based) */
line: number;
/** Character offset (zero-based) */
character: number;
}Utility functions and constants for character encoding detection and handling.
/**
* Common character encodings supported by FileResource
*/
enum Encoding {
UTF8 = 'utf8',
UTF16BE = 'utf16be',
UTF16LE = 'utf16le',
UTF32BE = 'utf32be',
UTF32LE = 'utf32le',
ASCII = 'ascii',
ISO88591 = 'iso88591',
WINDOWS1252 = 'windows1252'
}
/**
* Encoding detection result
*/
interface EncodingResult {
/** Detected encoding */
encoding: string;
/** Confidence level (0-1) */
confidence: number;
/** Whether BOM was detected */
hasBOM: boolean;
}
/**
* Detect encoding from binary data
*/
function detectEncoding(buffer: Uint8Array): EncodingResult;
/**
* Check if encoding is valid/supported
*/
function isValidEncoding(encoding: string): boolean;Usage Examples:
import { FileResource, FileResourceResolver } from "@theia/filesystem/lib/browser";
import { URI } from "@theia/core/lib/common/uri";
// Get resource resolver
const resolver = container.get(FileResourceResolver);
// Resolve file to resource
const fileUri = URI.parse('file:///workspace/src/main.ts');
const resource = await resolver.resolve(fileUri);
// Read file contents
const content = await resource.readContents();
console.log(`File content: ${content}`);
// Read with specific encoding
const contentUtf16 = await resource.readContents({ encoding: 'utf16le' });
// Check if file is read-only
if (typeof resource.readOnly === 'boolean' && !resource.readOnly) {
// File is writable
await resource.saveContents?.('console.log("Hello, World!");');
} else {
console.log('File is read-only');
if (typeof resource.readOnly !== 'boolean') {
console.log(`Reason: ${resource.readOnly.value}`);
}
}
// Stream reading for large files
const stream = await resource.readStream();
const reader = stream.getReader();
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
console.log('Chunk:', value);
}
} finally {
reader.releaseLock();
}
// Encoding detection
const encoding = await resource.guessEncoding();
console.log(`Detected encoding: ${encoding}`);
// Version information
if (resource.version) {
console.log(`Version: ${resource.version.version}`);
console.log(`Encoding: ${resource.version.encoding}`);
console.log(`Modified: ${new Date(resource.version.mtime)}`);
console.log(`ETag: ${resource.version.etag}`);
}
// Incremental updates
if (resource.saveContentChanges) {
await resource.saveContentChanges([{
range: { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } },
text: '// Added comment\n'
}]);
}
// Save with options
await resource.saveContents?.('new content', {
encoding: 'utf8',
trimTrailingWhitespace: true,
insertFinalNewline: true,
format: true
});
// Resource cleanup
resource.dispose();import { ResourceProvider, Resource } from "@theia/core/lib/common/resource";
// Working with resource provider
const resourceProvider = container.get(ResourceProvider);
// Get or create resource
const resource = await resourceProvider.get(fileUri);
// Listen for content changes
resource.onDidChangeContents(uri => {
console.log(`Resource changed: ${uri.toString()}`);
});
// Batch operations with multiple resources
const resources = await Promise.all([
resourceProvider.get(URI.parse('file:///file1.txt')),
resourceProvider.get(URI.parse('file:///file2.txt')),
resourceProvider.get(URI.parse('file:///file3.txt'))
]);
// Read all contents in parallel
const contents = await Promise.all(
resources.map(resource => resource.readContents())
);
// Save all with same options
const saveOptions = { trimTrailingWhitespace: true, insertFinalNewline: true };
await Promise.all(
resources.map((resource, index) =>
resource.saveContents?.(contents[index].toUpperCase(), saveOptions)
)
);
// Binary file handling
const binaryResource = await resourceProvider.get(URI.parse('file:///image.png'));
const binaryContent = await binaryResource.readContents({ encoding: 'binary' });// Custom resource with additional functionality
class CustomFileResource extends FileResource {
// Add custom metadata
async getCustomMetadata(): Promise<any> {
// Custom implementation
return {};
}
// Override encoding detection with custom logic
async guessEncoding(): Promise<string> {
// Custom encoding detection logic
const detected = await super.guessEncoding();
// Apply custom rules
if (this.uri.path.endsWith('.log')) {
return 'ascii'; // Force ASCII for log files
}
return detected;
}
// Add validation before save
async saveContents(content: string, options?: SaveOptions): Promise<void> {
// Validate content before saving
if (!this.validateContent(content)) {
throw new Error('Invalid content format');
}
return super.saveContents!(content, options);
}
private validateContent(content: string): boolean {
// Custom validation logic
return content.length > 0;
}
}Install with Tessl CLI
npx tessl i tessl/npm-theia--filesystem