Skip to main content

Workspace API

The Workspace API provides access to workspace folders, files, configuration, and file system operations. It’s the primary way to interact with the user’s project files and settings.

Namespace

vscode.workspace
All workspace-related functionality is available through the workspace namespace.

Workspace Folders

Accessing Workspace Folders

import * as vscode from 'vscode';

// Get all workspace folders
const folders = vscode.workspace.workspaceFolders;

if (folders && folders.length > 0) {
    folders.forEach(folder => {
        console.log('Folder name:', folder.name);
        console.log('Folder URI:', folder.uri.toString());
        console.log('Folder index:', folder.index);
    });
} else {
    console.log('No workspace folders open');
}
workspaceFolders
readonly WorkspaceFolder[] | undefined
Array of workspace folders or undefined if no workspace is open

WorkspaceFolder Interface

interface WorkspaceFolder {
    readonly uri: Uri;
    readonly name: string;
    readonly index: number;
}

Workspace Folder Events

// Workspace folders changed
vscode.workspace.onDidChangeWorkspaceFolders(event => {
    console.log('Added:', event.added);
    console.log('Removed:', event.removed);
});

Working with Files

Opening Documents

const uri = vscode.Uri.file('/path/to/file.txt');
const document = await vscode.workspace.openTextDocument(uri);

// Show in editor
await vscode.window.showTextDocument(document);

Finding Files

// Find all JavaScript files
const files = await vscode.workspace.findFiles(
    '**/*.js',           // include pattern
    '**/node_modules/**', // exclude pattern
    100                   // max results
);

for (const file of files) {
    console.log('Found:', file.fsPath);
}
include
GlobPattern
required
Glob pattern defining files to search for
exclude
GlobPattern | null
Glob pattern for exclusion (null = no excludes)
maxResults
number
Maximum number of results to return
token
CancellationToken
Cancellation token for the search operation

Relative Patterns

const folder = vscode.workspace.workspaceFolders?.[0];
if (folder) {
    // Search only in specific folder
    const pattern = new vscode.RelativePattern(folder, '*.ts');
    const files = await vscode.workspace.findFiles(pattern);
}

// Relative to a URI
const baseUri = vscode.Uri.file('/base/path');
const relPattern = new vscode.RelativePattern(baseUri, 'src/**/*.js');

File System Operations

Reading Files

const uri = vscode.Uri.file('/path/to/file.txt');

// Read as text (auto-detect encoding)
const content = await vscode.workspace.fs.readFile(uri);
const text = Buffer.from(content).toString('utf8');

// Or use workspace.decode
const decoded = await vscode.workspace.decode(content);

Writing Files

const uri = vscode.Uri.file('/path/to/file.txt');
const content = Buffer.from('Hello World', 'utf8');

// Write file
await vscode.workspace.fs.writeFile(uri, content);

// Or use workspace.encode
const encoded = await vscode.workspace.encode('Hello World');
await vscode.workspace.fs.writeFile(uri, encoded);

File Operations

// Create directory
const dirUri = vscode.Uri.file('/path/to/dir');
await vscode.workspace.fs.createDirectory(dirUri);

// Delete file
const fileUri = vscode.Uri.file('/path/to/file.txt');
await vscode.workspace.fs.delete(fileUri);

// Delete directory recursively
await vscode.workspace.fs.delete(dirUri, {
    recursive: true,
    useTrash: false
});

File System Watchers

Creating Watchers

// Watch for TypeScript file changes
const watcher = vscode.workspace.createFileSystemWatcher(
    '**/*.ts',
    false,  // ignoreCreateEvents
    false,  // ignoreChangeEvents
    false   // ignoreDeleteEvents
);

watcher.onDidCreate(uri => {
    console.log('File created:', uri.fsPath);
});

watcher.onDidChange(uri => {
    console.log('File changed:', uri.fsPath);
});

watcher.onDidDelete(uri => {
    console.log('File deleted:', uri.fsPath);
});

