import { spawn } from 'child_process'; import { existsSync, mkdirSync, readdirSync, readFileSync } from 'fs'; import { basename, extname, parse, resolve } from 'path'; import { TextEncoder } from 'util'; import * as vscode from 'vscode'; import { Hanlder } from '../common/handler'; import { Console } from '../common/Console'; import { Util } from '../common/util'; import { tmpdir } from 'os'; import { workspace } from 'vscode'; const mammoth = require("mammoth"); /** * support view office files */ export class OfficeViewerProvider implements vscode.CustomReadonlyEditorProvider { private extensionPath: string; constructor(private context: vscode.ExtensionContext) { this.extensionPath = context.extensionPath; } public openCustomDocument(uri: vscode.Uri, openContext: vscode.CustomDocumentOpenContext, token: vscode.CancellationToken): vscode.CustomDocument | Thenable { return { uri, dispose: (): void => { } }; } public resolveCustomEditor(document: vscode.CustomDocument, webviewPanel: vscode.WebviewPanel, token: vscode.CancellationToken): void | Thenable { const uri = document.uri; const webview = webviewPanel.webview; const folderPath = vscode.Uri.file(resolve(uri.fsPath, "..")); webview.options = { enableScripts: true, localResourceRoots: [vscode.Uri.file(this.extensionPath), folderPath] } const ext = extname(uri.fsPath).toLowerCase() let htmlPath: string | null = null; const handler = Hanlder.bind(webviewPanel, uri); if (ext.match(/\.(jpg|png|svg|gif|apng|bmp|ico|cur|jpeg|pjpeg|pjp|tif|tiff|webp)$/i)) { this.handleImage(uri, webview) handler.on("fileChange", () => { this.handleImage(uri, webview) }) return; } switch (ext) { case ".xlsx": case ".xls": case ".csv": htmlPath = this.handleXlsx(uri, handler) break; case ".ttf": case ".woff": case ".otf": this.handleFont(document, handler) break; case ".psd": webview.onDidReceiveMessage(() => webview.postMessage({ type: "open", content: webview.asWebviewUri(uri).toString() })) htmlPath = "psd.html" break; case ".docx": this.handleDocx(uri, webview) break; case ".svg": this.handleSvg(uri, webview); break; case ".class": this.handleClass(uri, webviewPanel); break; case ".swf": this.handleFlash(uri, handler, webview); break; case ".pdf": this.handlePdf(uri, webview); handler.on("fileChange", () => { this.handlePdf(uri, webview); }) break; case ".xmind": webview.onDidReceiveMessage(async () => { webview.postMessage({ type: "open", content: readFileSync(uri.fsPath) }) }); webview.html = Util.buildPath(readFileSync(this.extensionPath + "/resource/xmind/index.html", 'utf8'), webview, this.extensionPath + "/resource"); break; case ".htm": case ".html": webview.html = Util.buildPath(readFileSync(uri.fsPath, 'utf8'), webview, folderPath.fsPath); Util.listen(webviewPanel, uri, () => { webviewPanel.webview.html = Util.buildPath(readFileSync(uri.fsPath, 'utf8'), webviewPanel.webview, folderPath.fsPath); }) break; case ".epub": webview.onDidReceiveMessage(async () => webview.postMessage({ type: "open", content: webview.asWebviewUri(uri).toString() })) webview.html = Util.buildPath(readFileSync(this.extensionPath + "/resource/epub/index.html", 'utf8'), webview, this.extensionPath + "/resource/epub"); break; default: vscode.commands.executeCommand('vscode.openWith', uri, "default"); } if (htmlPath != null) { webview.html = Util.buildPath(readFileSync(this.extensionPath + "/resource/" + htmlPath, 'utf8'), webview, this.extensionPath + "/resource") .replace("$autoTheme", workspace.getConfiguration("vscode-office").get("autoTheme")+'') } } private handleFlash(uri: vscode.Uri, handler: Hanlder, webview: vscode.Webview) { handler.on("init", () => { handler.emit('open', webview.asWebviewUri(uri).toString()) }) webview.html = Util.buildPath( readFileSync(this.extensionPath + "/resource/flash/flash.html", 'utf8'), webview, this.extensionPath + "/resource/flash" ); } private async handleClass(uri: vscode.Uri, panel: vscode.WebviewPanel) { if (uri.scheme != "file") { vscode.commands.executeCommand('vscode.openWith', uri, "default"); return; } const tempPath=`${tmpdir()}/office_temp_java` if(!existsSync(tempPath)){ mkdirSync(tempPath) } const java = spawn("java", ['-cp', 'java-decompiler.jar','org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler', uri.fsPath, tempPath], { cwd: __dirname }) java.stdout.on('data', (data) => { console.log(data.toString("utf8")) if (data.toString("utf8").indexOf("done") == -1 ) { return; } const fileName = `${tempPath}/${parse(uri.fsPath).name}.java`; setTimeout(() => { vscode.window.showTextDocument(vscode.Uri.file(fileName).with({ scheme: "decompile_java", query: new Date().getTime().toString() })); }, 10); }); java.stderr.on('data', (data) => { Console.log(data.toString("utf8")) }); } private handleImage(uri: vscode.Uri, webview: vscode.Webview) { const folderPath = vscode.Uri.file(resolve(uri.fsPath, "..")); const files = readdirSync(folderPath.fsPath) let text = ""; let current; let i = 0; const currentFile = basename(uri.fsPath) for (const file of files) { if (currentFile == file) { current = i; } if (file.match(/\.(jpg|png|svg|gif|apng|bmp|ico|cur|jpeg|pjpeg|pjp|tif|tiff|webp)$/i)) { i++; const resUri = vscode.Uri.file(folderPath.fsPath + "/" + file); const resource = webview.asWebviewUri(resUri).with({ query: `nonce=${Date.now().toString()}` }).toString(); text += ` ` } } webview.html = Util.buildPath(readFileSync(this.extensionPath + "/resource/lightgallery/lg.html", 'utf8'), webview, this.extensionPath + "/resource/lightgallery") .replace("{{content}}", text).replace("{{current}}", current); } private handlePdf(uri: vscode.Uri, webview: vscode.Webview) { webview.html = Util.buildPath( readFileSync(this.extensionPath + "/resource/pdf/viewer.html", 'utf8').replace("{{content}}", JSON.stringify({ path: webview.asWebviewUri(uri).with({ query: `nonce=${Date.now().toString()}` }).toString(), defaults: { cursor: "select", scale: "auto", sidebar: true, scrollMode: "vertical", spreadMode: "none", }, }).replace(/"/g, '"') ), webview, this.extensionPath + "/resource/pdf" ); } private handleSvg(uri: vscode.Uri, webview: vscode.Webview) { webview.html = Util.buildPath( readFileSync(this.extensionPath + "/resource/svg/svg.html", 'utf8') .replace("{{content}}", encodeURIComponent(readFileSync(uri.fsPath, 'utf8')) ), webview, this.extensionPath + "/resource" ); } private handleDocx(uri: vscode.Uri, webview: vscode.Webview) { mammoth.convertToHtml({ path: uri.fsPath }) .then((result: any) => { console.debug(result.messages) webview.html = Util.buildPath( readFileSync(this.extensionPath + "/resource/word.html", 'utf8').replace("{{content}}", result.value) .replace("$autoTheme", workspace.getConfiguration("vscode-office").get("autoTheme")+'') , webview, this.extensionPath + "/resource" ) }) .done(); } private handleFont(document: vscode.CustomDocument, handler: Hanlder) { const webview = handler.panel.webview; handler.on("init", () => { handler.emit('open', { href: webview.asWebviewUri(document.uri).toString() }) }) webview.html = Util.buildPath( readFileSync(this.extensionPath + "/resource/font/ttf/index.html", 'utf8') , webview, this.extensionPath + "/resource/font/ttf" ) } private handleXlsx(uri: vscode.Uri, handler: Hanlder) { var enc = new TextEncoder(); handler.on("init", async () => { const content = await vscode.workspace.fs.readFile(uri) handler.emit("open", { content, file: resolve(uri.fsPath),ext:extname(uri.fsPath) }) }).on("save", async (content) => { await vscode.workspace.fs.writeFile(uri, new Uint8Array(content)) handler.emit("saveDone") }).on("saveCsv", async (content) => { await vscode.workspace.fs.writeFile(uri, enc.encode(content)) handler.emit("saveDone") }) return "excel.html" } }