0
0
Files
vs-p/out/panels/ConfigPanel.js

1541 lines
68 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigPanel = void 0;
const vscode = __importStar(require("vscode"));
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));
const isomorphic_git_1 = __importDefault(require("isomorphic-git"));
const node_1 = __importDefault(require("isomorphic-git/http/node"));
const ProjectView_1 = require("./views/ProjectView");
const AircraftView_1 = require("./views/AircraftView");
const ContainerView_1 = require("./views/ContainerView");
const ConfigView_1 = require("./views/ConfigView");
class ConfigPanel {
static createOrShow(extensionUri) {
const column = vscode.window.activeTextEditor?.viewColumn || vscode.ViewColumn.One;
if (ConfigPanel.currentPanel) {
ConfigPanel.currentPanel.panel.reveal(column);
return;
}
const panel = vscode.window.createWebviewPanel('DCSP', '数字卫星构建平台', column, {
enableScripts: true,
localResourceRoots: [extensionUri],
retainContextWhenHidden: true
});
ConfigPanel.currentPanel = new ConfigPanel(panel, extensionUri);
}
constructor(panel, extensionUri) {
this.currentView = 'projects';
this.currentProjectId = '';
this.currentAircraftId = '';
this.currentContainerId = '';
this.currentRepoId = '';
// 数据存储
this.projects = [];
this.aircrafts = [];
this.containers = [];
this.configs = [];
this.gitRepos = []; // Git 仓库数据
this.mergedFolders = [];
// Git 文件树
this.currentRepoFileTree = [];
// 项目存储路径映射
this.projectPaths = new Map();
// Webview 状态跟踪
this.isWebviewDisposed = false;
this.panel = panel;
this.extensionUri = extensionUri;
this.isWebviewDisposed = false; // 初始化状态
// 初始化各个视图
this.projectView = new ProjectView_1.ProjectView(extensionUri);
this.aircraftView = new AircraftView_1.AircraftView(extensionUri);
this.containerView = new ContainerView_1.ContainerView(extensionUri);
this.configView = new ConfigView_1.ConfigView(extensionUri);
this.updateWebview();
this.setupMessageListener();
this.panel.onDidDispose(() => {
this.isWebviewDisposed = true; // 标记为已销毁
ConfigPanel.currentPanel = undefined;
});
}
setupMessageListener() {
this.panel.webview.onDidReceiveMessage(async (data) => {
console.log('📨 收到Webview消息:', data);
// 检查 Webview 是否仍然有效
if (this.isWebviewDisposed) {
console.log('⚠️ Webview 已被销毁,忽略消息');
return;
}
try {
switch (data.type) {
case 'openExistingProject':
await this.openExistingProject();
break;
case 'configureProject':
const selectedPath = await this.selectProjectPath(data.projectId, data.projectName);
if (selectedPath) {
this.currentView = 'aircrafts';
this.currentProjectId = data.projectId;
this.updateWebview();
}
break;
case 'openProject':
// 已配置的项目直接打开
this.currentView = 'aircrafts';
this.currentProjectId = data.projectId;
this.updateWebview();
break;
case 'openAircraftConfig':
this.currentView = 'containers';
this.currentProjectId = data.projectId;
this.currentAircraftId = data.aircraftId;
this.updateWebview();
break;
case 'openContainerConfig':
this.currentView = 'configs';
this.currentContainerId = data.containerId;
this.updateWebview();
break;
// 修复返回按钮的消息处理
case 'goBackToProjects':
this.currentView = 'projects';
// 清空当前选择的ID
this.currentProjectId = '';
this.currentAircraftId = '';
this.currentContainerId = '';
this.currentRepoId = '';
this.updateWebview();
break;
case 'goBackToAircrafts':
this.currentView = 'aircrafts';
// 保持 currentProjectId清空其他ID
this.currentAircraftId = '';
this.currentContainerId = '';
this.updateWebview();
break;
case 'goBackToContainers':
this.currentView = 'containers';
// 保持 currentProjectId 和 currentAircraftId清空 currentContainerId
this.currentContainerId = '';
this.updateWebview();
break;
case 'updateProjectName':
await this.updateProjectName(data.projectId, data.name);
break;
case 'createProject':
await this.createProject(data.name);
break;
case 'updateAircraftName':
await this.updateAircraftName(data.aircraftId, data.name);
break;
case 'createAircraft':
await this.createAircraft(data.name);
break;
case 'updateContainerName':
await this.updateContainerName(data.containerId, data.name);
break;
case 'createContainer':
await this.createContainer(data.name);
break;
case 'updateConfigName':
await this.updateConfigName(data.configId, data.name);
break;
case 'createConfig':
await this.createConfig(data.name);
break;
case 'deleteProject':
await this.deleteProject(data.projectId);
break;
case 'deleteAircraft':
await this.deleteAircraft(data.aircraftId);
break;
case 'deleteContainer':
await this.deleteContainer(data.containerId);
break;
case 'deleteConfig':
await this.deleteConfig(data.configId);
break;
// Git 仓库管理功能
case 'fetchBranches':
console.log('🌿 获取分支列表:', data.url);
await this.fetchBranches(data.url);
break;
case 'cloneBranches':
console.log('🚀 克隆选中的分支:', data);
await this.cloneBranches(data.url, data.branches);
break;
case 'cancelBranchSelection':
console.log('❌ 取消分支选择');
this.updateWebview();
break;
case 'loadGitRepo':
await this.loadGitRepo(data.repoId);
break;
case 'syncGitRepo':
await this.syncGitRepo(data.repoId);
break;
case 'deleteGitRepo':
await this.deleteGitRepo(data.repoId);
break;
case 'importGitFile':
await this.importGitFile(data.filePath);
break;
case 'openGitRepoInVSCode':
await this.openGitRepoInVSCode(data.repoId);
break;
case 'openConfigFileInVSCode':
await this.openConfigFileInVSCode(data.configId);
break;
case 'mergeConfigs':
await this.mergeConfigs(data.configIds, data.displayName, data.folderName);
break;
case 'deleteMergedFolder':
await this.deleteMergedFolder(data.folderId);
break;
case 'openMergedFolderInVSCode':
await this.openMergedFolderInVSCode(data.folderId);
break;
case 'loadMergedFolder':
await this.loadMergedFolder(data.folderId);
break;
}
}
catch (error) {
console.error('处理 Webview 消息时出错:', error);
if (!this.isWebviewDisposed) {
vscode.window.showErrorMessage(`处理操作时出错: ${error}`);
}
}
});
}
// === 目录创建方法 ===
/**
* 创建飞行器目录
*/
async createAircraftDirectory(aircraft) {
try {
const projectPath = this.projectPaths.get(aircraft.projectId);
if (!projectPath) {
console.warn('未找到项目路径,跳过创建飞行器目录');
return;
}
const aircraftDir = vscode.Uri.joinPath(vscode.Uri.file(projectPath), aircraft.name);
// 创建飞行器目录
await vscode.workspace.fs.createDirectory(aircraftDir);
console.log(`✅ 创建飞行器目录: ${aircraftDir.fsPath}`);
}
catch (error) {
console.error(`创建飞行器目录失败: ${error}`);
}
}
/**
* 创建容器目录
*/
async createContainerDirectory(container) {
try {
const aircraft = this.aircrafts.find(a => a.id === container.aircraftId);
if (!aircraft) {
console.warn('未找到对应的飞行器,跳过创建容器目录');
return;
}
const projectPath = this.projectPaths.get(aircraft.projectId);
if (!projectPath) {
console.warn('未找到项目路径,跳过创建容器目录');
return;
}
// 构建路径:项目路径/飞行器名/容器名
const aircraftDir = vscode.Uri.joinPath(vscode.Uri.file(projectPath), aircraft.name);
const containerDir = vscode.Uri.joinPath(aircraftDir, container.name);
// 确保飞行器目录存在
try {
await vscode.workspace.fs.createDirectory(aircraftDir);
}
catch (error) {
// 目录可能已存在,忽略错误
}
// 创建容器目录
await vscode.workspace.fs.createDirectory(containerDir);
console.log(`✅ 创建容器目录: ${containerDir.fsPath}`);
}
catch (error) {
console.error(`创建容器目录失败: ${error}`);
}
}
/**
* 确保容器目录存在
*/
async ensureContainerDirectoryExists(containerId) {
try {
const container = this.containers.find(c => c.id === containerId);
if (!container)
return;
const aircraft = this.aircrafts.find(a => a.id === container.aircraftId);
if (!aircraft)
return;
const projectPath = this.projectPaths.get(aircraft.projectId);
if (!projectPath)
return;
// 构建路径并创建目录
const aircraftDir = vscode.Uri.joinPath(vscode.Uri.file(projectPath), aircraft.name);
const containerDir = vscode.Uri.joinPath(aircraftDir, container.name);
await vscode.workspace.fs.createDirectory(aircraftDir);
await vscode.workspace.fs.createDirectory(containerDir);
}
catch (error) {
console.error(`确保容器目录存在失败: ${error}`);
}
}
// === Git 仓库管理方法 ===
/**
* 添加 Git 仓库到容器目录
*/
async addGitRepo(url, name, branch) {
try {
// 验证 URL
if (!url || !url.startsWith('http')) {
vscode.window.showErrorMessage('请输入有效的 Git 仓库 URL');
return;
}
if (!this.currentContainerId) {
vscode.window.showErrorMessage('请先选择容器');
return;
}
const repoId = 'git-' + Date.now();
// 构建本地路径 - 在容器目录下创建分支子目录
const container = this.containers.find(c => c.id === this.currentContainerId);
if (!container) {
vscode.window.showErrorMessage('未找到容器');
return;
}
const aircraft = this.aircrafts.find(a => a.id === container.aircraftId);
if (!aircraft) {
vscode.window.showErrorMessage('未找到飞行器');
return;
}
const projectPath = this.projectPaths.get(aircraft.projectId);
if (!projectPath) {
vscode.window.showErrorMessage('未找到项目路径');
return;
}
// 为每个分支创建独立的子目录
const branchName = branch || 'main';
const branchSafeName = branchName.replace(/[^a-zA-Z0-9-_]/g, '-');
const repoDirName = name;
// 路径:项目路径/飞行器名/容器名/仓库名-分支名/
const localPath = path.join(projectPath, aircraft.name, container.name, repoDirName);
console.log(`📁 Git仓库将保存到: ${localPath}`);
// 检查是否已存在相同 URL 和分支的仓库
const existingRepo = this.gitRepos.find(repo => repo.url === url && repo.branch === branchName && repo.containerId === this.currentContainerId);
if (existingRepo) {
vscode.window.showWarningMessage('该 Git 仓库和分支组合已存在');
return;
}
const newRepo = {
id: repoId,
name: `${name} (${branchName})`,
url: url,
localPath: localPath,
branch: branchName,
lastSync: new Date().toLocaleString(),
containerId: this.currentContainerId
};
console.log(`📁 准备克隆仓库: ${name}, 分支: ${newRepo.branch}, 路径: ${localPath}`);
// 显示进度
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: `正在克隆仓库: ${name} (${newRepo.branch})`,
cancellable: false
}, async (progress) => {
progress.report({ increment: 0 });
try {
// 确保目录存在
await fs.promises.mkdir(localPath, { recursive: true });
// 检查目录是否为空
const dirContents = await fs.promises.readdir(localPath);
if (dirContents.length > 0) {
const confirm = await vscode.window.showWarningMessage(`目标目录不为空,确定要覆盖吗?`, { modal: true }, '确定覆盖', '取消');
if (confirm !== '确定覆盖') {
vscode.window.showInformationMessage('克隆操作已取消');
return;
}
// 清空目录(除了 .git 文件夹,如果存在的话)
for (const item of dirContents) {
const itemPath = path.join(localPath, item);
if (item !== '.git') {
await fs.promises.rm(itemPath, { recursive: true, force: true });
}
}
}
// 克隆仓库
await isomorphic_git_1.default.clone({
fs: fs,
http: node_1.default,
dir: localPath,
url: url,
singleBranch: true,
depth: 1,
ref: branchName,
onProgress: (event) => {
if (event.total) {
const percent = (event.loaded / event.total) * 100;
progress.report({ increment: percent, message: `${event.phase}...` });
}
}
});
console.log('✅ Git克隆成功完成');
this.gitRepos.push(newRepo);
await this.saveCurrentProjectData();
console.log('✅ Git仓库数据已保存到项目文件');
vscode.window.showInformationMessage(`Git 仓库克隆成功: ${name} (${newRepo.branch})`);
// 检查 Webview 状态后再加载文件树
if (!this.isWebviewDisposed) {
console.log('🌳 开始加载仓库文件树...');
// 自动加载仓库文件树
this.currentRepoId = repoId;
await this.loadGitRepoFileTree(repoId);
console.log('✅ 仓库文件树加载完成');
}
else {
console.log('⚠️ Webview 已被销毁,跳过文件树加载');
}
}
catch (error) {
console.error('❌ 在克隆过程中捕获错误:', error);
vscode.window.showErrorMessage(`克隆仓库失败: ${error}`);
}
});
}
catch (error) {
console.error('❌ 在addGitRepo外部捕获错误:', error);
vscode.window.showErrorMessage(`添加 Git 仓库失败: ${error}`);
}
}
/**
* 加载 Git 仓库文件树
*/
async loadGitRepo(repoId) {
this.currentRepoId = repoId;
await this.loadGitRepoFileTree(repoId);
this.updateWebview();
}
/**
* 同步 Git 仓库
*/
async syncGitRepo(repoId) {
const repo = this.gitRepos.find(r => r.id === repoId);
if (!repo) {
vscode.window.showErrorMessage('未找到指定的 Git 仓库');
return;
}
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: `正在同步仓库: ${repo.name}`,
cancellable: false
}, async (progress) => {
try {
progress.report({ increment: 0, message: '拉取最新更改...' });
// 拉取最新更改
await isomorphic_git_1.default.pull({
fs: fs,
http: node_1.default,
dir: repo.localPath,
author: { name: 'DCSP User', email: 'user@dcsp.local' },
fastForward: true
});
// 更新最后同步时间
repo.lastSync = new Date().toLocaleString();
await this.saveCurrentProjectData();
// 重新加载文件树
await this.loadGitRepoFileTree(repoId);
vscode.window.showInformationMessage(`Git 仓库同步成功: ${repo.name}`);
this.updateWebview();
}
catch (error) {
vscode.window.showErrorMessage(`同步 Git 仓库失败: ${error}`);
}
});
}
/**
* 删除 Git 仓库
*/
async deleteGitRepo(repoId) {
const repo = this.gitRepos.find(r => r.id === repoId);
if (!repo)
return;
const confirm = await vscode.window.showWarningMessage(`确定要删除 Git 仓库 "${repo.name}" 吗?这将删除本地文件。`, { modal: true }, '确定删除', '取消');
if (confirm === '确定删除') {
try {
// 删除整个仓库目录(因为是独立目录)
await fs.promises.rm(repo.localPath, { recursive: true, force: true });
// 从列表中移除
this.gitRepos = this.gitRepos.filter(r => r.id !== repoId);
await this.saveCurrentProjectData();
// 如果删除的是当前仓库,清空状态
if (this.currentRepoId === repoId) {
this.currentRepoId = '';
this.currentRepoFileTree = [];
}
vscode.window.showInformationMessage(`Git 仓库已删除: ${repo.name}`);
this.updateWebview();
}
catch (error) {
vscode.window.showErrorMessage(`删除 Git 仓库失败: ${error}`);
}
}
}
/**
* 加载 Git 仓库文件树
*/
async loadGitRepoFileTree(repoId) {
// 检查 Webview 是否仍然有效
if (this.isWebviewDisposed) {
console.log('⚠️ Webview 已被销毁,跳过文件树加载');
return;
}
const repo = this.gitRepos.find(r => r.id === repoId);
if (!repo)
return;
// 通知前端开始加载
try {
this.panel.webview.postMessage({
type: 'gitRepoLoading',
loading: true
});
}
catch (error) {
console.log('⚠️ 无法发送加载消息Webview 可能已被销毁');
return;
}
try {
const fileTree = await this.buildFileTree(repo.localPath);
this.currentRepoFileTree = fileTree;
// 更新最后访问时间
repo.lastSync = new Date().toLocaleString();
await this.saveCurrentProjectData();
}
catch (error) {
console.error('加载仓库文件树失败:', error);
this.currentRepoFileTree = [];
}
// 再次检查 Webview 状态
if (this.isWebviewDisposed) {
console.log('⚠️ Webview 已被销毁,跳过完成通知');
return;
}
// 通知前端加载完成
try {
this.panel.webview.postMessage({
type: 'gitRepoLoading',
loading: false
});
this.updateWebview();
}
catch (error) {
console.log('⚠️ 无法发送完成消息Webview 可能已被销毁');
}
}
/**
* 构建文件树
*/
async buildFileTree(dir, relativePath = '') {
try {
const files = await fs.promises.readdir(dir);
const tree = [];
for (const file of files) {
// 忽略 .git 文件夹和 .dcsp-data.json
if (file.startsWith('.') && file !== '.git')
continue;
if (file === '.dcsp-data.json')
continue;
const filePath = path.join(dir, file);
const stats = await fs.promises.stat(filePath);
const currentRelativePath = path.join(relativePath, file);
if (stats.isDirectory()) {
const children = await this.buildFileTree(filePath, currentRelativePath);
tree.push({
name: file,
type: 'folder',
path: currentRelativePath,
children: children
});
}
else {
tree.push({
name: file,
type: 'file',
path: currentRelativePath
});
}
}
return tree;
}
catch (error) {
console.error('构建文件树失败:', error);
return [];
}
}
/**
* 导入 Git 文件到当前容器
*/
async importGitFile(filePath) {
if (!this.currentRepoId || !this.currentContainerId) {
vscode.window.showErrorMessage('请先选择 Git 仓库和容器');
return;
}
const repo = this.gitRepos.find(r => r.id === this.currentRepoId);
if (!repo) {
vscode.window.showErrorMessage('未找到当前 Git 仓库');
return;
}
const container = this.containers.find(c => c.id === this.currentContainerId);
if (!container) {
vscode.window.showErrorMessage('未找到当前容器');
return;
}
try {
const fullPath = path.join(repo.localPath, filePath);
const content = await fs.promises.readFile(fullPath, 'utf8');
const fileName = path.basename(filePath);
// 创建新配置
const newId = 'cfg' + (this.configs.length + 1);
const newConfig = {
id: newId,
name: fileName,
fileName: fileName,
content: content,
containerId: this.currentContainerId
};
this.configs.push(newConfig);
await this.saveCurrentProjectData();
vscode.window.showInformationMessage(`文件已导入到容器 ${container.name}: ${fileName}`);
this.updateWebview();
}
catch (error) {
vscode.window.showErrorMessage(`导入文件失败: ${error}`);
}
}
// === 原有项目配置管理方法 ===
// === 打开现有项目功能 ===
async openExistingProject() {
try {
const result = await vscode.window.showOpenDialog({
canSelectFiles: false,
canSelectFolders: true,
canSelectMany: false,
openLabel: '选择项目文件夹',
title: '选择包含项目数据的文件夹'
});
if (result && result.length > 0) {
const selectedPath = result[0].fsPath;
await this.loadProjectData(selectedPath);
}
}
catch (error) {
vscode.window.showErrorMessage(`打开项目时出错: ${error}`);
}
}
// === 数据持久化方法 ===
/**
* 保存当前项目数据到项目路径
*/
async saveCurrentProjectData() {
try {
if (!this.currentProjectId) {
console.warn('未找到当前项目,数据将不会保存');
return;
}
const projectPath = this.projectPaths.get(this.currentProjectId);
if (!projectPath) {
console.warn('未找到项目存储路径,数据将不会保存');
return;
}
const dataUri = vscode.Uri.joinPath(vscode.Uri.file(projectPath), '.dcsp-data.json');
// 只保存与当前项目相关的数据
const currentProjectAircrafts = this.aircrafts.filter(a => a.projectId === this.currentProjectId);
const currentAircraftIds = currentProjectAircrafts.map(a => a.id);
const currentProjectContainers = this.containers.filter(c => currentAircraftIds.includes(c.aircraftId));
const currentContainerIds = currentProjectContainers.map(c => c.id);
const currentProjectConfigs = this.configs.filter(cfg => currentContainerIds.includes(cfg.containerId));
// 只保存与当前项目容器相关的 Git 仓库和合并文件夹
const currentProjectGitRepos = this.gitRepos.filter(repo => currentContainerIds.includes(repo.containerId));
const currentProjectMergedFolders = this.mergedFolders.filter(folder => currentContainerIds.includes(folder.containerId));
const data = {
projects: this.projects.filter(p => p.id === this.currentProjectId),
aircrafts: currentProjectAircrafts,
containers: currentProjectContainers,
configs: currentProjectConfigs,
gitRepos: currentProjectGitRepos,
mergedFolders: currentProjectMergedFolders // 保存合并文件夹数据
};
const uint8Array = new TextEncoder().encode(JSON.stringify(data, null, 2));
await vscode.workspace.fs.writeFile(dataUri, uint8Array);
console.log('✅ 当前项目数据已保存,包含', currentProjectGitRepos.length, '个 Git 仓库和', currentProjectMergedFolders.length, '个合并文件夹');
}
catch (error) {
vscode.window.showErrorMessage(`保存项目数据失败: ${error}`);
}
}
/**
* 从项目路径加载数据
*/
async loadProjectData(projectPath) {
try {
const dataUri = vscode.Uri.joinPath(vscode.Uri.file(projectPath), '.dcsp-data.json');
// 检查数据文件是否存在
try {
await vscode.workspace.fs.stat(dataUri);
}
catch {
vscode.window.showErrorMessage('选择的文件夹中没有找到项目数据文件 (.dcsp-data.json)');
return false;
}
// 读取数据文件
const fileData = await vscode.workspace.fs.readFile(dataUri);
const dataStr = new TextDecoder().decode(fileData);
const data = JSON.parse(dataStr);
// 清空现有数据
this.projects = [];
this.aircrafts = [];
this.containers = [];
this.configs = [];
this.gitRepos = [];
this.mergedFolders = []; // 清空合并文件夹数据
// 验证数据格式并加载
if (data.projects && Array.isArray(data.projects)) {
this.projects = data.projects;
}
if (data.aircrafts && Array.isArray(data.aircrafts)) {
this.aircrafts = data.aircrafts;
}
if (data.containers && Array.isArray(data.containers)) {
this.containers = data.containers;
}
if (data.configs && Array.isArray(data.configs)) {
this.configs = data.configs;
}
if (data.gitRepos && Array.isArray(data.gitRepos)) {
this.gitRepos = data.gitRepos;
}
if (data.mergedFolders && Array.isArray(data.mergedFolders)) {
this.mergedFolders = data.mergedFolders; // 加载合并文件夹数据
}
// 设置当前项目为第一个项目(如果有的话)
if (this.projects.length > 0) {
this.currentProjectId = this.projects[0].id;
this.projectPaths.set(this.currentProjectId, projectPath);
this.currentView = 'aircrafts';
}
vscode.window.showInformationMessage(`项目数据已从 ${projectPath} 加载,包含 ${this.gitRepos.length} 个 Git 仓库和 ${this.mergedFolders.length} 个合并文件夹`);
this.updateWebview();
return true;
}
catch (error) {
vscode.window.showErrorMessage(`加载项目数据失败: ${error}`);
return false;
}
}
/**
* 检查项目路径是否已存在数据
*/
async checkProjectPathHasData(projectPath) {
try {
const dataUri = vscode.Uri.joinPath(vscode.Uri.file(projectPath), '.dcsp-data.json');
await vscode.workspace.fs.stat(dataUri);
return true;
}
catch {
return false;
}
}
// === 项目路径选择 ===
async selectProjectPath(projectId, projectName) {
try {
// 选择现有路径或输入新路径
const choice = await vscode.window.showQuickPick([
{
label: '$(folder) 选择现有文件夹',
description: '从文件系统中选择已存在的文件夹',
value: 'select'
},
{
label: '$(new-folder) 创建新文件夹',
description: '输入新文件夹路径(将自动创建)',
value: 'create'
}
], {
placeHolder: '选择项目存储方式'
});
if (!choice) {
return null;
}
if (choice.value === 'select') {
// 选择现有路径
const result = await vscode.window.showOpenDialog({
canSelectFiles: false,
canSelectFolders: true,
canSelectMany: false,
openLabel: `选择 ${projectName} 的存储位置`,
title: `为项目 "${projectName}" 选择存储文件夹`
});
if (result && result.length > 0) {
const selectedPath = result[0].fsPath;
// 检查是否已存在数据
const hasExistingData = await this.checkProjectPathHasData(selectedPath);
if (hasExistingData) {
const loadChoice = await vscode.window.showWarningMessage(`在路径 ${selectedPath} 中检测到现有项目数据,是否加载?`, { modal: true }, '是,加载现有数据', '否,创建新项目');
if (loadChoice === '是,加载现有数据') {
// 加载现有数据
const success = await this.loadProjectData(selectedPath);
if (success) {
this.projectPaths.set(projectId, selectedPath);
this.currentView = 'aircrafts';
this.currentProjectId = projectId;
this.updateWebview();
vscode.window.showInformationMessage(`项目数据已从 ${selectedPath} 加载`);
return selectedPath;
}
}
// 如果选择不加载或加载失败,继续创建新项目
}
this.projectPaths.set(projectId, selectedPath);
vscode.window.showInformationMessage(`项目存储位置已设置: ${selectedPath}`);
// 保存初始数据
await this.saveCurrentProjectData();
return selectedPath;
}
}
else {
// 创建新路径
const pathInput = await vscode.window.showInputBox({
prompt: '请输入项目存储路径(绝对路径)',
placeHolder: `/path/to/your/project/${projectName}`,
validateInput: (value) => {
if (!value) {
return '路径不能为空';
}
return null;
}
});
if (pathInput) {
try {
// 尝试创建目录
const dirUri = vscode.Uri.file(pathInput);
await vscode.workspace.fs.createDirectory(dirUri);
this.projectPaths.set(projectId, pathInput);
vscode.window.showInformationMessage(`项目存储位置已创建: ${pathInput}`);
// 保存初始数据
await this.saveCurrentProjectData();
return pathInput;
}
catch (error) {
vscode.window.showErrorMessage(`创建目录失败: ${error}`);
return null;
}
}
}
return null;
}
catch (error) {
vscode.window.showErrorMessage(`选择存储路径时出错: ${error}`);
return null;
}
}
// 更新项目名
async updateProjectName(projectId, newName) {
const project = this.projects.find(p => p.id === projectId);
if (project) {
project.name = newName;
vscode.window.showInformationMessage(`项目名称更新: ${newName}`);
await this.saveCurrentProjectData();
this.updateWebview();
}
}
// 创建新项目
async createProject(name) {
const newId = 'p' + (this.projects.length + 1);
const newProject = {
id: newId,
name: name
};
this.projects.push(newProject);
vscode.window.showInformationMessage(`新建项目: ${name}`);
this.updateWebview();
}
// 删除项目
async deleteProject(projectId) {
const project = this.projects.find(p => p.id === projectId);
if (!project)
return;
this.projects = this.projects.filter(p => p.id !== projectId);
// 删除相关的飞行器
const relatedAircrafts = this.aircrafts.filter(a => a.projectId === projectId);
const aircraftIds = relatedAircrafts.map(a => a.id);
this.aircrafts = this.aircrafts.filter(a => a.projectId !== projectId);
// 删除相关的容器
this.containers = this.containers.filter(c => !aircraftIds.includes(c.aircraftId));
// 删除相关的配置
const containerIds = this.containers.filter(c => aircraftIds.includes(c.aircraftId)).map(c => c.id);
this.configs = this.configs.filter(cfg => !containerIds.includes(cfg.containerId));
// 删除相关的 Git 仓库
this.gitRepos = this.gitRepos.filter(repo => !containerIds.includes(repo.containerId));
// 删除项目路径映射
this.projectPaths.delete(projectId);
vscode.window.showInformationMessage(`删除项目: ${project.name}`);
await this.saveCurrentProjectData();
this.updateWebview();
}
// 更新飞行器名
async updateAircraftName(aircraftId, newName) {
const aircraft = this.aircrafts.find(a => a.id === aircraftId);
if (aircraft) {
aircraft.name = newName;
vscode.window.showInformationMessage(`飞行器名称更新: ${newName}`);
await this.saveCurrentProjectData();
this.updateWebview();
}
}
// 创建新飞行器
async createAircraft(name) {
if (!this.currentProjectId) {
vscode.window.showErrorMessage('无法创建飞行器:未找到当前项目');
return;
}
const newId = 'a' + (this.aircrafts.length + 1);
const newAircraft = {
id: newId,
name: name,
projectId: this.currentProjectId
};
this.aircrafts.push(newAircraft);
// 创建飞行器目录
await this.createAircraftDirectory(newAircraft);
vscode.window.showInformationMessage(`新建飞行器: ${name}`);
await this.saveCurrentProjectData();
this.updateWebview();
}
// 删除飞行器
async deleteAircraft(aircraftId) {
const aircraft = this.aircrafts.find(a => a.id === aircraftId);
if (!aircraft)
return;
this.aircrafts = this.aircrafts.filter(a => a.id !== aircraftId);
// 删除相关的容器
this.containers = this.containers.filter(c => c.aircraftId !== aircraftId);
// 删除相关的配置
const containerIds = this.containers.filter(c => c.aircraftId === aircraftId).map(c => c.id);
this.configs = this.configs.filter(cfg => !containerIds.includes(cfg.containerId));
// 删除相关的 Git 仓库
this.gitRepos = this.gitRepos.filter(repo => !containerIds.includes(repo.containerId));
vscode.window.showInformationMessage(`删除飞行器: ${aircraft.name}`);
await this.saveCurrentProjectData();
this.updateWebview();
}
// 更新容器名
async updateContainerName(containerId, newName) {
const container = this.containers.find(c => c.id === containerId);
if (container) {
container.name = newName;
vscode.window.showInformationMessage(`容器名称更新: ${newName}`);
await this.saveCurrentProjectData();
this.updateWebview();
}
}
// 创建新容器
async createContainer(name) {
if (!this.currentAircraftId) {
vscode.window.showErrorMessage('无法创建容器:未找到当前飞行器');
return;
}
const newId = 'c' + (this.containers.length + 1);
const newContainer = {
id: newId,
name: name,
aircraftId: this.currentAircraftId
};
this.containers.push(newContainer);
// 创建容器目录
await this.createContainerDirectory(newContainer);
// 创建两个默认配置文件
const configCount = this.configs.length;
// 第一个配置文件
this.configs.push({
id: 'cfg' + (configCount + 1),
name: '配置1',
fileName: 'dockerfile',
content: `# ${name} 的 Dockerfile\nFROM ubuntu:20.04\n\n# 设置工作目录\nWORKDIR /app\n\n# 复制文件\nCOPY . .\n\n# 安装依赖\nRUN apt-get update && apt-get install -y \\\n python3 \\\n python3-pip\n\n# 暴露端口\nEXPOSE 8080\n\n# 启动命令\nCMD ["python3", "app.py"]`,
containerId: newId
});
// 第二个配置文件
this.configs.push({
id: 'cfg' + (configCount + 2),
name: '配置2',
fileName: 'docker-compose.yml',
content: `# ${name} 的 Docker Compose 配置\nversion: '3.8'\n\nservices:\n ${name.toLowerCase().replace(/\\s+/g, '-')}:\n build: .\n container_name: ${name}\n ports:\n - "8080:8080"\n environment:\n - NODE_ENV=production\n volumes:\n - ./data:/app/data\n restart: unless-stopped`,
containerId: newId
});
vscode.window.showInformationMessage(`新建容器: ${name} (包含2个默认配置文件)`);
await this.saveCurrentProjectData();
this.updateWebview();
}
// 删除容器
async deleteContainer(containerId) {
const container = this.containers.find(c => c.id === containerId);
if (!container)
return;
// 删除容器
this.containers = this.containers.filter(c => c.id !== containerId);
// 删除相关的配置
this.configs = this.configs.filter(cfg => cfg.containerId !== containerId);
// 删除相关的 Git 仓库
this.gitRepos = this.gitRepos.filter(repo => repo.containerId !== containerId);
vscode.window.showInformationMessage(`删除容器: ${container.name}`);
await this.saveCurrentProjectData();
this.updateWebview();
}
// 更新配置名
async updateConfigName(configId, newName) {
const config = this.configs.find(c => c.id === configId);
if (config) {
config.name = newName;
vscode.window.showInformationMessage(`配置名称更新: ${newName}`);
await this.saveCurrentProjectData();
this.updateWebview();
}
}
// 创建新配置文件
async createConfig(name) {
const newId = 'cfg' + (this.configs.length + 1);
const newConfig = {
id: newId,
name: name,
fileName: name.toLowerCase().replace(/\s+/g, '_'),
content: `# ${name} 配置文件\n# 创建时间: ${new Date().toLocaleString()}\n# 您可以在此编辑配置内容\n\n`,
containerId: this.currentContainerId
};
this.configs.push(newConfig);
// 确保容器目录存在
await this.ensureContainerDirectoryExists(this.currentContainerId);
vscode.window.showInformationMessage(`新建配置: ${name}`);
await this.saveCurrentProjectData();
this.updateWebview();
}
// 删除配置文件 - 修复版本,同时删除磁盘文件
async deleteConfig(configId) {
const config = this.configs.find(c => c.id === configId);
if (!config)
return;
const confirm = await vscode.window.showWarningMessage(`确定要删除配置文件 "${config.name}" 吗?这将同时删除磁盘上的文件。`, { modal: true }, '确定删除', '取消');
if (confirm !== '确定删除') {
return;
}
try {
// 从内存中删除配置
this.configs = this.configs.filter(c => c.id !== configId);
// 删除磁盘上的配置文件
const container = this.containers.find(c => c.id === config.containerId);
if (container) {
const aircraft = this.aircrafts.find(a => a.id === container.aircraftId);
if (aircraft) {
const projectPath = this.projectPaths.get(aircraft.projectId);
if (projectPath) {
const filePath = path.join(projectPath, aircraft.name, container.name, config.fileName);
// 检查文件是否存在,如果存在则删除
if (fs.existsSync(filePath)) {
await fs.promises.unlink(filePath);
console.log(`✅ 已删除配置文件: ${filePath}`);
}
}
}
}
vscode.window.showInformationMessage(`删除配置: ${config.name}`);
await this.saveCurrentProjectData();
this.updateWebview();
}
catch (error) {
vscode.window.showErrorMessage(`删除配置文件失败: ${error}`);
}
}
// === Git 分支管理 ===
async fetchBranches(url) {
try {
console.log('🌿 开始获取分支列表:', url);
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: '正在获取分支信息',
cancellable: false
}, async (progress) => {
progress.report({ increment: 0, message: '连接远程仓库...' });
try {
// 使用 isomorphic-git 的 listServerRefs
progress.report({ increment: 30, message: '获取远程引用...' });
console.log('🔍 使用 listServerRefs 获取分支信息...');
const refs = await isomorphic_git_1.default.listServerRefs({
http: node_1.default,
url: url
});
console.log('📋 获取到的引用:', refs);
// 过滤出分支引用 (refs/heads/ 和 refs/remotes/origin/)
const branchRefs = refs.filter(ref => ref.ref.startsWith('refs/heads/') || ref.ref.startsWith('refs/remotes/origin/'));
console.log('🌿 过滤后的分支引用:', branchRefs);
// 构建分支数据 - 修复分支名称显示
const branches = branchRefs.map(ref => {
let branchName;
if (ref.ref.startsWith('refs/remotes/')) {
// 远程分支:移除 refs/remotes/origin/ 前缀
branchName = ref.ref.replace('refs/remotes/origin/', '');
}
else {
// 本地分支:移除 refs/heads/ 前缀
branchName = ref.ref.replace('refs/heads/', '');
}
return {
name: branchName,
isCurrent: branchName === 'main' || branchName === 'master',
selected: false // 所有分支默认不选中
};
});
console.log('🎯 最终分支列表:', branches);
if (branches.length === 0) {
throw new Error('未找到任何分支');
}
progress.report({ increment: 80, message: '处理分支数据...' });
// === 新增:构建分支树状结构 ===
const branchTree = this.buildBranchTree(branches);
console.log('🌳 构建的分支树结构:', branchTree);
// 发送分支数据到前端 - 同时包含扁平列表和树状结构
if (!this.isWebviewDisposed) {
this.panel.webview.postMessage({
type: 'branchesFetched',
branches: branches,
branchTree: branchTree,
repoUrl: url
});
}
progress.report({ increment: 100, message: '完成' });
}
catch (error) {
console.error('❌ 使用 listServerRefs 获取分支失败:', error);
// 只在右下角显示分支获取失败的通知,不模拟分支数据
vscode.window.showErrorMessage(`获取分支失败: ${error}`);
}
});
}
catch (error) {
console.error('❌ 获取分支失败:', error);
vscode.window.showErrorMessage(`获取分支失败: ${error}`);
}
}
/**
* 构建分支树状结构
*/
buildBranchTree(branches) {
const root = [];
branches.forEach(branch => {
const parts = branch.name.split('/');
let currentLevel = root;
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
const isLeaf = i === parts.length - 1;
const fullName = parts.slice(0, i + 1).join('/');
let node = currentLevel.find((n) => n.name === part);
if (!node) {
node = {
name: part,
fullName: fullName,
isLeaf: isLeaf,
children: [],
level: i,
expanded: true // 默认展开
};
currentLevel.push(node);
}
if (isLeaf) {
// 叶子节点存储分支信息
node.branch = branch;
}
currentLevel = node.children;
}
});
return root;
}
async cloneBranches(url, branches) {
try {
console.log('🚀 开始克隆分支:', { url, branches });
// 显示总进度
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: `正在克隆 ${branches.length} 个分支`,
cancellable: false
}, async (progress) => {
for (let i = 0; i < branches.length; i++) {
const branch = branches[i];
const progressPercent = (i / branches.length) * 100;
progress.report({
increment: progressPercent,
message: `克隆分支: ${branch} (${i + 1}/${branches.length})`
});
console.log(`📥 克隆分支: ${branch}`);
await this.addGitRepo(url, this.generateRepoName(url, branch), branch);
}
});
vscode.window.showInformationMessage(`成功克隆 ${branches.length} 个分支`);
}
catch (error) {
console.error('❌ 克隆分支失败:', error);
vscode.window.showErrorMessage(`克隆分支失败: ${error}`);
}
}
generateRepoName(url, branch) {
const repoName = url.split('/').pop()?.replace('.git', '') || 'unknown-repo';
const branchSafeName = branch.replace(/[^a-zA-Z0-9-_]/g, '-');
return `${repoName}-${branchSafeName}`;
}
// 更新视图
updateWebview() {
// 检查 Webview 是否仍然有效
if (this.isWebviewDisposed) {
console.log('⚠️ Webview 已被销毁,跳过更新');
return;
}
try {
this.panel.webview.html = this.getWebviewContent();
}
catch (error) {
console.error('更新 Webview 失败:', error);
}
}
getWebviewContent() {
switch (this.currentView) {
case 'projects':
return this.projectView.render({
projects: this.projects,
projectPaths: this.projectPaths
});
case 'aircrafts':
const projectAircrafts = this.aircrafts.filter(a => a.projectId === this.currentProjectId);
return this.aircraftView.render({
aircrafts: projectAircrafts
});
case 'containers':
const currentProject = this.projects.find(p => p.id === this.currentProjectId);
const currentAircraft = this.aircrafts.find(a => a.id === this.currentAircraftId);
const projectContainers = this.containers.filter(c => c.aircraftId === this.currentAircraftId);
return this.containerView.render({
project: currentProject,
aircraft: currentAircraft,
containers: projectContainers
});
case 'configs':
const currentContainer = this.containers.find(c => c.id === this.currentContainerId);
const containerConfigs = this.configs.filter(cfg => cfg.containerId === this.currentContainerId);
const currentRepo = this.gitRepos.find(r => r.id === this.currentRepoId);
// 获取当前容器的 Git 仓库和合并文件夹
const containerGitRepos = this.gitRepos.filter(repo => repo.containerId === this.currentContainerId);
const containerMergedFolders = this.mergedFolders.filter(folder => folder.containerId === this.currentContainerId);
return this.configView.render({
container: currentContainer,
configs: containerConfigs,
gitRepos: containerGitRepos,
currentGitRepo: currentRepo,
gitFileTree: this.currentRepoFileTree,
gitLoading: false,
mergedFolders: containerMergedFolders // 传递合并文件夹数据
});
default:
return this.projectView.render({
projects: this.projects,
projectPaths: this.projectPaths
});
}
}
async openGitRepoInVSCode(repoId) {
const repo = this.gitRepos.find(r => r.id === repoId);
if (!repo) {
vscode.window.showErrorMessage('未找到指定的 Git 仓库');
return;
}
try {
// 检查仓库目录是否存在
if (!fs.existsSync(repo.localPath)) {
vscode.window.showErrorMessage('Git 仓库目录不存在,请重新克隆');
return;
}
// 使用 VSCode 的文件选择器让用户选择要打开的文件
const fileUri = await vscode.window.showOpenDialog({
defaultUri: vscode.Uri.file(repo.localPath),
canSelectFiles: true,
canSelectFolders: false,
canSelectMany: false,
openLabel: '选择要打开的文件',
title: `${repo.name} 中选择文件`
});
if (fileUri && fileUri.length > 0) {
// 打开选中的文件
const document = await vscode.workspace.openTextDocument(fileUri[0]);
await vscode.window.showTextDocument(document);
vscode.window.showInformationMessage(`已打开文件: ${path.basename(fileUri[0].fsPath)}`);
}
}
catch (error) {
vscode.window.showErrorMessage(`打开 Git 仓库文件失败: ${error}`);
}
}
async openConfigFileInVSCode(configId) {
const config = this.configs.find(c => c.id === configId);
if (!config) {
vscode.window.showErrorMessage('未找到配置文件');
return;
}
const container = this.containers.find(c => c.id === config.containerId);
if (!container) {
vscode.window.showErrorMessage('未找到容器');
return;
}
const aircraft = this.aircrafts.find(a => a.id === container.aircraftId);
if (!aircraft) {
vscode.window.showErrorMessage('未找到飞行器');
return;
}
const projectPath = this.projectPaths.get(aircraft.projectId);
if (!projectPath) {
vscode.window.showErrorMessage('未设置项目存储路径');
return;
}
// 构建文件路径
const filePath = path.join(projectPath, aircraft.name, container.name, config.fileName);
try {
// 检查文件是否存在
if (!fs.existsSync(filePath)) {
vscode.window.showWarningMessage('配置文件不存在,将创建新文件');
// 确保目录存在
const dirPath = path.dirname(filePath);
await fs.promises.mkdir(dirPath, { recursive: true });
// 创建文件
await fs.promises.writeFile(filePath, config.content || '');
}
// 在 VSCode 中打开文件
const document = await vscode.workspace.openTextDocument(filePath);
await vscode.window.showTextDocument(document);
}
catch (error) {
vscode.window.showErrorMessage(`打开配置文件失败: ${error}`);
}
}
async mergeConfigs(configIds, displayName, folderName) {
try {
if (!this.currentContainerId) {
vscode.window.showErrorMessage('未找到当前容器');
return;
}
if (configIds.length < 2) {
vscode.window.showErrorMessage('请至少选择两个配置文件进行合并');
return;
}
const container = this.containers.find(c => c.id === this.currentContainerId);
if (!container) {
vscode.window.showErrorMessage('未找到容器');
return;
}
const aircraft = this.aircrafts.find(a => a.id === container.aircraftId);
if (!aircraft) {
vscode.window.showErrorMessage('未找到飞行器');
return;
}
const projectPath = this.projectPaths.get(aircraft.projectId);
if (!projectPath) {
vscode.window.showErrorMessage('未设置项目存储路径');
return;
}
// 获取选中的配置文件
const selectedConfigs = this.configs.filter(config => configIds.includes(config.id));
if (selectedConfigs.length !== configIds.length) {
vscode.window.showErrorMessage('部分配置文件未找到');
return;
}
// 创建合并文件夹
const mergeFolderPath = path.join(projectPath, aircraft.name, container.name, folderName);
await fs.promises.mkdir(mergeFolderPath, { recursive: true });
// 将选中的配置文件复制到合并文件夹中
const copiedFiles = [];
for (const config of selectedConfigs) {
const sourcePath = path.join(projectPath, aircraft.name, container.name, config.fileName);
const targetPath = path.join(mergeFolderPath, config.fileName);
if (fs.existsSync(sourcePath)) {
await fs.promises.copyFile(sourcePath, targetPath);
copiedFiles.push(config.fileName);
console.log(`✅ 已复制配置文件: ${config.fileName}`);
}
else {
// 如果源文件不存在,创建新文件
await fs.promises.writeFile(targetPath, config.content || '');
copiedFiles.push(config.fileName);
console.log(`✅ 已创建配置文件: ${config.fileName}`);
}
}
// 创建合并文件夹记录
const newFolder = {
id: 'merged-' + Date.now(),
displayName: displayName,
folderName: folderName,
path: mergeFolderPath,
fileCount: copiedFiles.length,
containerId: this.currentContainerId,
originalConfigIds: configIds,
createdAt: new Date().toLocaleString()
};
// 添加到合并文件夹列表
this.mergedFolders.push(newFolder);
// 删除原始配置文件
for (const configId of configIds) {
await this.deleteConfigInternal(configId);
}
// 保存数据
await this.saveCurrentProjectData();
vscode.window.showInformationMessage(`成功合并 ${selectedConfigs.length} 个配置文件到文件夹: ${folderName}`);
// 更新UI不自动打开文件夹
this.updateWebview();
}
catch (error) {
console.error('❌ 合并配置文件失败:', error);
vscode.window.showErrorMessage(`合并配置文件失败: ${error}`);
}
}
/**
* 内部删除配置文件方法(不显示确认对话框)
*/
async deleteConfigInternal(configId) {
try {
const config = this.configs.find(c => c.id === configId);
if (!config)
return;
// 从内存中删除配置
this.configs = this.configs.filter(c => c.id !== configId);
// 删除磁盘上的配置文件
const container = this.containers.find(c => c.id === config.containerId);
if (container) {
const aircraft = this.aircrafts.find(a => a.id === container.aircraftId);
if (aircraft) {
const projectPath = this.projectPaths.get(aircraft.projectId);
if (projectPath) {
const filePath = path.join(projectPath, aircraft.name, container.name, config.fileName);
// 检查文件是否存在,如果存在则删除
if (fs.existsSync(filePath)) {
await fs.promises.unlink(filePath);
console.log(`✅ 已删除配置文件: ${filePath}`);
}
}
}
}
console.log(`✅ 内部删除配置: ${config.name}`);
}
catch (error) {
console.error(`删除配置文件失败: ${error}`);
}
}
/**
* 删除合并文件夹
*/
async deleteMergedFolder(folderId) {
const folder = this.mergedFolders.find(f => f.id === folderId);
if (!folder)
return;
const confirm = await vscode.window.showWarningMessage(`确定要删除合并文件夹 "${folder.displayName}" 吗?这将删除文件夹及其所有内容。`, { modal: true }, '确定删除', '取消');
if (confirm === '确定删除') {
try {
// 删除文件夹及其所有内容
await fs.promises.rm(folder.path, { recursive: true, force: true });
// 从列表中移除
this.mergedFolders = this.mergedFolders.filter(f => f.id !== folderId);
await this.saveCurrentProjectData();
vscode.window.showInformationMessage(`合并文件夹已删除: ${folder.displayName}`);
this.updateWebview();
}
catch (error) {
vscode.window.showErrorMessage(`删除合并文件夹失败: ${error}`);
}
}
}
/**
* 在 VSCode 中打开合并文件夹
*/
async openMergedFolderInVSCode(folderId) {
const folder = this.mergedFolders.find(f => f.id === folderId);
if (!folder) {
vscode.window.showErrorMessage('未找到指定的合并文件夹');
return;
}
try {
// 检查文件夹是否存在
if (!fs.existsSync(folder.path)) {
vscode.window.showErrorMessage('合并文件夹不存在');
return;
}
// 使用 VSCode 打开文件夹
const folderUri = vscode.Uri.file(folder.path);
vscode.commands.executeCommand('vscode.openFolder', folderUri, { forceNewWindow: false });
}
catch (error) {
vscode.window.showErrorMessage(`打开合并文件夹失败: ${error}`);
}
}
async loadMergedFolder(folderId) {
const folder = this.mergedFolders.find(f => f.id === folderId);
if (!folder) {
vscode.window.showErrorMessage('未找到指定的合并文件夹');
return;
}
try {
// 检查文件夹是否存在
if (!fs.existsSync(folder.path)) {
vscode.window.showErrorMessage('合并文件夹目录不存在');
return;
}
// 使用 VSCode 的文件选择器让用户选择要打开的文件
const fileUri = await vscode.window.showOpenDialog({
defaultUri: vscode.Uri.file(folder.path),
canSelectFiles: true,
canSelectFolders: false,
canSelectMany: false,
openLabel: '选择要打开的文件',
title: `在合并文件夹 ${folder.displayName} 中选择文件`
});
if (fileUri && fileUri.length > 0) {
// 打开选中的文件
const document = await vscode.workspace.openTextDocument(fileUri[0]);
await vscode.window.showTextDocument(document);
vscode.window.showInformationMessage(`已打开文件: ${path.basename(fileUri[0].fsPath)}`);
}
}
catch (error) {
vscode.window.showErrorMessage(`打开合并文件夹文件失败: ${error}`);
}
}
}
exports.ConfigPanel = ConfigPanel;
//# sourceMappingURL=ConfigPanel.js.map