pag-player
Version:
pag预览插件
217 lines (197 loc) • 8.35 kB
text/typescript
import * as vscode from "vscode";
const path = require("path");
const fs = require("fs");
class PagCustomDocument implements vscode.CustomDocument {
uri: vscode.Uri;
constructor(uri: vscode.Uri) {
this.uri = uri;
}
dispose(): void {
// 如果需要清理资源,可以在这里实现
}
}
export class PagCustomEditorProvider
implements vscode.CustomReadonlyEditorProvider<PagCustomDocument>
{
public static readonly viewType = "pag-preview.editor";
private statusBarItem: vscode.StatusBarItem;
// private pagInfo: any = {};
private pagInfoMap: WeakMap<vscode.WebviewPanel, { width: number; height: number; size: number, duration: number }>;
constructor(private readonly context: vscode.ExtensionContext) {
// 创建状态栏项
this.statusBarItem = vscode.window.createStatusBarItem(
vscode.StatusBarAlignment.Right, // 对齐到右下角
100 // 优先级
);
this.pagInfoMap = new WeakMap(); // 使用 WeakMap 存储每个 Webview 的 pagInfo
}
/**
* openCustomDocument 方法,用于打开自定义文档
*/
public openCustomDocument(
uri: vscode.Uri,
_openContext: vscode.CustomDocumentOpenContext,
_token: vscode.CancellationToken
): vscode.CustomDocument | Thenable<vscode.CustomDocument> {
// 创建并返回自定义文档实例
return new PagCustomDocument(uri);
}
/**
* resolveCustomEditor 方法,在文件被打开时触发
*/
public async resolveCustomEditor(
document: PagCustomDocument,
webviewPanel: vscode.WebviewPanel,
_token: vscode.CancellationToken
): Promise<void> {
console.log(`Opening file: ${document.uri.fsPath}`);
// vscode指令通信
// vscode.commands.executeCommand("pag-preview.fileDetail", document.uri);
// 设置 Webview 选项
webviewPanel.webview.options = {
enableScripts: true,
// localResourceRoots作用:防止 WebView 意外访问到插件不该访问的本地文件系统区域。只有处在 localResourceRoots 所列出的目录中的资源,才可以被 WebView 加载,这有助于保障用户系统的安全,避免恶意代码利用 WebView 越界访问敏感文件
localResourceRoots: [
vscode.Uri.file(path.join(this.context.extensionPath, "dist")),
vscode.Uri.file(path.dirname(document.uri.fsPath)),
],
};
// 获取当前主题模式
const currentTheme = vscode.window.activeColorTheme.kind;
const themeMap: { [key in vscode.ColorThemeKind]: string } = {
[vscode.ColorThemeKind.Dark]: "dark",
[vscode.ColorThemeKind.Light]: "light",
[vscode.ColorThemeKind.HighContrast]: "highContrast",
[vscode.ColorThemeKind.HighContrastLight]: "highContrastLight",
}
webviewPanel.webview.postMessage({
type: "themeChange",
theme: themeMap[currentTheme] || "dark",
});
vscode.window.onDidChangeActiveColorTheme((e) => {
// console.log("VSCode 主题已切换为:", e.kind);
webviewPanel.webview.postMessage({
type: "themeChange",
theme: themeMap[e.kind] || "dark",
});
});
// 关键:将文件 URI 转为 Webview 可访问的路径
const fileUri = webviewPanel.webview.asWebviewUri(document.uri);
// console.log("uri--", fileUri.toString()); https://file%2B.vscode-resource.vscode-cdn.net/Users/xxx/vscode/pag-preview/dist/webview/pag.min.js
// const htmlPath = path.join(
// this.context.extensionPath,
// "dist/index.html"
// );
// // console.log("htmlPath", htmlPath);
// // 解析html内容
// const htmlContent = fs.readFileSync(htmlPath, "utf-8");
// console.log('path: 777777', path.join(this.context.extensionPath, "dist/pag.min.js"));
// const fastDiffUri = webviewPanel.webview.asWebviewUri(
// vscode.Uri.file(
// path.join(this.context.extensionPath, "dist/pag.min.js")
// )
// );
// const updatedHtmlContent = htmlContent.replace("./pag.min.js", fastDiffUri);
// // 设置 Webview 内容
// webviewPanel.webview.html = updatedHtmlContent;
webviewPanel.webview.html = this.getWebviewContent(document, webviewPanel.webview);
// 将文件内容发送到 Webview
webviewPanel.webview.postMessage({
type: "loadFile",
fileUri: fileUri.toString(),
});
// 加载 PAG 文件并获取宽高和文件大小
const fileSize = await this.getFileSize(document.uri.fsPath);
// const { width, height } = await this.getPagDimensions(webviewPanel.webview);
// 更新状态栏
// this.updateStatusBar(width, height, fileSize);
// 监听来自 Webview 的消息
webviewPanel.webview.onDidReceiveMessage((message) => {
if (message.command === "alert") {
vscode.window.showInformationMessage(message.text);
} else if (message.type === "pagDimensions") {
console.log("PAG Dimensions:", message.width, message.height);
this.pagInfoMap.set(webviewPanel, { width: message.width, height: message.height, size: fileSize, duration: message.duration });
this.updateStatusBar(message.width, message.height, fileSize, message.duration);
}
});
// 监听 Webview 可见状态变化
webviewPanel.onDidChangeViewState((e) => {
if (e.webviewPanel.visible) {
console.log('回来了呀', e);
webviewPanel.webview.postMessage({ type: "play" });
const pagInfo = this.pagInfoMap.get(webviewPanel);
if (pagInfo) {
// this.statusBarItem.show(); // 显示状态栏
this.updateStatusBar(pagInfo.width, pagInfo.height, pagInfo.size, pagInfo.duration);
}
} else {
webviewPanel.webview.postMessage({ type: "pause" });
this.statusBarItem.hide();
}
});
// 处理自定义编辑器生命周期
webviewPanel.onDidDispose(() => {
console.log('pag文件关闭');
// vscode.commands.executeCommand("pag-preview.fileDetail");
console.log('PAG file closed');
this.statusBarItem.hide(); // 隐藏状态栏
document.dispose();
// 不需要手动清理 WeakMap,垃圾回收会自动处理
});
}
private getWebviewContent(document: PagCustomDocument, webview: vscode.Webview): string {
const htmlPath = path.join(this.context.extensionPath, "dist/index.html");
let htmlContent;
try {
htmlContent = fs.readFileSync(htmlPath, "utf-8");
} catch (error: any) {
vscode.window.showErrorMessage(`Failed to load HTML file: ${error.message}`);
return "";
}
const pagJsUri = webview.asWebviewUri(
vscode.Uri.file(path.join(this.context.extensionPath, "dist/pag.min.js"))
);
return htmlContent.replace("./pag.min.js", pagJsUri.toString());
}
private async getFileSize(filePath: string): Promise<number> {
try {
const stats = fs.statSync(filePath);
return stats.size; // 返回文件大小(字节)
} catch (error) {
console.error("Failed to get file size:", error);
return 0;
}
}
private async getPagDimensions(webview: vscode.Webview): Promise<{ width: number; height: number }> {
return new Promise((resolve) => {
const listener = webview.onDidReceiveMessage((message) => {
if (message.type === "pagDimensions") {
resolve({ width: message.width, height: message.height });
listener.dispose(); // 移除监听器
}
});
// 请求 Webview 发送 PAG 文件的宽高
webview.postMessage({ type: "getPagDimensions" });
});
}
private updateStatusBar(width: number, height: number, fileSize: number, duration: number): void {
const sizeInKB = (fileSize / 1024).toFixed(2); // 将文件大小转换为 KB
this.statusBarItem.text = `PAG: ${width}x${height} | ${sizeInKB} KB | ${duration} s`;
this.statusBarItem.show(); // 显示状态栏
console.log('statusBarItem Info:', width, height, sizeInKB);
}
}
export default (context: vscode.ExtensionContext) => {
console.log("PAG Custom Editor Activated!");
let disposable = vscode.window.registerCustomEditorProvider(
PagCustomEditorProvider.viewType,
new PagCustomEditorProvider(context),
{
webviewOptions: {
retainContextWhenHidden: true, // 切换标签时保留上下文
},
}
);
return disposable;
};