// Don't forget to dispose
context.subscriptions.push(watcher);
File watchers work across all workspace folders by default. Use RelativePattern to watch a specific folder.

Workspace-scoped Watcher

const folder = vscode.workspace.workspaceFolders?.[0];
if (folder) {
    const pattern = new vscode.RelativePattern(folder, 'src/**/*.js');
    const watcher = vscode.workspace.createFileSystemWatcher(pattern);
    
    watcher.onDidChange(uri => {
        console.log('Changed in workspace:', uri.fsPath);
    });
}

Configuration

Reading Configuration

// Get configuration for your extension
const config = vscode.workspace.getConfiguration('myExtension');

// Get values
const value = config.get('settingName', 'defaultValue');
const number = config.get<number>('timeout');

// Check if setting exists
if (config.has('settingName')) {
    console.log('Setting exists');
}
section
string
Configuration section (e.g., ‘editor’ or ‘myExtension.subSection’)
scope
ConfigurationScope
Scope for which to get configuration (resource, folder, language)

Updating Configuration

const config = vscode.workspace.getConfiguration('myExtension');

// Update in different scopes
await config.update(
    'settingName',
    'newValue',
    vscode.ConfigurationTarget.Global  // User settings
);

await config.update(
    'settingName',
    'workspaceValue',
    vscode.ConfigurationTarget.Workspace  // Workspace settings
);

await config.update(
    'settingName',
    'folderValue',
    vscode.ConfigurationTarget.WorkspaceFolder  // Folder settings
);

Configuration Inspection

const config = vscode.workspace.getConfiguration('editor');
const inspection = config.inspect('fontSize');

if (inspection) {
    console.log('Default value:', inspection.defaultValue);
    console.log('Global value:', inspection.globalValue);
    console.log('Workspace value:', inspection.workspaceValue);
    console.log('Folder value:', inspection.workspaceFolderValue);
}

Configuration Events

vscode.workspace.onDidChangeConfiguration(event => {
    // Check if specific section changed
    if (event.affectsConfiguration('myExtension.setting')) {
        console.log('My setting changed');
        
        // Re-read configuration
        const config = vscode.workspace.getConfiguration('myExtension');
        const newValue = config.get('setting');
    }
    
    // Check with scope
    const uri = vscode.window.activeTextEditor?.document.uri;
    if (uri && event.affectsConfiguration('editor.fontSize', uri)) {
        console.log('Font size changed for this document');
    }
});

Text Documents

Accessing Documents

// Get all open documents
const documents = vscode.workspace.textDocuments;

for (const doc of documents) {
    console.log('Open document:', doc.fileName);
    console.log('Language:', doc.languageId);
    console.log('Dirty:', doc.isDirty);
}

Document Events

vscode.workspace.onDidOpenTextDocument(document => {
    console.log('Opened:', document.fileName);
});

vscode.workspace.onDidCloseTextDocument(document => {
    console.log('Closed:', document.fileName);
});

Workspace Edit

Creating Edits

const edit = new vscode.WorkspaceEdit();

// Edit text in document
const uri = vscode.Uri.file('/path/to/file.txt');
edit.insert(uri, new vscode.Position(0, 0), 'Hello\n');
edit.replace(
    uri,
    new vscode.Range(1, 0, 1, 5),
    'World'
);
edit.delete(uri, new vscode.Range(2, 0, 3, 0));

// Apply the edit
const success = await vscode.workspace.applyEdit(edit);
console.log('Edit applied:', success);

File Operations in Edits

const edit = new vscode.WorkspaceEdit();

// Create file
const newFile = vscode.Uri.file('/path/to/new.txt');
edit.createFile(newFile, {
    overwrite: false,
    ignoreIfExists: true,
    contents: Buffer.from('Initial content')
});

// Delete file
const oldFile = vscode.Uri.file('/path/to/old.txt');
edit.deleteFile(oldFile, {
    recursive: false,
    ignoreIfNotExists: true
});

