# VS Code Extension API 核心知识点 ## 目录 - [1. Extension 生命周期](#1-extension-生命周期) ⭐⭐⭐ - [2. 激活事件 (Activation Events)](#2-激活事件-activation-events) ⭐⭐ - [3. 命令系统 (Commands)](#3-命令系统-commands) ⭐⭐ - [4. Webview API](#4-webview-api) ⭐⭐⭐⭐⭐ **面试重点** - [5. TreeView 和自定义视图](#5-treeview-和自定义视图) ⭐⭐ - [6. 文件系统操作](#6-文件系统操作) ⭐⭐⭐ - [7. 配置和存储](#7-配置和存储) ⭐⭐⭐⭐ **面试重点** - [8. 消息通知](#8-消息通知) ⭐ - [9. 语言特性支持](#9-语言特性支持) ⭐ - [10. 调试和诊断](#10-调试和诊断) ⭐ --- ## 1. Extension 生命周期 ⭐⭐⭐ ### 1.1 核心函数 🔥必考 ```typescript // extension.ts import * as vscode from 'vscode'; // 插件激活时调用(只调用一次) export function activate(context: vscode.ExtensionContext) { console.log('Extension is now active!'); // 注册命令、视图、事件监听等 // 使用 context.subscriptions 管理资源 } // 插件停用时调用(清理资源) export function deactivate() { console.log('Extension is deactivated'); // 清理资源、关闭连接等 } ``` ### 1.2 ExtensionContext 重要属性 🔥必考 ```typescript interface ExtensionContext { // 插件订阅管理(自动清理) subscriptions: { dispose(): any }[]; // 工作区存储路径 storageUri: vscode.Uri | undefined; globalStorageUri: vscode.Uri; // 插件路径 extensionUri: vscode.Uri; extensionPath: string; // 状态存储 workspaceState: Memento; // 工作区级别 globalState: Memento; // 全局级别 secrets: SecretStorage; // 敏感信息存储 // 环境变量 environmentVariableCollection: EnvironmentVariableCollection; } ``` ### 1.3 资源管理最佳实践 🔥必考 ```typescript export function activate(context: vscode.ExtensionContext) { // ✅ 推荐:使用 context.subscriptions 自动管理 context.subscriptions.push( vscode.commands.registerCommand('extension.command', () => {}) ); // ❌ 不推荐:手动管理容易忘记清理 const disposable = vscode.commands.registerCommand('extension.command', () => {}); // 需要在 deactivate 中手动调用 disposable.dispose() } ``` --- ## 2. 激活事件 (Activation Events) ⭐⭐ ### 2.1 常用激活事件 📌重要 ```json // package.json { "activationEvents": [ // 启动时激活 "onStartupFinished", // 执行命令时激活 "onCommand:extension.helloWorld", // 打开特定语言文件时激活 "onLanguage:javascript", "onLanguage:verilog", // 打开特定文件类型时激活 "onFileSystem:sftp", // 打开特定视图时激活 "onView:myCustomView", // 调试时激活 "onDebug", // 打开特定 URI 时激活 "onUri", // Webview 恢复时激活 "onWebviewPanel:myWebview", // 任务执行时激活 "onTaskType:npm" ] } ``` ### 2.2 延迟激活策略 🔥必考 ```typescript // ✅ 推荐:使用 onStartupFinished 延迟激活 "activationEvents": ["onStartupFinished"] // ❌ 不推荐:使用 * 会拖慢启动速度 "activationEvents": ["*"] ``` --- ## 3. 命令系统 (Commands) ### 3.1 注册命令 ```typescript // 注册简单命令 const disposable = vscode.commands.registerCommand( 'extension.helloWorld', () => { vscode.window.showInformationMessage('Hello World!'); } ); context.subscriptions.push(disposable); // 注册带参数的命令 vscode.commands.registerCommand( 'extension.openFile', (filePath: string) => { vscode.workspace.openTextDocument(filePath).then(doc => { vscode.window.showTextDocument(doc); }); } ); ``` ### 3.2 执行命令 ```typescript // 执行内置命令 await vscode.commands.executeCommand('workbench.action.files.save'); // 执行自定义命令 await vscode.commands.executeCommand('extension.openFile', '/path/to/file'); // 获取所有可用命令 const commands = await vscode.commands.getCommands(); ``` ### 3.3 常用内置命令 ```typescript // 文件操作 'workbench.action.files.save' 'workbench.action.files.saveAll' 'workbench.action.closeActiveEditor' // 编辑器操作 'editor.action.formatDocument' 'editor.action.commentLine' 'editor.action.selectAll' // 窗口操作 'workbench.action.toggleSidebarVisibility' 'workbench.action.terminal.new' 'workbench.action.quickOpen' // Git 操作 'git.commit' 'git.push' 'git.pull' ``` --- ## 4. Webview API ⭐⭐⭐⭐⭐ **面试重点** ### 4.1 创建 Webview Panel 🔥必考 ```typescript const panel = vscode.window.createWebviewPanel( 'myWebview', // viewType(唯一标识) 'My Webview', // 标题 vscode.ViewColumn.One, // 显示位置 { enableScripts: true, // 启用 JavaScript retainContextWhenHidden: true, // 隐藏时保留状态 localResourceRoots: [ // 允许访问的本地资源路径 vscode.Uri.joinPath(context.extensionUri, 'media') ] } ); ``` ### 4.2 设置 Webview 内容 ```typescript panel.webview.html = getWebviewContent(); function getWebviewContent() { return ` My Webview

