1.0.2 优化打开逻辑

This commit is contained in:
睿 安
2025-09-17 12:57:41 +08:00
parent a2a77558bd
commit 0502a9ddb8
11 changed files with 267 additions and 61 deletions

View File

@@ -3,6 +3,57 @@ import { FileModel, FileEntry } from './model';
import { FileProvider } from './provider';
import { FunctionExtractor } from './functionExtractor';
// 查找已打开的文档
function findExistingDocument(filePath: string): vscode.TextDocument | undefined {
const documents = vscode.workspace.textDocuments;
for (const doc of documents) {
if (doc.uri.scheme === 'squirrel' && doc.uri.path === `/${filePath}`) {
return doc;
}
}
return undefined;
}
// 打开文件的通用函数
async function openFile(model: FileModel, provider: FileProvider, entry: FileEntry): Promise<void> {
if (!model.getIsConnected()) {
vscode.window.showErrorMessage('请先连接到 pvfUtility API');
return;
}
// 检查是否已经有相同的文件打开
const existingDocument = findExistingDocument(entry.key);
if (existingDocument) {
// 如果文件已打开,则聚焦到该标签页
await vscode.window.showTextDocument(existingDocument);
return;
}
// 如果文件未打开,则在新标签页中打开
try {
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: `正在加载文件 ${entry.name}...`,
cancellable: false
}, async (progress) => {
const content = await model.getFileContent(entry.key);
if (content !== undefined) {
// 创建虚拟文档使用时间戳确保URI唯一以支持多标签页
const timestamp = Date.now();
const uri = vscode.Uri.parse(`squirrel:/${entry.key}?instance=${timestamp}`);
const doc = await vscode.workspace.openTextDocument(uri);
await vscode.window.showTextDocument(doc, { preview: false });
provider.refresh();
} else {
vscode.window.showErrorMessage(`加载文件 ${entry.name} 失败`);
}
});
} catch (error) {
vscode.window.showErrorMessage(`打开文件失败: ${error}`);
}
}
export function registerCommands(context: vscode.ExtensionContext, model: FileModel, provider: FileProvider, functionExtractor: FunctionExtractor, output?: vscode.OutputChannel) {
// 连接到 API
console.log('注册 squirrel.connectToApi 命令...');
@@ -63,34 +114,9 @@ export function registerCommands(context: vscode.ExtensionContext, model: FileMo
}
});
// 打开文件
// 打开文件(单击或双击文件时调用)
const openFileCommand = vscode.commands.registerCommand('squirrel.openFile', async (entry: FileEntry) => {
if (!model.getIsConnected()) {
vscode.window.showErrorMessage('请先连接到 pvfUtility API');
return;
}
try {
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: `正在加载文件 ${entry.name}...`,
cancellable: false
}, async (progress) => {
const content = await model.getFileContent(entry.key);
if (content !== undefined) {
// 创建虚拟文档
const uri = vscode.Uri.parse(`squirrel:/${entry.key}`);
const doc = await vscode.workspace.openTextDocument(uri);
await vscode.window.showTextDocument(doc);
provider.refresh();
} else {
vscode.window.showErrorMessage(`加载文件 ${entry.name} 失败`);
}
});
} catch (error) {
vscode.window.showErrorMessage(`打开文件失败: ${error}`);
}
await openFile(model, provider, entry);
});
// 保存文件(通过 VS Code 的保存事件处理,这个命令主要用于显示)

View File

@@ -116,6 +116,9 @@ export function activate(context: vscode.ExtensionContext) {
isCaseSensitive: true
});
// 将 fileSystemProvider 添加到 context 以便在 commands 中使用
(global as any).fileSystemProvider = fileSystemProvider;
// 注册所有命令
console.log('正在注册命令...');
registerCommands(context, model, provider, functionExtractor, output);
@@ -147,7 +150,14 @@ export function activate(context: vscode.ExtensionContext) {
}
});
context.subscriptions.push(configChangeListener, saveListener);
// 注册文件关闭事件以清理缓存
const closeListener = vscode.workspace.onDidCloseTextDocument((doc) => {
if (doc.uri.scheme === 'squirrel') {
fileSystemProvider.clearFileCache(doc.uri);
}
});
context.subscriptions.push(configChangeListener, saveListener, closeListener);
output.appendLine('[Squirrel] 扩展激活完成');
output.show();

View File

@@ -5,6 +5,8 @@ export class SquirrelFileSystemProvider implements vscode.FileSystemProvider {
private model: FileModel;
private _onDidChangeFile = new vscode.EventEmitter<vscode.FileChangeEvent[]>();
onDidChangeFile = this._onDidChangeFile.event;
// 存储文件实例内容,支持多标签页
private fileContentCache = new Map<string, string>();
constructor(model: FileModel) {
this.model = model;
@@ -13,12 +15,24 @@ export class SquirrelFileSystemProvider implements vscode.FileSystemProvider {
// 读取文件
async readFile(uri: vscode.Uri): Promise<Uint8Array> {
const filePath = this.getPathFromUri(uri);
// 检查是否有缓存的内容(用于多标签页支持)
const cacheKey = uri.toString();
if (this.fileContentCache.has(cacheKey)) {
const content = this.fileContentCache.get(cacheKey)!;
return new TextEncoder().encode(content);
}
// 从模型获取内容
const content = await this.model.getFileContent(filePath);
if (content === undefined) {
throw vscode.FileSystemError.FileNotFound(uri);
}
// 缓存内容以支持多标签页
this.fileContentCache.set(cacheKey, content);
return new TextEncoder().encode(content);
}
@@ -27,6 +41,10 @@ export class SquirrelFileSystemProvider implements vscode.FileSystemProvider {
const filePath = this.getPathFromUri(uri);
const textContent = new TextDecoder().decode(content);
// 更新缓存内容
const cacheKey = uri.toString();
this.fileContentCache.set(cacheKey, textContent);
const success = await this.model.saveFileContent(filePath, textContent);
if (!success) {
@@ -36,11 +54,19 @@ export class SquirrelFileSystemProvider implements vscode.FileSystemProvider {
// 其他必须实现的方法(简化实现)
stat(uri: vscode.Uri): vscode.FileStat {
// 获取文件内容以确定大小
const cacheKey = uri.toString();
let content = '';
if (this.fileContentCache.has(cacheKey)) {
content = this.fileContentCache.get(cacheKey)!;
}
return {
type: vscode.FileType.File,
ctime: Date.now(),
mtime: Date.now(),
size: 0
size: Buffer.byteLength(content, 'utf8')
};
}
@@ -64,11 +90,23 @@ export class SquirrelFileSystemProvider implements vscode.FileSystemProvider {
return new vscode.Disposable(() => {});
}
// 清理文件缓存
clearFileCache(uri: vscode.Uri): void {
const cacheKey = uri.toString();
this.fileContentCache.delete(cacheKey);
}
// 从 URI 解析文件路径
private getPathFromUri(uri: vscode.Uri): string {
if (uri.scheme !== 'squirrel') {
throw vscode.FileSystemError.FileNotFound(uri);
}
// 移除查询参数,只返回路径部分
return uri.path.substring(1); // 去掉开头的 '/'
}
// 获取文件实例ID
private getInstanceId(uri: vscode.Uri): string {
return uri.query ? new URLSearchParams(uri.query).get('instance') || 'default' : 'default';
}
}