1.0.0 初始版
This commit is contained in:
293
src/model.ts
Normal file
293
src/model.ts
Normal file
@@ -0,0 +1,293 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { ApiClient } from './apiClient';
|
||||
|
||||
export interface FileEntry {
|
||||
key: string; // 文件路径
|
||||
name: string; // 显示名称
|
||||
isFile: boolean;
|
||||
content?: string; // 文件内容
|
||||
lastLoaded?: Date; // 最后加载时间
|
||||
}
|
||||
|
||||
export class FileModel {
|
||||
private fileList = new Map<string, FileEntry>();
|
||||
private apiClient: ApiClient;
|
||||
private config: vscode.WorkspaceConfiguration;
|
||||
private isConnected = false;
|
||||
|
||||
constructor() {
|
||||
this.apiClient = new ApiClient();
|
||||
this.config = vscode.workspace.getConfiguration('squirrel');
|
||||
}
|
||||
|
||||
// 更新配置
|
||||
updateConfig() {
|
||||
this.config = vscode.workspace.getConfiguration('squirrel');
|
||||
const baseUrl = this.config.get<string>('api.baseUrl', 'http://localhost');
|
||||
const port = this.config.get<number>('api.port', 8080);
|
||||
this.apiClient.updateConfig(baseUrl, port);
|
||||
}
|
||||
|
||||
// 连接到API
|
||||
async connect(): Promise<boolean> {
|
||||
try {
|
||||
this.updateConfig();
|
||||
const baseUrl = this.config.get<string>('api.baseUrl', 'http://localhost');
|
||||
const port = this.config.get<number>('api.port', 8080);
|
||||
const defaultDir = this.config.get<string>('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: string) => file.trim() !== '');
|
||||
console.log(`成功获取到 ${files.length} 个文件`);
|
||||
|
||||
this.fileList.clear();
|
||||
|
||||
files.forEach((filePath: string) => {
|
||||
const entry: FileEntry = {
|
||||
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(): boolean {
|
||||
return this.isConnected;
|
||||
}
|
||||
|
||||
// 获取指定目录的子文件(支持树形结构)
|
||||
getChildren(parentKey?: string): FileEntry[] {
|
||||
if (!parentKey) {
|
||||
// 获取根目录内容
|
||||
const folders = new Map<string, string>(); // folderKey -> name
|
||||
const files: FileEntry[] = [];
|
||||
|
||||
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: FileEntry[] = [...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<string>();
|
||||
const result: FileEntry[] = [];
|
||||
|
||||
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: string): Promise<string | undefined> {
|
||||
const entry = this.fileList.get(filePath);
|
||||
if (!entry) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// 如果已经加载过内容,直接返回
|
||||
if (entry.content) {
|
||||
return entry.content;
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取编码设置
|
||||
const encodingType = this.config.get<string>('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: string, content: string): Promise<boolean> {
|
||||
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(): Promise<boolean> {
|
||||
if (!this.isConnected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
this.updateConfig();
|
||||
const defaultDir = this.config.get<string>('defaultDirectory', 'sqr');
|
||||
const filesData = await this.apiClient.getFileList(defaultDir);
|
||||
|
||||
// 将字符串按换行符分割成数组
|
||||
const files = filesData.split(/\r?\n/).filter((file: string) => file.trim() !== '');
|
||||
|
||||
this.fileList.clear();
|
||||
files.forEach((filePath: string) => {
|
||||
const entry: FileEntry = {
|
||||
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(): Promise<void> {
|
||||
try {
|
||||
// 获取所有文件路径
|
||||
const filePaths = Array.from(this.fileList.keys());
|
||||
|
||||
if (filePaths.length === 0) {
|
||||
console.log('没有文件需要加载');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`准备加载 ${filePaths.length} 个文件的内容`);
|
||||
|
||||
// 获取编码设置
|
||||
const encodingType = this.config.get<string>('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: string): FileEntry | undefined {
|
||||
return this.fileList.get(filePath);
|
||||
}
|
||||
|
||||
// 获取所有nut文件路径
|
||||
getAllNutFiles(): string[] {
|
||||
return Array.from(this.fileList.keys())
|
||||
.filter(filePath => filePath.endsWith('.nut'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user