// Rename file
const sourceFile = vscode.Uri.file('/path/source.txt');
const targetFile = vscode.Uri.file('/path/target.txt');
edit.renameFile(sourceFile, targetFile, {
    overwrite: false
});

// Apply all changes atomically
await vscode.workspace.applyEdit(edit);

Edit Metadata

const edit = new vscode.WorkspaceEdit();

// Add metadata to edits
const metadata: vscode.WorkspaceEditEntryMetadata = {
    needsConfirmation: true,
    label: 'Refactor',
    description: 'Rename variable'
};

edit.replace(uri, range, newText, metadata);

// Mark as refactoring
const editMetadata: vscode.WorkspaceEditMetadata = {
    isRefactoring: true
};

await vscode.workspace.applyEdit(edit, editMetadata);

File Operations Events

Before Operations

vscode.workspace.onWillCreateFiles(event => {
    const files = event.files;  // URIs of files being created
    console.log('Will create:', files);
    
    // Provide additional edits
    event.waitUntil(
        Promise.resolve(new vscode.WorkspaceEdit())
    );
});

vscode.workspace.onWillDeleteFiles(event => {
    console.log('Will delete:', event.files);
});

vscode.workspace.onWillRenameFiles(event => {
    for (const file of event.files) {
        console.log('Rename:', file.oldUri, '->', file.newUri);
    }
});

After Operations

vscode.workspace.onDidCreateFiles(event => {
    console.log('Created:', event.files);
});

vscode.workspace.onDidDeleteFiles(event => {
    console.log('Deleted:', event.files);
});

vscode.workspace.onDidRenameFiles(event => {
    console.log('Renamed:', event.files);
});
These events are triggered by user gestures and workspace.applyEdit, but NOT by direct file system operations.

Text Encoding

Encoding and Decoding

// Decode bytes to string
const bytes = await vscode.workspace.fs.readFile(uri);
const text = await vscode.workspace.decode(bytes);

// Decode with specific encoding
const textUtf8 = await vscode.workspace.decode(bytes, {
    encoding: 'utf8'
});

// Decode with URI context
const textWithUri = await vscode.workspace.decode(bytes, {
    uri: documentUri
});

// Encode string to bytes
const encoded = await vscode.workspace.encode('Hello World');
const encodedUtf8 = await vscode.workspace.encode('Hello', {
    encoding: 'utf8'
});

Workspace Trust

// Check if workspace is trusted
if (vscode.workspace.isTrusted) {
    console.log('Workspace is trusted');
} else {
    console.log('Workspace is untrusted');
}

// Listen for trust changes
vscode.workspace.onDidGrantWorkspaceTrust(() => {
    console.log('Workspace was granted trust');
    // Re-initialize features that require trust
});

Common Patterns

Get Workspace Folder for File

const uri = vscode.Uri.file('/path/to/file.txt');
const folder = vscode.workspace.getWorkspaceFolder(uri);

if (folder) {
    console.log('File is in workspace folder:', folder.name);
}

Save All Files

// Save all dirty files
const success = await vscode.workspace.saveAll(false);

// Save all including untitled
await vscode.workspace.saveAll(true);

Open Folder in Workspace

const uri = vscode.Uri.file('/path/to/folder');

// Update workspace folders
const success = vscode.workspace.updateWorkspaceFolders(
    0,  // start index
    0,  // delete count
    { uri, name: 'New Folder' }
);

Best Practices

  • Use glob patterns to limit file searches
  • Cancel long-running operations with CancellationToken
  • Dispose file watchers when no longer needed
  • Batch file operations in WorkspaceEdit
  • Always check if workspace folders exist before accessing
  • Handle cases where files may not exist
  • Use try-catch for file system operations
  • Validate URIs before file operations
  • Show progress for long file operations
  • Use workspace edit for atomic changes
  • Respect user’s file encoding settings
  • Request confirmation for destructive operations