Hello from Webview!

`; } ``` ### 4.3 Webview 消息通信 🔥必考(项目核心) ```typescript // Extension → Webview panel.webview.postMessage({ command: 'update', data: 'some data' }); // Webview → Extension panel.webview.onDidReceiveMessage( message => { switch (message.command) { case 'alert': vscode.window.showInformationMessage(message.text); break; case 'getData': // 处理数据请求 panel.webview.postMessage({ command: 'dataResponse', data: fetchData() }); break; } }, undefined, context.subscriptions ); ``` ### 4.4 Webview 生命周期管理 📌重要 ```typescript // 监听 Webview 关闭事件 panel.onDidDispose( () => { // 清理资源 console.log('Webview disposed'); }, null, context.subscriptions ); // 监听 Webview 可见性变化 panel.onDidChangeViewState( e => { if (e.webviewPanel.visible) { console.log('Webview is now visible'); } }, null, context.subscriptions ); ``` ### 4.5 加载本地资源 📌重要 ```typescript // 获取本地资源 URI const scriptUri = panel.webview.asWebviewUri( vscode.Uri.joinPath(context.extensionUri, 'media', 'script.js') ); const styleUri = panel.webview.asWebviewUri( vscode.Uri.joinPath(context.extensionUri, 'media', 'style.css') ); // 在 HTML 中使用 const html = ` `; ``` ### 4.6 Webview 状态持久化 📌重要 ```typescript // Webview 中保存状态 const vscode = acquireVsCodeApi(); const state = vscode.getState() || { count: 0 }; // 更新状态 state.count++; vscode.setState(state); // Extension 中序列化状态 panel.webview.options = { enableScripts: true, retainContextWhenHidden: true }; // 恢复 Webview vscode.window.registerWebviewPanelSerializer('myWebview', { async deserializeWebviewPanel(webviewPanel, state) { webviewPanel.webview.html = getWebviewContent(); // 恢复状态 webviewPanel.webview.postMessage({ command: 'restore', state }); } }); ``` --- ## 5. TreeView 和自定义视图 ### 5.1 创建 TreeView Provider ```typescript class MyTreeDataProvider implements vscode.TreeDataProvider { private _onDidChangeTreeData = new vscode.EventEmitter(); readonly onDidChangeTreeData = this._onDidChangeTreeData.event; refresh(): void { this._onDidChangeTreeData.fire(undefined); } getTreeItem(element: TreeItem): vscode.TreeItem { return element; } getChildren(element?: TreeItem): Thenable { if (!element) { // 返回根节点 return Promise.resolve([ new TreeItem('Item 1', vscode.TreeItemCollapsibleState.None), new TreeItem('Item 2', vscode.TreeItemCollapsibleState.Collapsed) ]); } // 返回子节点 return Promise.resolve([]); } } class TreeItem extends vscode.TreeItem { constructor( public readonly label: string, public readonly collapsibleState: vscode.TreeItemCollapsibleState ) { super(label, collapsibleState); this.tooltip = `Tooltip for ${label}`; this.command = { command: 'extension.itemClicked', title: 'Click Item', arguments: [this] }; } } ``` ### 5.2 注册 TreeView ```typescript const treeDataProvider = new MyTreeDataProvider(); const treeView = vscode.window.createTreeView('myTreeView', { treeDataProvider, showCollapseAll: true }); context.subscriptions.push(treeView); // 刷新视图 treeDataProvider.refresh(); ``` ### 5.3 WebviewView Provider(侧边栏 Webview) ```typescript class MyWebviewViewProvider implements vscode.WebviewViewProvider { resolveWebviewView( webviewView: vscode.WebviewView, context: vscode.WebviewViewResolveContext, token: vscode.CancellationToken ) { webviewView.webview.options = { enableScripts: true }; webviewView.webview.html = getWebviewContent(); webviewView.webview.onDidReceiveMessage(message => { // 处理消息 }); } } // 注册 vscode.window.registerWebviewViewProvider( 'myWebviewView', new MyWebviewViewProvider() ); ``` --- ## 6. 文件系统操作 ⭐⭐⭐ ### 6.1 读取文件 📌重要 ```typescript // 读取文本文件 const uri = vscode.Uri.file('/path/to/file.txt'); const content = await vscode.workspace.fs.readFile(uri); const text = Buffer.from(content).toString('utf8'); // 使用 TextDocument API const document = await vscode.workspace.openTextDocument(uri); const text = document.getText(); ``` ### 6.2 写入文件 ```typescript // 写入文件 const uri = vscode.Uri.file('/path/to/file.txt'); const content = Buffer.from('Hello World', 'utf8'); await vscode.workspace.fs.writeFile(uri, content); // 使用 WorkspaceEdit const edit = new vscode.WorkspaceEdit(); edit.createFile(uri, { overwrite: true }); edit.insert(uri, new vscode.Position(0, 0), 'Hello World'); await vscode.workspace.applyEdit(edit); ``` ### 6.3 文件监听 ```typescript // 监听文件变化 const watcher = vscode.workspace.createFileSystemWatcher('**/*.js'); 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); }); context.subscriptions.push(watcher); ``` ### 6.4 工作区操作 ```typescript // 获取工作区文件夹 const workspaceFolders = vscode.workspace.workspaceFolders; if (workspaceFolders) { const rootPath = workspaceFolders[0].uri.fsPath; } // 查找文件 const files = await vscode.workspace.findFiles( '**/*.ts', // include pattern '**/node_modules/**' // exclude pattern ); // 打开文件 const document = await vscode.workspace.openTextDocument(uri); await vscode.window.showTextDocument(document); ``` --- ## 7. 配置和存储 ⭐⭐⭐⭐ **面试重点** ### 7.1 读取配置 📌重要 ```typescript // 读取配置 const config = vscode.workspace.getConfiguration('myExtension'); const value = config.get('settingName', 'defaultValue'); // 监听配置变化 vscode.workspace.onDidChangeConfiguration(e => { if (e.affectsConfiguration('myExtension.settingName')) { console.log('Configuration changed'); } }); ``` ### 7.2 更新配置 ```typescript const config = vscode.workspace.getConfiguration('myExtension'); // 更新用户配置(全局) await config.update('settingName', 'newValue', vscode.ConfigurationTarget.Global); // 更新工作区配置 await config.update('settingName', 'newValue', vscode.ConfigurationTarget.Workspace); ``` ### 7.3 状态存储 🔥必考 ```typescript // 工作区状态(仅当前工作区) await context.workspaceState.update('key', 'value'); const value = context.workspaceState.get('key'); // 全局状态(跨工作区) await context.globalState.update('key', 'value'); const value = context.globalState.get('key'); // 存储对象 await context.globalState.update('userData', { name: 'John', age: 30 }); ``` ### 7.4 敏感信息存储 🔥必考(Token 管理) ```typescript // 存储密码、Token 等敏感信息 await context.secrets.store('apiToken', 'secret-token-value'); // 读取 const token = await context.secrets.get('apiToken'); // 删除 await context.secrets.delete('apiToken'); // 监听变化 context.secrets.onDidChange(e => { console.log('Secret changed:', e.key); }); ``` --- ## 8. 消息通知 ### 8.1 信息提示 ```typescript // 普通信息 vscode.window.showInformationMessage('Operation completed!'); // 警告 vscode.window.showWarningMessage('This action may cause issues'); // 错误 vscode.window.showErrorMessage('Operation failed!'); ``` ### 8.2 带按钮的提示 ```typescript const result = await vscode.window.showInformationMessage( 'Do you want to continue?', 'Yes', 'No', 'Cancel' ); if (result === 'Yes') { // 用户点击了 Yes } ``` ### 8.3 输入框 ```typescript // 简单输入 const input = await vscode.window.showInputBox({ prompt: 'Enter your name', placeHolder: 'John Doe', validateInput: (value) => { return value.length < 3 ? 'Name too short' : null; } }); // 快速选择 const selected = await vscode.window.showQuickPick( ['Option 1', 'Option 2', 'Option 3'], { placeHolder: 'Select an option', canPickMany: false } ); ``` ### 8.4 进度提示 ```typescript await vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, title: 'Processing...', cancellable: true }, async (progress, token) => { token.onCancellationRequested(() => { console.log('User canceled'); }); progress.report({ increment: 0, message: 'Starting...' }); await doWork1(); progress.report({ increment: 50, message: 'Half done...' }); await doWork2(); progress.report({ increment: 100, message: 'Complete!' }); } ); ``` --- ## 9. 语言特性支持 ### 9.1 代码补全 ```typescript const provider = vscode.languages.registerCompletionItemProvider( 'javascript', { provideCompletionItems(document, position) { const item = new vscode.CompletionItem('myFunction'); item.kind = vscode.CompletionItemKind.Function; item.detail = 'My custom function'; item.documentation = 'This is a custom function'; item.insertText = new vscode.SnippetString('myFunction($1)$0'); return [item]; } }, '.' // 触发字符 ); context.subscriptions.push(provider); ``` ### 9.2 悬停提示 ```typescript const provider = vscode.languages.registerHoverProvider('javascript', { provideHover(document, position) { const range = document.getWordRangeAtPosition(position); const word = document.getText(range); return new vscode.Hover([ `**${word}**`, 'This is a hover tooltip' ]); } }); ``` ### 9.3 诊断(错误提示) ```typescript const diagnosticCollection = vscode.languages.createDiagnosticCollection('myExtension'); context.subscriptions.push(diagnosticCollection); function updateDiagnostics(document: vscode.TextDocument) { const diagnostics: vscode.Diagnostic[] = []; const text = document.getText(); const regex = /TODO/g; let match; while ((match = regex.exec(text))) { const range = new vscode.Range( document.positionAt(match.index), document.positionAt(match.index + match[0].length) ); const diagnostic = new vscode.Diagnostic( range, 'TODO found', vscode.DiagnosticSeverity.Warning ); diagnostics.push(diagnostic); } diagnosticCollection.set(document.uri, diagnostics); } ``` --- ## 10. 调试和诊断 ### 10.1 输出通道 ```typescript const outputChannel = vscode.window.createOutputChannel('My Extension'); context.subscriptions.push(outputChannel); outputChannel.appendLine('Extension activated'); outputChannel.show(); // 显示输出面板 ``` ### 10.2 日志记录 ```typescript // 使用 LogOutputChannel(带时间戳) const logger = vscode.window.createOutputChannel('My Extension', { log: true }); logger.trace('Trace message'); logger.debug('Debug message'); logger.info('Info message'); logger.warn('Warning message'); logger.error('Error message'); ``` ### 10.3 错误处理 ```typescript try { await riskyOperation(); } catch (error) { if (error instanceof Error) { vscode.window.showErrorMessage(`Error: ${error.message}`); logger.error(error.stack || error.message); } } ``` --- ## 最佳实践总结 ### ✅ 推荐做法 1. **资源管理**:所有 disposable 对象都放入 `context.subscriptions` 2. **延迟激活**:使用 `onStartupFinished` 而不是 `*` 3. **异步操作**:使用 `async/await` 处理异步操作 4. **错误处理**:捕获异常并给用户友好提示 5. **类型安全**:充分利用 TypeScript 类型系统 6. **状态持久化**:使用 `globalState`/`workspaceState` 保存状态 7. **敏感信息**:使用 `secrets` API 存储 Token、密码等 ### ❌ 避免做法 1. 不要在 `activate` 中执行耗时操作 2. 不要忘记清理资源(监听器、Webview 等) 3. 不要在 Webview 中直接访问文件系统 4. 不要在配置中存储敏感信息 5. 不要阻塞主线程(使用 Worker 或异步操作) --- ## 参考资源 - [VS Code Extension API 官方文档](https://code.visualstudio.com/api) - [Extension Samples](https://github.com/microsoft/vscode-extension-samples) - [Extension Guidelines](https://code.visualstudio.com/api/references/extension-guidelines)