- 修改model.ts的saveFileContent方法,在上传文件前先通过C++服务验证脚本 - 如果C++服务可连接,则先发送脚本进行编译验证,只有在返回200状态码(编译通过)后才上传到服务器 - 如果C++服务返回非200状态码(编译失败),则不允许上传并提示错误 - 如果C++服务不可连接,则直接上传到服务器 - 简化extension.ts中的保存事件监听器,仅执行UI更新和缓存更新 - 保持原有错误处理机制,确保在C++服务故障时也能正常上传文件 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
325 lines
13 KiB
JavaScript
325 lines
13 KiB
JavaScript
"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 () {
|
||
var ownKeys = function(o) {
|
||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||
var ar = [];
|
||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||
return ar;
|
||
};
|
||
return ownKeys(o);
|
||
};
|
||
return function (mod) {
|
||
if (mod && mod.__esModule) return mod;
|
||
var result = {};
|
||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||
__setModuleDefault(result, mod);
|
||
return result;
|
||
};
|
||
})();
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
exports.FileModel = void 0;
|
||
const vscode = __importStar(require("vscode"));
|
||
const apiClient_1 = require("./apiClient");
|
||
const localClient_1 = require("./localClient");
|
||
class FileModel {
|
||
constructor() {
|
||
this.fileList = new Map();
|
||
this.isConnected = false;
|
||
this.apiClient = new apiClient_1.ApiClient();
|
||
this.config = vscode.workspace.getConfiguration('squirrel');
|
||
}
|
||
// 更新配置
|
||
updateConfig() {
|
||
this.config = vscode.workspace.getConfiguration('squirrel');
|
||
const baseUrl = this.config.get('api.baseUrl', 'http://localhost');
|
||
const port = this.config.get('api.port', 8080);
|
||
this.apiClient.updateConfig(baseUrl, port);
|
||
}
|
||
// 连接到API
|
||
async connect() {
|
||
try {
|
||
this.updateConfig();
|
||
const baseUrl = this.config.get('api.baseUrl', 'http://localhost');
|
||
const port = this.config.get('api.port', 8080);
|
||
const defaultDir = this.config.get('defaultDirectory', 'sqr');
|
||
console.log(`尝试连接到: ${baseUrl}:${port}, 目录: ${defaultDir}`);
|
||
// 首先检查版本号
|
||
console.log('正在检查 pvfUtility 版本号...');
|
||
const version = await this.apiClient.getVersion();
|
||
console.log(`pvfUtility 版本: ${version}`);
|
||
// 测试连接并获取文件列表
|
||
const filesData = await this.apiClient.getFileList(defaultDir);
|
||
console.log(`API返回数据: ${JSON.stringify(filesData)}`);
|
||
// 将字符串按换行符分割成数组
|
||
const files = filesData.split(/\r?\n/).filter((file) => file.trim() !== '');
|
||
console.log(`成功获取到 ${files.length} 个文件`);
|
||
this.fileList.clear();
|
||
files.forEach((filePath) => {
|
||
const entry = {
|
||
key: filePath,
|
||
name: filePath.split('/').pop() || filePath,
|
||
isFile: true
|
||
};
|
||
this.fileList.set(filePath, entry);
|
||
});
|
||
// 自动加载所有文件内容
|
||
console.log('开始自动加载所有文件内容...');
|
||
await this.loadAllFileContents();
|
||
this.isConnected = true;
|
||
return true;
|
||
}
|
||
catch (error) {
|
||
console.error('连接失败详细信息:', error);
|
||
this.isConnected = false;
|
||
return false;
|
||
}
|
||
}
|
||
// 是否已连接
|
||
getIsConnected() {
|
||
return this.isConnected;
|
||
}
|
||
// 获取指定目录的子文件(支持树形结构)
|
||
getChildren(parentKey) {
|
||
if (!parentKey) {
|
||
// 获取根目录内容
|
||
const folders = new Map(); // folderKey -> name
|
||
const files = [];
|
||
for (const key of this.fileList.keys()) {
|
||
const idx = key.indexOf('/');
|
||
if (idx === -1) {
|
||
// 根目录文件
|
||
const entry = this.fileList.get(key);
|
||
if (entry)
|
||
files.push(entry);
|
||
}
|
||
else {
|
||
// 根目录文件夹
|
||
const folder = key.substring(0, idx);
|
||
if (!folders.has(folder))
|
||
folders.set(folder, folder);
|
||
}
|
||
}
|
||
const dirs = [...folders.keys()].map(k => ({
|
||
key: k,
|
||
name: k,
|
||
isFile: false
|
||
}));
|
||
return [...files, ...dirs].sort((a, b) => (a.isFile === b.isFile) ?
|
||
a.name.localeCompare(b.name, 'en', { sensitivity: 'base' }) :
|
||
(a.isFile ? 1 : -1));
|
||
}
|
||
// 获取子目录内容
|
||
const prefix = parentKey.endsWith('/') ? parentKey : parentKey + '/';
|
||
const seenFolders = new Set();
|
||
const result = [];
|
||
for (const key of this.fileList.keys()) {
|
||
if (!key.startsWith(prefix))
|
||
continue;
|
||
const rest = key.substring(prefix.length);
|
||
const slash = rest.indexOf('/');
|
||
if (slash === -1) {
|
||
// 直接子文件
|
||
const entry = this.fileList.get(key);
|
||
if (entry)
|
||
result.push(entry);
|
||
}
|
||
else {
|
||
// 子文件夹
|
||
const childFolder = rest.substring(0, slash);
|
||
const childKey = prefix + childFolder;
|
||
if (!seenFolders.has(childKey)) {
|
||
seenFolders.add(childKey);
|
||
result.push({
|
||
key: childKey,
|
||
name: childFolder,
|
||
isFile: false
|
||
});
|
||
}
|
||
}
|
||
}
|
||
result.sort((a, b) => (a.isFile === b.isFile) ?
|
||
a.name.localeCompare(b.name, 'en', { sensitivity: 'base' }) :
|
||
(a.isFile ? 1 : -1));
|
||
return result;
|
||
}
|
||
// 获取文件内容
|
||
async getFileContent(filePath) {
|
||
const entry = this.fileList.get(filePath);
|
||
if (!entry) {
|
||
return undefined;
|
||
}
|
||
// 如果已经加载过内容,直接返回
|
||
if (entry.content) {
|
||
return entry.content;
|
||
}
|
||
try {
|
||
// 获取编码设置
|
||
const encodingType = this.config.get('nutEncoding', 'UTF8');
|
||
const contents = await this.apiClient.getFileContents([filePath], encodingType);
|
||
const content = contents[filePath];
|
||
if (content !== undefined) {
|
||
entry.content = content;
|
||
entry.lastLoaded = new Date();
|
||
return content;
|
||
}
|
||
}
|
||
catch (error) {
|
||
vscode.window.showErrorMessage(`获取文件内容失败: ${error}`);
|
||
}
|
||
return undefined;
|
||
}
|
||
// 保存文件内容
|
||
async saveFileContent(filePath, content) {
|
||
// 先检查C++服务是否可连接
|
||
const isCppServiceConnected = await (0, localClient_1.checkCppServiceConnection)();
|
||
if (isCppServiceConnected) {
|
||
// C++服务可连接,先发送进行编译验证
|
||
try {
|
||
const sendSuccess = await (0, localClient_1.sendFileToCppService)(filePath, content);
|
||
if (sendSuccess) {
|
||
// C++编译服务返回200,说明脚本编译通过,允许上传
|
||
const success = await this.apiClient.uploadFileContent(filePath, content);
|
||
if (success) {
|
||
const entry = this.fileList.get(filePath);
|
||
if (entry) {
|
||
entry.content = content;
|
||
entry.lastLoaded = new Date();
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
else {
|
||
// C++编译服务返回非200,说明脚本存在问题,不允许上传
|
||
vscode.window.showErrorMessage(`脚本编译失败,无法保存文件 ${filePath}。请检查代码错误后再试。`);
|
||
return false;
|
||
}
|
||
}
|
||
catch (error) {
|
||
// 向C++服务发送文件过程中出现错误
|
||
vscode.window.showErrorMessage(`发送文件到编译服务时出错: ${error},但仍尝试直接保存文件`);
|
||
const success = await this.apiClient.uploadFileContent(filePath, content);
|
||
if (success) {
|
||
const entry = this.fileList.get(filePath);
|
||
if (entry) {
|
||
entry.content = content;
|
||
entry.lastLoaded = new Date();
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
// C++服务不可连接,直接执行上传
|
||
try {
|
||
const success = await this.apiClient.uploadFileContent(filePath, content);
|
||
if (success) {
|
||
const entry = this.fileList.get(filePath);
|
||
if (entry) {
|
||
entry.content = content;
|
||
entry.lastLoaded = new Date();
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
catch (error) {
|
||
vscode.window.showErrorMessage(`保存文件失败: ${error}`);
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
// 刷新文件列表
|
||
async refresh() {
|
||
if (!this.isConnected) {
|
||
return false;
|
||
}
|
||
try {
|
||
this.updateConfig();
|
||
const defaultDir = this.config.get('defaultDirectory', 'sqr');
|
||
const filesData = await this.apiClient.getFileList(defaultDir);
|
||
// 将字符串按换行符分割成数组
|
||
const files = filesData.split(/\r?\n/).filter((file) => file.trim() !== '');
|
||
this.fileList.clear();
|
||
files.forEach((filePath) => {
|
||
const entry = {
|
||
key: filePath,
|
||
name: filePath.split('/').pop() || filePath,
|
||
isFile: true
|
||
};
|
||
this.fileList.set(filePath, entry);
|
||
});
|
||
return true;
|
||
}
|
||
catch (error) {
|
||
vscode.window.showErrorMessage(`刷新文件列表失败: ${error}`);
|
||
return false;
|
||
}
|
||
}
|
||
// 批量加载所有文件内容
|
||
async loadAllFileContents() {
|
||
try {
|
||
// 获取所有文件路径
|
||
const filePaths = Array.from(this.fileList.keys());
|
||
if (filePaths.length === 0) {
|
||
console.log('没有文件需要加载');
|
||
return;
|
||
}
|
||
console.log(`准备加载 ${filePaths.length} 个文件的内容`);
|
||
// 获取编码设置
|
||
const encodingType = this.config.get('nutEncoding', 'UTF8');
|
||
// 分批获取文件内容,避免一次性请求过多文件
|
||
const batchSize = 50; // 每批处理50个文件
|
||
for (let i = 0; i < filePaths.length; i += batchSize) {
|
||
const batch = filePaths.slice(i, i + batchSize);
|
||
console.log(`正在加载批次 ${Math.floor(i / batchSize) + 1}/${Math.ceil(filePaths.length / batchSize)}: ${batch.length} 个文件`);
|
||
try {
|
||
const contents = await this.apiClient.getFileContents(batch, encodingType);
|
||
// 更新文件内容
|
||
for (const [filePath, content] of Object.entries(contents)) {
|
||
const entry = this.fileList.get(filePath);
|
||
if (entry) {
|
||
entry.content = content;
|
||
entry.lastLoaded = new Date();
|
||
}
|
||
}
|
||
console.log(`批次 ${Math.floor(i / batchSize) + 1} 加载完成`);
|
||
}
|
||
catch (batchError) {
|
||
console.error(`加载批次 ${Math.floor(i / batchSize) + 1} 失败:`, batchError);
|
||
// 继续处理下一个批次,不中断整个过程
|
||
}
|
||
}
|
||
console.log('所有文件内容加载完成');
|
||
}
|
||
catch (error) {
|
||
console.error('批量加载文件内容失败:', error);
|
||
vscode.window.showErrorMessage(`批量加载文件内容失败: ${error}`);
|
||
}
|
||
}
|
||
// 获取文件条目
|
||
getFileEntry(filePath) {
|
||
return this.fileList.get(filePath);
|
||
}
|
||
// 获取所有nut文件路径
|
||
getAllNutFiles() {
|
||
return Array.from(this.fileList.keys())
|
||
.filter(filePath => filePath.endsWith('.nut'));
|
||
}
|
||
}
|
||
exports.FileModel = FileModel;
|
||
//# sourceMappingURL=model.js.map
|