扩展 API
扩展 API 是 Trae IDE 的核心功能之一,允许开发者创建功能强大的扩展来增强 IDE 的功能。
概述
Trae IDE 扩展系统提供了丰富的 API,让您能够:
- 添加自定义命令和菜单项
- 创建自定义编辑器和视图
- 集成外部工具和服务
- 扩展语言支持
- 自定义用户界面
- 管理工作区和文件
- 与其他扩展通信
核心接口
Extension
扩展的主要接口定义。
typescript
interface Extension {
readonly id: string;
readonly name: string;
readonly version: string;
readonly description?: string;
readonly publisher: string;
readonly isActive: boolean;
readonly packageJSON: any;
readonly extensionPath: string;
readonly globalState: Memento;
readonly workspaceState: Memento;
activate(context: ExtensionContext): Promise<any>;
deactivate?(): Promise<void>;
}ExtensionContext
扩展上下文提供了扩展运行时的环境信息。
typescript
interface ExtensionContext {
readonly subscriptions: Disposable[];
readonly workspaceState: Memento;
readonly globalState: Memento;
readonly secrets: SecretStorage;
readonly extensionUri: Uri;
readonly extensionPath: string;
readonly environmentVariableCollection: EnvironmentVariableCollection;
readonly storageUri?: Uri;
readonly globalStorageUri: Uri;
readonly logUri: Uri;
asAbsolutePath(relativePath: string): string;
}基本扩展结构
typescript
// extension.ts
import * as TraeAPI from 'trae';
export function activate(context: TraeAPI.ExtensionContext) {
console.log('扩展已激活:', context.extension.id);
// 注册命令
const disposable = TraeAPI.commands.registerCommand('myExtension.helloWorld', () => {
TraeAPI.window.showInformationMessage('Hello World from My Extension!');
});
context.subscriptions.push(disposable);
}
export function deactivate() {
console.log('扩展已停用');
}生命周期管理
扩展激活
typescript
// package.json 中的激活事件
{
"activationEvents": [
"onCommand:myExtension.activate",
"onLanguage:typescript",
"onFileSystem:sftp",
"workspaceContains:**/*.config.js",
"onStartupFinished"
]
}
// 激活函数
export async function activate(context: TraeAPI.ExtensionContext): Promise<ExtensionAPI> {
// 初始化扩展
const extension = new MyExtension(context);
await extension.initialize();
// 返回公共 API(可选)
return {
getVersion: () => extension.version,
getStatus: () => extension.status,
performAction: (action: string) => extension.performAction(action)
};
}
// 停用函数
export async function deactivate(): Promise<void> {
// 清理资源
await MyExtension.cleanup();
}扩展状态管理
typescript
class ExtensionStateManager {
constructor(private context: TraeAPI.ExtensionContext) {}
// 全局状态(跨工作区)
getGlobalState<T>(key: string, defaultValue?: T): T {
return this.context.globalState.get(key, defaultValue!);
}
async setGlobalState<T>(key: string, value: T): Promise<void> {
await this.context.globalState.update(key, value);
}
// 工作区状态(特定于当前工作区)
getWorkspaceState<T>(key: string, defaultValue?: T): T {
return this.context.workspaceState.get(key, defaultValue!);
}
async setWorkspaceState<T>(key: string, value: T): Promise<void> {
await this.context.workspaceState.update(key, value);
}
// 密钥存储
async storeSecret(key: string, value: string): Promise<void> {
await this.context.secrets.store(key, value);
}
async getSecret(key: string): Promise<string | undefined> {
return await this.context.secrets.get(key);
}
async deleteSecret(key: string): Promise<void> {
await this.context.secrets.delete(key);
}
}
// 使用示例
const stateManager = new ExtensionStateManager(context);
// 保存用户偏好
await stateManager.setGlobalState('userPreferences', {
theme: 'dark',
fontSize: 14,
autoSave: true
});
// 获取用户偏好
const preferences = stateManager.getGlobalState('userPreferences', {
theme: 'light',
fontSize: 12,
autoSave: false
});
// 存储 API 密钥
await stateManager.storeSecret('apiKey', 'your-secret-api-key');
const apiKey = await stateManager.getSecret('apiKey');命令系统
注册命令
typescript
// 简单命令
const simpleCommand = TraeAPI.commands.registerCommand('myExtension.simple', () => {
TraeAPI.window.showInformationMessage('简单命令执行成功!');
});
// 带参数的命令
const parameterizedCommand = TraeAPI.commands.registerCommand(
'myExtension.withParams',
(param1: string, param2: number) => {
TraeAPI.window.showInformationMessage(`参数: ${param1}, ${param2}`);
}
);
// 异步命令
const asyncCommand = TraeAPI.commands.registerCommand(
'myExtension.async',
async () => {
const result = await TraeAPI.window.showInputBox({
prompt: '请输入一些文本',
placeHolder: '在这里输入...'
});
if (result) {
TraeAPI.window.showInformationMessage(`您输入了: ${result}`);
}
}
);
// 上下文相关命令
const contextCommand = TraeAPI.commands.registerCommand(
'myExtension.contextual',
(uri: TraeAPI.Uri) => {
if (uri) {
TraeAPI.window.showInformationMessage(`选中的文件: ${uri.fsPath}`);
} else {
const editor = TraeAPI.window.activeTextEditor;
if (editor) {
TraeAPI.window.showInformationMessage(`当前文件: ${editor.document.fileName}`);
}
}
}
);
// 添加到订阅
context.subscriptions.push(
simpleCommand,
parameterizedCommand,
asyncCommand,
contextCommand
);执行命令
typescript
// 执行内置命令
await TraeAPI.commands.executeCommand('workbench.action.files.save');
await TraeAPI.commands.executeCommand('editor.action.formatDocument');
// 执行自定义命令
await TraeAPI.commands.executeCommand('myExtension.simple');
await TraeAPI.commands.executeCommand('myExtension.withParams', 'hello', 42);
// 获取所有可用命令
const allCommands = await TraeAPI.commands.getCommands();
console.log('可用命令:', allCommands.filter(cmd => cmd.startsWith('myExtension')));命令面板集成
typescript
// package.json 中的命令贡献
{
"contributes": {
"commands": [
{
"command": "myExtension.openSettings",
"title": "打开设置",
"category": "My Extension",
"icon": "$(gear)"
},
{
"command": "myExtension.refresh",
"title": "刷新",
"category": "My Extension",
"icon": "$(refresh)"
}
]
}
}UI 贡献
菜单贡献
typescript
// package.json 中的菜单贡献
{
"contributes": {
"menus": {
"editor/context": [
{
"command": "myExtension.formatCode",
"when": "editorHasSelection",
"group": "1_modification"
}
],
"explorer/context": [
{
"command": "myExtension.processFile",
"when": "resourceExtname == .js",
"group": "2_workspace"
}
],
"commandPalette": [
{
"command": "myExtension.advancedFeature",
"when": "workspaceFolderCount > 0"
}
]
}
}
}状态栏项目
typescript
class StatusBarManager {
private statusBarItem: TraeAPI.StatusBarItem;
constructor() {
this.statusBarItem = TraeAPI.window.createStatusBarItem(
TraeAPI.StatusBarAlignment.Right,
100
);
this.statusBarItem.command = 'myExtension.showStatus';
this.statusBarItem.show();
}
updateStatus(text: string, tooltip?: string) {
this.statusBarItem.text = text;
this.statusBarItem.tooltip = tooltip;
}
showProgress(message: string) {
this.statusBarItem.text = `$(sync~spin) ${message}`;
}
showError(message: string) {
this.statusBarItem.text = `$(error) ${message}`;
this.statusBarItem.backgroundColor = new TraeAPI.ThemeColor('statusBarItem.errorBackground');
}
showSuccess(message: string) {
this.statusBarItem.text = `$(check) ${message}`;
this.statusBarItem.backgroundColor = undefined;
}
dispose() {
this.statusBarItem.dispose();
}
}
// 使用示例
const statusBar = new StatusBarManager();
statusBar.updateStatus('$(heart) My Extension', '点击查看状态');
// 注册状态命令
const statusCommand = TraeAPI.commands.registerCommand('myExtension.showStatus', () => {
TraeAPI.window.showInformationMessage('扩展状态: 正常运行');
});
context.subscriptions.push(statusCommand, statusBar);自定义视图
typescript
// 树视图提供程序
class MyTreeDataProvider implements TraeAPI.TreeDataProvider<TreeItem> {
private _onDidChangeTreeData: TraeAPI.EventEmitter<TreeItem | undefined | null | void> = new TraeAPI.EventEmitter<TreeItem | undefined | null | void>();
readonly onDidChangeTreeData: TraeAPI.Event<TreeItem | undefined | null | void> = this._onDidChangeTreeData.event;
private data: TreeItem[] = [
new TreeItem('项目 1', TraeAPI.TreeItemCollapsibleState.Collapsed),
new TreeItem('项目 2', TraeAPI.TreeItemCollapsibleState.Collapsed),
new TreeItem('项目 3', TraeAPI.TreeItemCollapsibleState.None)
];
getTreeItem(element: TreeItem): TraeAPI.TreeItem {
return element;
}
getChildren(element?: TreeItem): Thenable<TreeItem[]> {
if (!element) {
return Promise.resolve(this.data);
}
// 返回子项目
return Promise.resolve([
new TreeItem(`${element.label} - 子项 1`, TraeAPI.TreeItemCollapsibleState.None),
new TreeItem(`${element.label} - 子项 2`, TraeAPI.TreeItemCollapsibleState.None)
]);
}
refresh(): void {
this._onDidChangeTreeData.fire();
}
addItem(label: string): void {
this.data.push(new TreeItem(label, TraeAPI.TreeItemCollapsibleState.None));
this.refresh();
}
}
class TreeItem extends TraeAPI.TreeItem {
constructor(
public readonly label: string,
public readonly collapsibleState: TraeAPI.TreeItemCollapsibleState,
public readonly command?: TraeAPI.Command
) {
super(label, collapsibleState);
this.tooltip = `${this.label} - 自定义树项`;
this.description = '描述信息';
}
iconPath = {
light: path.join(__filename, '..', '..', 'resources', 'light', 'dependency.svg'),
dark: path.join(__filename, '..', '..', 'resources', 'dark', 'dependency.svg')
};
contextValue = 'treeItem';
}
// 注册树视图
const treeDataProvider = new MyTreeDataProvider();
const treeView = TraeAPI.window.createTreeView('myExtension.treeView', {
treeDataProvider,
showCollapseAll: true
});
// 树视图命令
const refreshCommand = TraeAPI.commands.registerCommand('myExtension.refreshTree', () => {
treeDataProvider.refresh();
});
const addItemCommand = TraeAPI.commands.registerCommand('myExtension.addTreeItem', async () => {
const label = await TraeAPI.window.showInputBox({
prompt: '输入新项目名称'
});
if (label) {
treeDataProvider.addItem(label);
}
});
context.subscriptions.push(treeView, refreshCommand, addItemCommand);Webview 面板
typescript
class WebviewManager {
private panels: Map<string, TraeAPI.WebviewPanel> = new Map();
createPanel(id: string, title: string, content: string): TraeAPI.WebviewPanel {
// 检查是否已存在
const existingPanel = this.panels.get(id);
if (existingPanel) {
existingPanel.reveal();
return existingPanel;
}
// 创建新面板
const panel = TraeAPI.window.createWebviewPanel(
id,
title,
TraeAPI.ViewColumn.One,
{
enableScripts: true,
retainContextWhenHidden: true,
localResourceRoots: [TraeAPI.Uri.file(path.join(context.extensionPath, 'media'))]
}
);
panel.webview.html = this.getWebviewContent(content);
// 处理消息
panel.webview.onDidReceiveMessage(
message => this.handleWebviewMessage(panel, message),
undefined,
context.subscriptions
);
// 面板关闭时清理
panel.onDidDispose(
() => this.panels.delete(id),
null,
context.subscriptions
);
this.panels.set(id, panel);
return panel;
}
private getWebviewContent(content: string): string {
return `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Extension</title>
<style>
body {
font-family: var(--vscode-font-family);
font-size: var(--vscode-font-size);
color: var(--vscode-foreground);
background-color: var(--vscode-editor-background);
padding: 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
}
button {
background-color: var(--vscode-button-background);
color: var(--vscode-button-foreground);
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
margin: 4px;
}
button:hover {
background-color: var(--vscode-button-hoverBackground);
}
input {
background-color: var(--vscode-input-background);
color: var(--vscode-input-foreground);
border: 1px solid var(--vscode-input-border);
padding: 8px;
border-radius: 4px;
width: 100%;
margin: 4px 0;
}
</style>
</head>
<body>
<div class="container">
<h1>My Extension Panel</h1>
<div id="content">${content}</div>
<div>
<input type="text" id="messageInput" placeholder="输入消息...">
<button onclick="sendMessage()">发送消息</button>
<button onclick="loadData()">加载数据</button>
</div>
<div id="output"></div>
</div>
<script>
const vscode = acquireVsCodeApi();
function sendMessage() {
const input = document.getElementById('messageInput');
const message = input.value;
vscode.postMessage({
command: 'sendMessage',
text: message
});
input.value = '';
}
function loadData() {
vscode.postMessage({
command: 'loadData'
});
}
window.addEventListener('message', event => {
const message = event.data;
const output = document.getElementById('output');
switch (message.command) {
case 'updateContent':
document.getElementById('content').innerHTML = message.content;
break;
case 'showMessage':
output.innerHTML += '<p>' + message.text + '</p>';
break;
}
});
</script>
</body>
</html>
`;
}
private handleWebviewMessage(panel: TraeAPI.WebviewPanel, message: any) {
switch (message.command) {
case 'sendMessage':
TraeAPI.window.showInformationMessage(`收到消息: ${message.text}`);
panel.webview.postMessage({
command: 'showMessage',
text: `回复: ${message.text}`
});
break;
case 'loadData':
// 模拟加载数据
setTimeout(() => {
panel.webview.postMessage({
command: 'updateContent',
content: '<p>数据已加载: ' + new Date().toLocaleString() + '</p>'
});
}, 1000);
break;
}
}
dispose() {
this.panels.forEach(panel => panel.dispose());
this.panels.clear();
}
}
// 使用示例
const webviewManager = new WebviewManager();
const openPanelCommand = TraeAPI.commands.registerCommand('myExtension.openPanel', () => {
webviewManager.createPanel(
'myExtensionPanel',
'My Extension Panel',
'<p>欢迎使用我的扩展!</p>'
);
});
context.subscriptions.push(openPanelCommand, webviewManager);配置管理
扩展配置
typescript
// package.json 中的配置贡献
{
"contributes": {
"configuration": {
"title": "My Extension",
"properties": {
"myExtension.enabled": {
"type": "boolean",
"default": true,
"description": "启用扩展功能"
},
"myExtension.apiUrl": {
"type": "string",
"default": "https://api.example.com",
"description": "API 服务器地址"
},
"myExtension.timeout": {
"type": "number",
"default": 5000,
"minimum": 1000,
"maximum": 30000,
"description": "请求超时时间(毫秒)"
},
"myExtension.features": {
"type": "object",
"default": {
"autoSave": true,
"notifications": true,
"analytics": false
},
"properties": {
"autoSave": {
"type": "boolean",
"description": "自动保存"
},
"notifications": {
"type": "boolean",
"description": "显示通知"
},
"analytics": {
"type": "boolean",
"description": "发送分析数据"
}
},
"description": "功能设置"
}
}
}
}
}配置访问和监听
typescript
class ConfigurationManager {
private config: TraeAPI.WorkspaceConfiguration;
private disposables: TraeAPI.Disposable[] = [];
constructor() {
this.config = TraeAPI.workspace.getConfiguration('myExtension');
// 监听配置变化
const configChangeListener = TraeAPI.workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('myExtension')) {
this.onConfigurationChanged();
}
});
this.disposables.push(configChangeListener);
}
// 获取配置值
get<T>(key: string, defaultValue?: T): T {
return this.config.get<T>(key, defaultValue!);
}
// 更新配置
async update<T>(key: string, value: T, target?: TraeAPI.ConfigurationTarget): Promise<void> {
await this.config.update(key, value, target);
}
// 获取所有配置
getAllSettings() {
return {
enabled: this.get<boolean>('enabled'),
apiUrl: this.get<string>('apiUrl'),
timeout: this.get<number>('timeout'),
features: this.get<any>('features')
};
}
// 重置配置
async resetToDefaults(): Promise<void> {
await this.update('enabled', undefined, TraeAPI.ConfigurationTarget.Global);
await this.update('apiUrl', undefined, TraeAPI.ConfigurationTarget.Global);
await this.update('timeout', undefined, TraeAPI.ConfigurationTarget.Global);
await this.update('features', undefined, TraeAPI.ConfigurationTarget.Global);
}
// 验证配置
validateConfiguration(): string[] {
const errors: string[] = [];
const apiUrl = this.get<string>('apiUrl');
if (!apiUrl || !this.isValidUrl(apiUrl)) {
errors.push('API URL 格式无效');
}
const timeout = this.get<number>('timeout');
if (timeout < 1000 || timeout > 30000) {
errors.push('超时时间必须在 1000-30000 毫秒之间');
}
return errors;
}
private onConfigurationChanged(): void {
console.log('配置已更改:', this.getAllSettings());
// 验证新配置
const errors = this.validateConfiguration();
if (errors.length > 0) {
TraeAPI.window.showWarningMessage(`配置错误: ${errors.join(', ')}`);
}
// 重新初始化功能
this.reinitializeFeatures();
}
private reinitializeFeatures(): void {
const settings = this.getAllSettings();
if (settings.enabled) {
// 启用功能
console.log('扩展功能已启用');
} else {
// 禁用功能
console.log('扩展功能已禁用');
}
}
private isValidUrl(url: string): boolean {
try {
new URL(url);
return true;
} catch {
return false;
}
}
dispose(): void {
this.disposables.forEach(d => d.dispose());
}
}
// 使用示例
const configManager = new ConfigurationManager();
// 获取配置
const isEnabled = configManager.get<boolean>('enabled');
const apiUrl = configManager.get<string>('apiUrl');
const features = configManager.get<any>('features');
console.log('扩展配置:', { isEnabled, apiUrl, features });
// 更新配置
await configManager.update('timeout', 10000, TraeAPI.ConfigurationTarget.Workspace);
context.subscriptions.push(configManager);状态管理
Memento 存储
typescript
class StateManager {
constructor(
private globalState: TraeAPI.Memento,
private workspaceState: TraeAPI.Memento
) {}
// 用户偏好(全局)
async saveUserPreferences(preferences: UserPreferences): Promise<void> {
await this.globalState.update('userPreferences', preferences);
}
getUserPreferences(): UserPreferences {
return this.globalState.get('userPreferences', {
theme: 'auto',
language: 'zh-CN',
notifications: true
});
}
// 项目设置(工作区)
async saveProjectSettings(settings: ProjectSettings): Promise<void> {
await this.workspaceState.update('projectSettings', settings);
}
getProjectSettings(): ProjectSettings {
return this.workspaceState.get('projectSettings', {
buildCommand: 'npm run build',
testCommand: 'npm test',
lintCommand: 'npm run lint'
});
}
// 缓存管理
async cacheData(key: string, data: any, ttl: number = 3600000): Promise<void> {
const cacheItem = {
data,
timestamp: Date.now(),
ttl
};
await this.globalState.update(`cache_${key}`, cacheItem);
}
getCachedData<T>(key: string): T | undefined {
const cacheItem = this.globalState.get<CacheItem>(`cache_${key}`);
if (!cacheItem) {
return undefined;
}
// 检查是否过期
if (Date.now() - cacheItem.timestamp > cacheItem.ttl) {
this.globalState.update(`cache_${key}`, undefined);
return undefined;
}
return cacheItem.data;
}
// 清理过期缓存
async cleanExpiredCache(): Promise<void> {
const keys = this.globalState.keys();
const cacheKeys = keys.filter(key => key.startsWith('cache_'));
for (const key of cacheKeys) {
const cacheItem = this.globalState.get<CacheItem>(key);
if (cacheItem && Date.now() - cacheItem.timestamp > cacheItem.ttl) {
await this.globalState.update(key, undefined);
}
}
}
// 统计信息
async incrementUsageCount(feature: string): Promise<void> {
const currentCount = this.globalState.get<number>(`usage_${feature}`, 0);
await this.globalState.update(`usage_${feature}`, currentCount + 1);
}
getUsageCount(feature: string): number {
return this.globalState.get<number>(`usage_${feature}`, 0);
}
getAllUsageStats(): Record<string, number> {
const keys = this.globalState.keys();
const usageKeys = keys.filter(key => key.startsWith('usage_'));
const stats: Record<string, number> = {};
for (const key of usageKeys) {
const feature = key.replace('usage_', '');
stats[feature] = this.getUsageCount(feature);
}
return stats;
}
}
interface UserPreferences {
theme: 'light' | 'dark' | 'auto';
language: string;
notifications: boolean;
}
interface ProjectSettings {
buildCommand: string;
testCommand: string;
lintCommand: string;
}
interface CacheItem {
data: any;
timestamp: number;
ttl: number;
}
// 使用示例
const stateManager = new StateManager(
context.globalState,
context.workspaceState
);
// 保存用户偏好
await stateManager.saveUserPreferences({
theme: 'dark',
language: 'zh-CN',
notifications: true
});
// 缓存 API 响应
await stateManager.cacheData('apiResponse', { data: 'some data' }, 1800000); // 30分钟
// 统计功能使用
await stateManager.incrementUsageCount('codeGeneration');
// 定期清理缓存
setInterval(() => {
stateManager.cleanExpiredCache();
}, 3600000); // 每小时清理一次扩展间通信
API 导出
typescript
// 定义公共 API 接口
export interface MyExtensionAPI {
getVersion(): string;
processData(data: any): Promise<any>;
registerCallback(callback: (data: any) => void): TraeAPI.Disposable;
getStatus(): ExtensionStatus;
}
export interface ExtensionStatus {
isActive: boolean;
lastUpdate: Date;
errorCount: number;
}
// 实现 API
class MyExtensionImpl implements MyExtensionAPI {
private callbacks: ((data: any) => void)[] = [];
private status: ExtensionStatus = {
isActive: true,
lastUpdate: new Date(),
errorCount: 0
};
getVersion(): string {
return '1.0.0';
}
async processData(data: any): Promise<any> {
try {
// 处理数据
const result = await this.performProcessing(data);
// 通知回调
this.callbacks.forEach(callback => {
try {
callback(result);
} catch (error) {
console.error('回调执行错误:', error);
}
});
this.status.lastUpdate = new Date();
return result;
} catch (error) {
this.status.errorCount++;
throw error;
}
}
registerCallback(callback: (data: any) => void): TraeAPI.Disposable {
this.callbacks.push(callback);
return {
dispose: () => {
const index = this.callbacks.indexOf(callback);
if (index >= 0) {
this.callbacks.splice(index, 1);
}
}
};
}
getStatus(): ExtensionStatus {
return { ...this.status };
}
private async performProcessing(data: any): Promise<any> {
// 模拟数据处理
await new Promise(resolve => setTimeout(resolve, 100));
return { processed: true, original: data, timestamp: Date.now() };
}
}
// 在 activate 函数中导出 API
export function activate(context: TraeAPI.ExtensionContext): MyExtensionAPI {
const extensionImpl = new MyExtensionImpl();
// 注册命令等...
return extensionImpl;
}使用其他扩展的 API
typescript
// 获取其他扩展的 API
async function useOtherExtensionAPI() {
// 获取扩展
const otherExtension = TraeAPI.extensions.getExtension<MyExtensionAPI>('publisher.my-extension');
if (!otherExtension) {
TraeAPI.window.showErrorMessage('未找到依赖的扩展');
return;
}
// 激活扩展(如果尚未激活)
if (!otherExtension.isActive) {
await otherExtension.activate();
}
// 使用 API
const api = otherExtension.exports;
if (api) {
console.log('扩展版本:', api.getVersion());
// 注册回调
const disposable = api.registerCallback((data) => {
console.log('收到数据:', data);
});
// 处理数据
const result = await api.processData({ test: 'data' });
console.log('处理结果:', result);
// 获取状态
const status = api.getStatus();
console.log('扩展状态:', status);
// 清理
context.subscriptions.push(disposable);
}
}
// 扩展依赖管理
class ExtensionDependencyManager {
private dependencies: Map<string, any> = new Map();
async loadDependency<T>(extensionId: string): Promise<T | undefined> {
// 检查缓存
if (this.dependencies.has(extensionId)) {
return this.dependencies.get(extensionId);
}
// 获取扩展
const extension = TraeAPI.extensions.getExtension<T>(extensionId);
if (!extension) {
console.warn(`扩展 ${extensionId} 未安装`);
return undefined;
}
// 激活扩展
if (!extension.isActive) {
try {
await extension.activate();
} catch (error) {
console.error(`激活扩展 ${extensionId} 失败:`, error);
return undefined;
}
}
// 缓存 API
const api = extension.exports;
this.dependencies.set(extensionId, api);
return api;
}
getDependency<T>(extensionId: string): T | undefined {
return this.dependencies.get(extensionId);
}
async checkDependencies(requiredExtensions: string[]): Promise<string[]> {
const missing: string[] = [];
for (const extensionId of requiredExtensions) {
const extension = TraeAPI.extensions.getExtension(extensionId);
if (!extension) {
missing.push(extensionId);
}
}
return missing;
}
async promptInstallMissing(missingExtensions: string[]): Promise<void> {
if (missingExtensions.length === 0) return;
const message = `此扩展需要以下依赖: ${missingExtensions.join(', ')}`;
const action = await TraeAPI.window.showWarningMessage(
message,
'安装依赖',
'取消'
);
if (action === '安装依赖') {
for (const extensionId of missingExtensions) {
await TraeAPI.commands.executeCommand('workbench.extensions.installExtension', extensionId);
}
}
}
}
// 使用示例
const dependencyManager = new ExtensionDependencyManager();
// 检查依赖
const requiredExtensions = ['ms-python.python', 'ms-vscode.vscode-typescript-next'];
const missing = await dependencyManager.checkDependencies(requiredExtensions);
if (missing.length > 0) {
await dependencyManager.promptInstallMissing(missing);
} else {
// 加载依赖
const pythonApi = await dependencyManager.loadDependency('ms-python.python');
if (pythonApi) {
// 使用 Python 扩展 API
}
}文件系统访问
文件操作
typescript
class FileSystemManager {
// 读取文件
async readFile(uri: TraeAPI.Uri): Promise<string> {
try {
const data = await TraeAPI.workspace.fs.readFile(uri);
return Buffer.from(data).toString('utf8');
} catch (error) {
console.error('读取文件失败:', error);
throw error;
}
}
// 写入文件
async writeFile(uri: TraeAPI.Uri, content: string): Promise<void> {
try {
const data = Buffer.from(content, 'utf8');
await TraeAPI.workspace.fs.writeFile(uri, data);
} catch (error) {
console.error('写入文件失败:', error);
throw error;
}
}
// 创建目录
async createDirectory(uri: TraeAPI.Uri): Promise<void> {
try {
await TraeAPI.workspace.fs.createDirectory(uri);
} catch (error) {
if (error.code !== 'FileExists') {
console.error('创建目录失败:', error);
throw error;
}
}
}
// 删除文件或目录
async delete(uri: TraeAPI.Uri, options?: { recursive?: boolean; useTrash?: boolean }): Promise<void> {
try {
await TraeAPI.workspace.fs.delete(uri, options);
} catch (error) {
console.error('删除失败:', error);
throw error;
}
}
// 复制文件
async copy(source: TraeAPI.Uri, target: TraeAPI.Uri, options?: { overwrite?: boolean }): Promise<void> {
try {
await TraeAPI.workspace.fs.copy(source, target, options);
} catch (error) {
console.error('复制失败:', error);
throw error;
}
}
// 重命名/移动文件
async rename(source: TraeAPI.Uri, target: TraeAPI.Uri, options?: { overwrite?: boolean }): Promise<void> {
try {
await TraeAPI.workspace.fs.rename(source, target, options);
} catch (error) {
console.error('重命名失败:', error);
throw error;
}
}
// 获取文件状态
async stat(uri: TraeAPI.Uri): Promise<TraeAPI.FileStat> {
try {
return await TraeAPI.workspace.fs.stat(uri);
} catch (error) {
console.error('获取文件状态失败:', error);
throw error;
}
}
// 读取目录
async readDirectory(uri: TraeAPI.Uri): Promise<[string, TraeAPI.FileType][]> {
try {
return await TraeAPI.workspace.fs.readDirectory(uri);
} catch (error) {
console.error('读取目录失败:', error);
throw error;
}
}
// 检查文件是否存在
async exists(uri: TraeAPI.Uri): Promise<boolean> {
try {
await this.stat(uri);
return true;
} catch {
return false;
}
}
// 递归读取目录
async readDirectoryRecursive(uri: TraeAPI.Uri, filter?: (name: string, type: TraeAPI.FileType) => boolean): Promise<TraeAPI.Uri[]> {
const results: TraeAPI.Uri[] = [];
try {
const entries = await this.readDirectory(uri);
for (const [name, type] of entries) {
if (filter && !filter(name, type)) {
continue;
}
const childUri = TraeAPI.Uri.joinPath(uri, name);
results.push(childUri);
if (type === TraeAPI.FileType.Directory) {
const childResults = await this.readDirectoryRecursive(childUri, filter);
results.push(...childResults);
}
}
} catch (error) {
console.error('递归读取目录失败:', error);
}
return results;
}
// 查找文件
async findFiles(pattern: string, exclude?: string): Promise<TraeAPI.Uri[]> {
return await TraeAPI.workspace.findFiles(pattern, exclude);
}
// 监听文件变化
watchFiles(pattern: TraeAPI.GlobPattern, callback: (uri: TraeAPI.Uri) => void): TraeAPI.Disposable {
const watcher = TraeAPI.workspace.createFileSystemWatcher(pattern);
const disposables = [
watcher.onDidCreate(callback),
watcher.onDidChange(callback),
watcher.onDidDelete(callback),
watcher
];
return {
dispose: () => {
disposables.forEach(d => d.dispose());
}
};
}
}
// 使用示例
const fsManager = new FileSystemManager();
// 读取配置文件
const configUri = TraeAPI.Uri.file('/path/to/config.json');
if (await fsManager.exists(configUri)) {
const configContent = await fsManager.readFile(configUri);
const config = JSON.parse(configContent);
console.log('配置:', config);
}
// 创建项目结构
const projectUri = TraeAPI.Uri.file('/path/to/new-project');
await fsManager.createDirectory(projectUri);
await fsManager.createDirectory(TraeAPI.Uri.joinPath(projectUri, 'src'));
await fsManager.createDirectory(TraeAPI.Uri.joinPath(projectUri, 'tests'));
// 创建文件
const packageJsonUri = TraeAPI.Uri.joinPath(projectUri, 'package.json');
const packageJsonContent = JSON.stringify({
name: 'my-project',
version: '1.0.0',
description: 'My awesome project'
}, null, 2);
await fsManager.writeFile(packageJsonUri, packageJsonContent);
// 查找 TypeScript 文件
const tsFiles = await fsManager.findFiles('**/*.ts', '**/node_modules/**');
console.log('TypeScript 文件:', tsFiles.map(uri => uri.fsPath));
// 监听文件变化
const watcher = fsManager.watchFiles('**/*.{js,ts}', (uri) => {
console.log('文件变化:', uri.fsPath);
});
context.subscriptions.push(watcher);高级功能
自定义编辑器
typescript
// 自定义编辑器提供程序
class CustomEditorProvider implements TraeAPI.CustomTextEditorProvider {
public static register(context: TraeAPI.ExtensionContext): TraeAPI.Disposable {
const provider = new CustomEditorProvider(context);
const providerRegistration = TraeAPI.window.registerCustomEditorProvider(
'myExtension.customEditor',
provider
);
return providerRegistration;
}
constructor(private readonly context: TraeAPI.ExtensionContext) {}
public async resolveCustomTextEditor(
document: TraeAPI.TextDocument,
webviewPanel: TraeAPI.WebviewPanel,
_token: TraeAPI.CancellationToken
): Promise<void> {
// 设置 webview 选项
webviewPanel.webview.options = {
enableScripts: true,
};
// 设置初始内容
webviewPanel.webview.html = this.getHtmlForWebview(webviewPanel.webview, document);
// 处理来自 webview 的消息
webviewPanel.webview.onDidReceiveMessage(e => {
switch (e.type) {
case 'update':
this.updateTextDocument(document, e.content);
return;
case 'save':
document.save();
return;
}
});
// 监听文档变化
const changeDocumentSubscription = TraeAPI.workspace.onDidChangeTextDocument(e => {
if (e.document.uri.toString() === document.uri.toString()) {
this.updateWebview(webviewPanel, document);
}
});
// 清理
webviewPanel.onDidDispose(() => {
changeDocumentSubscription.dispose();
});
}
private getHtmlForWebview(webview: TraeAPI.Webview, document: TraeAPI.TextDocument): string {
const content = document.getText();
return `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>自定义编辑器</title>
<style>
body {
font-family: var(--vscode-font-family);
font-size: var(--vscode-font-size);
color: var(--vscode-foreground);
background-color: var(--vscode-editor-background);
margin: 0;
padding: 20px;
}
.editor {
width: 100%;
height: 400px;
border: 1px solid var(--vscode-input-border);
background-color: var(--vscode-input-background);
color: var(--vscode-input-foreground);
padding: 10px;
font-family: var(--vscode-editor-font-family);
font-size: var(--vscode-editor-font-size);
resize: vertical;
}
.toolbar {
margin-bottom: 10px;
}
button {
background-color: var(--vscode-button-background);
color: var(--vscode-button-foreground);
border: none;
padding: 6px 12px;
border-radius: 3px;
cursor: pointer;
margin-right: 5px;
}
button:hover {
background-color: var(--vscode-button-hoverBackground);
}
</style>
</head>
<body>
<div class="toolbar">
<button onclick="save()">保存</button>
<button onclick="format()">格式化</button>
<button onclick="validate()">验证</button>
</div>
<textarea class="editor" id="editor">${content}</textarea>
<script>
const vscode = acquireVsCodeApi();
const editor = document.getElementById('editor');
// 监听内容变化
editor.addEventListener('input', () => {
vscode.postMessage({
type: 'update',
content: editor.value
});
});
function save() {
vscode.postMessage({ type: 'save' });
}
function format() {
try {
const formatted = JSON.stringify(JSON.parse(editor.value), null, 2);
editor.value = formatted;
vscode.postMessage({
type: 'update',
content: formatted
});
} catch (error) {
alert('格式化失败: ' + error.message);
}
}
function validate() {
try {
JSON.parse(editor.value);
alert('JSON 格式正确');
} catch (error) {
alert('JSON 格式错误: ' + error.message);
}
}
// 监听来自扩展的消息
window.addEventListener('message', event => {
const message = event.data;
switch (message.type) {
case 'update':
editor.value = message.content;
break;
}
});
</script>
</body>
</html>
`;
}
private updateTextDocument(document: TraeAPI.TextDocument, content: string) {
const edit = new TraeAPI.WorkspaceEdit();
edit.replace(
document.uri,
new TraeAPI.Range(0, 0, document.lineCount, 0),
content
);
TraeAPI.workspace.applyEdit(edit);
}
private updateWebview(panel: TraeAPI.WebviewPanel, document: TraeAPI.TextDocument) {
panel.webview.postMessage({
type: 'update',
content: document.getText()
});
}
}
// 注册自定义编辑器
const customEditorProvider = CustomEditorProvider.register(context);
context.subscriptions.push(customEditorProvider);语言服务器集成
typescript
// 语言客户端
import {
LanguageClient,
LanguageClientOptions,
ServerOptions,
TransportKind
} from 'vscode-languageclient/node';
class LanguageServerManager {
private client: LanguageClient | undefined;
async startLanguageServer(context: TraeAPI.ExtensionContext): Promise<void> {
// 服务器选项
const serverModule = context.asAbsolutePath(
path.join('server', 'out', 'server.js')
);
const debugOptions = { execArgv: ['--nolazy', '--inspect=6009'] };
const serverOptions: ServerOptions = {
run: { module: serverModule, transport: TransportKind.ipc },
debug: {
module: serverModule,
transport: TransportKind.ipc,
options: debugOptions
}
};
// 客户端选项
const clientOptions: LanguageClientOptions = {
documentSelector: [{ scheme: 'file', language: 'mylanguage' }],
synchronize: {
fileEvents: TraeAPI.workspace.createFileSystemWatcher('**/.clientrc')
}
};
// 创建语言客户端
this.client = new LanguageClient(
'myLanguageServer',
'My Language Server',
serverOptions,
clientOptions
);
// 启动客户端
await this.client.start();
console.log('语言服务器已启动');
}
async stopLanguageServer(): Promise<void> {
if (this.client) {
await this.client.stop();
this.client = undefined;
console.log('语言服务器已停止');
}
}
isRunning(): boolean {
return this.client !== undefined;
}
async sendRequest<T>(method: string, params?: any): Promise<T> {
if (!this.client) {
throw new Error('语言服务器未运行');
}
return await this.client.sendRequest(method, params);
}
sendNotification(method: string, params?: any): void {
if (this.client) {
this.client.sendNotification(method, params);
}
}
}
// 使用示例
const languageServerManager = new LanguageServerManager();
// 启动语言服务器
await languageServerManager.startLanguageServer(context);
// 发送自定义请求
const result = await languageServerManager.sendRequest('custom/analyze', {
uri: 'file:///path/to/file.mylang'
});
// 清理
context.subscriptions.push({
dispose: () => languageServerManager.stopLanguageServer()
});测试
单元测试
typescript
// test/extension.test.ts
import * as assert from 'assert';
import * as TraeAPI from 'trae';
import * as myExtension from '../src/extension';
suite('Extension Test Suite', () => {
TraeAPI.window.showInformationMessage('开始运行测试!');
test('扩展激活测试', async () => {
// 模拟扩展上下文
const context = {
subscriptions: [],
workspaceState: {
get: () => undefined,
update: () => Promise.resolve()
},
globalState: {
get: () => undefined,
update: () => Promise.resolve()
}
} as any;
// 激活扩展
const result = await myExtension.activate(context);
// 验证结果
assert.ok(result);
assert.ok(context.subscriptions.length > 0);
});
test('命令注册测试', async () => {
// 获取所有命令
const commands = await TraeAPI.commands.getCommands();
// 验证自定义命令是否注册
assert.ok(commands.includes('myExtension.helloWorld'));
});
test('配置读取测试', () => {
const config = TraeAPI.workspace.getConfiguration('myExtension');
const enabled = config.get<boolean>('enabled');
// 验证配置
assert.strictEqual(typeof enabled, 'boolean');
});
});集成测试
typescript
// test/integration.test.ts
import * as assert from 'assert';
import * as TraeAPI from 'trae';
import * as path from 'path';
suite('Integration Test Suite', () => {
test('文件操作集成测试', async () => {
const workspaceFolder = TraeAPI.workspace.workspaceFolders?.[0];
if (!workspaceFolder) {
assert.fail('需要打开工作区');
}
const testFileUri = TraeAPI.Uri.joinPath(workspaceFolder.uri, 'test.txt');
const testContent = 'Hello, World!';
// 写入文件
await TraeAPI.workspace.fs.writeFile(testFileUri, Buffer.from(testContent));
// 读取文件
const readContent = await TraeAPI.workspace.fs.readFile(testFileUri);
const contentString = Buffer.from(readContent).toString();
// 验证内容
assert.strictEqual(contentString, testContent);
// 清理
await TraeAPI.workspace.fs.delete(testFileUri);
});
test('编辑器集成测试', async () => {
// 创建新文档
const document = await TraeAPI.workspace.openTextDocument({
content: 'function test() {\n console.log("test");\n}',
language: 'javascript'
});
// 打开编辑器
const editor = await TraeAPI.window.showTextDocument(document);
// 验证编辑器
assert.ok(editor);
assert.strictEqual(editor.document.languageId, 'javascript');
assert.ok(editor.document.getText().includes('function test'));
});
});发布
扩展打包
typescript
// 使用 vsce 打包扩展
// package.json 配置
{
"name": "my-extension",
"displayName": "My Extension",
"description": "我的扩展描述",
"version": "1.0.0",
"publisher": "my-publisher",
"engines": {
"trae": "^1.0.0"
},
"categories": [
"Other"
],
"activationEvents": [
"onCommand:myExtension.activate"
],
"main": "./out/extension.js",
"contributes": {
"commands": [
{
"command": "myExtension.helloWorld",
"title": "Hello World"
}
]
},
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"package": "vsce package",
"publish": "vsce publish"
},
"devDependencies": {
"@types/trae": "^1.0.0",
"typescript": "^4.0.0",
"vsce": "^2.0.0"
}
}发布流程
bash
# 安装 vsce
npm install -g vsce
# 登录发布者账户
vsce login <publisher-name>
# 打包扩展
vsce package
# 发布扩展
vsce publish
# 发布特定版本
vsce publish 1.0.1
# 发布预发布版本
vsce publish --pre-release最佳实践
性能优化
typescript
// 延迟加载
class LazyFeatureManager {
private features: Map<string, () => Promise<any>> = new Map();
private loadedFeatures: Map<string, any> = new Map();
registerFeature(name: string, loader: () => Promise<any>): void {
this.features.set(name, loader);
}
async getFeature<T>(name: string): Promise<T> {
// 检查是否已加载
if (this.loadedFeatures.has(name)) {
return this.loadedFeatures.get(name);
}
// 延迟加载
const loader = this.features.get(name);
if (!loader) {
throw new Error(`功能 ${name} 未注册`);
}
const feature = await loader();
this.loadedFeatures.set(name, feature);
return feature;
}
}
// 使用示例
const featureManager = new LazyFeatureManager();
// 注册功能
featureManager.registerFeature('heavyFeature', async () => {
const { HeavyFeature } = await import('./heavy-feature');
return new HeavyFeature();
});
// 按需加载
const heavyFeature = await featureManager.getFeature('heavyFeature');错误处理
typescript
class ErrorHandler {
private static instance: ErrorHandler;
private errorCount: number = 0;
private maxErrors: number = 10;
static getInstance(): ErrorHandler {
if (!ErrorHandler.instance) {
ErrorHandler.instance = new ErrorHandler();
}
return ErrorHandler.instance;
}
handleError(error: Error, context?: string): void {
this.errorCount++;
console.error(`错误 [${context || 'Unknown'}]:`, error);
// 记录错误
this.logError(error, context);
// 显示用户友好的错误消息
this.showUserError(error, context);
// 检查错误频率
if (this.errorCount > this.maxErrors) {
this.handleTooManyErrors();
}
}
private logError(error: Error, context?: string): void {
// 发送到日志服务
const errorInfo = {
message: error.message,
stack: error.stack,
context,
timestamp: new Date().toISOString(),
version: TraeAPI.extensions.getExtension('my-publisher.my-extension')?.packageJSON.version
};
// 这里可以发送到远程日志服务
console.log('错误日志:', errorInfo);
}
private showUserError(error: Error, context?: string): void {
let message = '操作失败';
if (context) {
message += `: ${context}`;
}
TraeAPI.window.showErrorMessage(message, '查看详情').then(selection => {
if (selection === '查看详情') {
TraeAPI.window.showErrorMessage(error.message);
}
});
}
private handleTooManyErrors(): void {
TraeAPI.window.showWarningMessage(
'扩展遇到多个错误,建议重启 IDE',
'重启',
'忽略'
).then(selection => {
if (selection === '重启') {
TraeAPI.commands.executeCommand('workbench.action.reloadWindow');
}
});
}
resetErrorCount(): void {
this.errorCount = 0;
}
}
// 全局错误处理装饰器
function handleErrors(target: any, propertyName: string, descriptor: PropertyDescriptor) {
const method = descriptor.value;
descriptor.value = async function (...args: any[]) {
try {
return await method.apply(this, args);
} catch (error) {
ErrorHandler.getInstance().handleError(error as Error, `${target.constructor.name}.${propertyName}`);
throw error;
}
};
}
// 使用示例
class MyService {
@handleErrors
async processData(data: any): Promise<any> {
// 可能抛出错误的代码
if (!data) {
throw new Error('数据不能为空');
}
return { processed: true, data };
}
}国际化
typescript
// package.json 中的国际化配置
{
"contributes": {
"languages": [
{
"id": "zh-cn",
"aliases": ["Chinese (Simplified)", "中文(简体)"],
"configuration": "./language-configuration.json"
}
]
}
}
// 国际化管理器
class I18nManager {
private messages: Map<string, any> = new Map();
private currentLocale: string = 'zh-CN';
constructor(private context: TraeAPI.ExtensionContext) {
this.loadMessages();
}
private async loadMessages(): Promise<void> {
try {
// 获取当前语言
this.currentLocale = TraeAPI.env.language;
// 加载对应的语言文件
const messagesPath = path.join(
this.context.extensionPath,
'i18n',
`${this.currentLocale}.json`
);
const messagesUri = TraeAPI.Uri.file(messagesPath);
const messagesContent = await TraeAPI.workspace.fs.readFile(messagesUri);
const messages = JSON.parse(Buffer.from(messagesContent).toString());
this.messages.set(this.currentLocale, messages);
} catch (error) {
// 回退到默认语言
console.warn('加载语言文件失败,使用默认语言:', error);
this.loadDefaultMessages();
}
}
private loadDefaultMessages(): void {
const defaultMessages = {
'hello': '你好',
'goodbye': '再见',
'error.fileNotFound': '文件未找到',
'error.invalidInput': '输入无效',
'success.saved': '保存成功',
'confirm.delete': '确定要删除吗?'
};
this.messages.set('zh-CN', defaultMessages);
}
t(key: string, ...args: any[]): string {
const messages = this.messages.get(this.currentLocale) || this.messages.get('zh-CN') || {};
let message = messages[key] || key;
// 替换占位符
if (args.length > 0) {
message = message.replace(/\{(\d+)\}/g, (match: string, index: string) => {
const argIndex = parseInt(index, 10);
return args[argIndex] !== undefined ? args[argIndex] : match;
});
}
return message;
}
getCurrentLocale(): string {
return this.currentLocale;
}
async changeLocale(locale: string): Promise<void> {
this.currentLocale = locale;
await this.loadMessages();
}
}
// 使用示例
const i18n = new I18nManager(context);
// 获取翻译文本
const helloMessage = i18n.t('hello');
const errorMessage = i18n.t('error.fileNotFound');
const confirmMessage = i18n.t('confirm.delete');
// 带参数的翻译
const welcomeMessage = i18n.t('welcome.user', 'John'); // "欢迎,{0}!" -> "欢迎,John!"
// 在命令中使用
TraeAPI.commands.registerCommand('myExtension.showMessage', () => {
TraeAPI.window.showInformationMessage(i18n.t('success.saved'));
});完整扩展示例
typescript
// extension.ts - 完整的扩展示例
import * as TraeAPI from 'trae';
import * as path from 'path';
// 扩展主类
class MyExtension {
private statusBar: TraeAPI.StatusBarItem;
private outputChannel: TraeAPI.OutputChannel;
private configManager: ConfigurationManager;
private stateManager: StateManager;
private disposables: TraeAPI.Disposable[] = [];
constructor(private context: TraeAPI.ExtensionContext) {
this.statusBar = TraeAPI.window.createStatusBarItem(TraeAPI.StatusBarAlignment.Right, 100);
this.outputChannel = TraeAPI.window.createOutputChannel('My Extension');
this.configManager = new ConfigurationManager();
this.stateManager = new StateManager(context.globalState, context.workspaceState);
}
async activate(): Promise<void> {
this.outputChannel.appendLine('扩展正在激活...');
// 注册命令
this.registerCommands();
// 设置状态栏
this.setupStatusBar();
// 监听事件
this.setupEventListeners();
// 初始化功能
await this.initializeFeatures();
this.outputChannel.appendLine('扩展激活完成');
}
private registerCommands(): void {
const commands = [
TraeAPI.commands.registerCommand('myExtension.helloWorld', this.helloWorld.bind(this)),
TraeAPI.commands.registerCommand('myExtension.showStatus', this.showStatus.bind(this)),
TraeAPI.commands.registerCommand('myExtension.openSettings', this.openSettings.bind(this)),
TraeAPI.commands.registerCommand('myExtension.processFile', this.processFile.bind(this))
];
this.disposables.push(...commands);
}
private setupStatusBar(): void {
this.statusBar.text = '$(heart) My Extension';
this.statusBar.tooltip = '点击查看扩展状态';
this.statusBar.command = 'myExtension.showStatus';
this.statusBar.show();
this.disposables.push(this.statusBar);
}
private setupEventListeners(): void {
// 监听文档变化
const docChangeListener = TraeAPI.workspace.onDidChangeTextDocument(e => {
this.onDocumentChanged(e);
});
// 监听配置变化
const configChangeListener = TraeAPI.workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('myExtension')) {
this.onConfigurationChanged();
}
});
this.disposables.push(docChangeListener, configChangeListener);
}
private async initializeFeatures(): Promise<void> {
// 加载用户偏好
const preferences = this.stateManager.getUserPreferences();
this.outputChannel.appendLine(`用户偏好: ${JSON.stringify(preferences)}`);
// 检查配置
const errors = this.configManager.validateConfiguration();
if (errors.length > 0) {
TraeAPI.window.showWarningMessage(`配置错误: ${errors.join(', ')}`);
}
}
// 命令实现
private async helloWorld(): Promise<void> {
const message = 'Hello World from My Extension!';
TraeAPI.window.showInformationMessage(message);
this.outputChannel.appendLine(message);
// 统计使用次数
await this.stateManager.incrementUsageCount('helloWorld');
}
private async showStatus(): Promise<void> {
const stats = this.stateManager.getAllUsageStats();
const config = this.configManager.getAllSettings();
const statusInfo = {
version: this.context.extension.packageJSON.version,
isActive: this.context.extension.isActive,
usageStats: stats,
configuration: config
};
this.outputChannel.appendLine('扩展状态:');
this.outputChannel.appendLine(JSON.stringify(statusInfo, null, 2));
this.outputChannel.show();
}
private async openSettings(): Promise<void> {
await TraeAPI.commands.executeCommand('workbench.action.openSettings', 'myExtension');
}
private async processFile(uri?: TraeAPI.Uri): Promise<void> {
const targetUri = uri || TraeAPI.window.activeTextEditor?.document.uri;
if (!targetUri) {
TraeAPI.window.showWarningMessage('请选择一个文件');
return;
}
try {
const content = await TraeAPI.workspace.fs.readFile(targetUri);
const text = Buffer.from(content).toString();
// 处理文件内容
const processedText = text.toUpperCase();
// 保存处理结果
const outputUri = TraeAPI.Uri.file(targetUri.fsPath + '.processed');
await TraeAPI.workspace.fs.writeFile(outputUri, Buffer.from(processedText));
TraeAPI.window.showInformationMessage(`文件已处理: ${outputUri.fsPath}`);
} catch (error) {
TraeAPI.window.showErrorMessage(`处理文件失败: ${error}`);
}
}
// 事件处理
private onDocumentChanged(e: TraeAPI.TextDocumentChangeEvent): void {
if (e.document.languageId === 'javascript' || e.document.languageId === 'typescript') {
this.statusBar.text = '$(sync~spin) 分析中...';
// 延迟分析
setTimeout(() => {
this.statusBar.text = '$(check) 分析完成';
}, 1000);
}
}
private onConfigurationChanged(): void {
this.outputChannel.appendLine('配置已更改,重新初始化...');
this.initializeFeatures();
}
// 清理资源
dispose(): void {
this.disposables.forEach(d => d.dispose());
this.outputChannel.dispose();
}
}
// 扩展激活函数
export async function activate(context: TraeAPI.ExtensionContext): Promise<void> {
const extension = new MyExtension(context);
await extension.activate();
context.subscriptions.push(extension);
}
// 扩展停用函数
export function deactivate(): void {
console.log('扩展已停用');
}这个完整的扩展 API 参考涵盖了 Trae IDE 扩展开发的所有重要方面,包括基础概念、高级功能、最佳实践和完整示例。通过这些 API,您可以创建功能强大且用户友好的扩展。