diff --git a/.gitignore b/.gitignore index 5fe00fe..89c2164 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ out node_modules .vscode-test/ *.vsix +.vscode/ \ No newline at end of file diff --git a/html/mind-map-preview-webview.template.html b/html/mind-map-preview-webview.template.html new file mode 100644 index 0000000..a091231 --- /dev/null +++ b/html/mind-map-preview-webview.template.html @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/package.json b/package.json index c46534c..3366684 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "Other" ], "activationEvents": [ - "onCommand:mdmmp.showMindMap" + "onCommand:mdmmp.showMindMap", + "onCommand:mdmmp.exportSvg" ], "main": "./out/extension.js", "contributes": { @@ -39,6 +40,15 @@ "light": "./icon/mind-map-theme-light.svg", "dark": "./icon/mind-map-theme-dark.svg" } + }, + { + "when": "resourceLangId == markdown", + "command": "mdmmp.exportSvg", + "title": "Export Mind Map SVG", + "icon": { + "light": "./icon/mind-map-theme-light.svg", + "dark": "./icon/mind-map-theme-dark.svg" + } } ], "menus": { @@ -70,6 +80,5 @@ "mocha": "^8.1.3", "typescript": "^4.0.2", "vscode-test": "^1.4.0" - }, - "dependencies": {} + } } diff --git a/src/extension.ts b/src/extension.ts index d2fdf8b..08838ed 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,18 +1,25 @@ -// The module 'vscode' contains the VS Code extensibility API -// Import the module and reference it with the alias vscode in your code below import * as vscode from 'vscode'; import { MindMapPreview } from "./mindMapPreviewWebview"; -// this method is called when your extension is activated -// your extension is activated the very first time the command is executed export function activate(context: vscode.ExtensionContext) { + let mindMapPreview: MindMapPreview; context.subscriptions.push( vscode.commands.registerCommand('mdmmp.showMindMap', () => { - const mindMapPreview = new MindMapPreview(context); + if ((mindMapPreview === undefined) || mindMapPreview.isDisposed) { + mindMapPreview = new MindMapPreview(context); + } mindMapPreview.updatePreview(); }) ); + context.subscriptions.push( + vscode.commands.registerCommand('mdmmp.exportSvg', () => { + if ((mindMapPreview === undefined) || mindMapPreview.isDisposed) { + vscode.window.showWarningMessage("Sorry, you need open the preview tab first."); + return; + } + mindMapPreview.exportSvg(); + }) + ); } -// this method is called when your extension is deactivated export function deactivate() {} diff --git a/src/mindMapPreviewWebview.ts b/src/mindMapPreviewWebview.ts index 16123fe..77d50c2 100644 --- a/src/mindMapPreviewWebview.ts +++ b/src/mindMapPreviewWebview.ts @@ -1,11 +1,35 @@ import * as vscode from 'vscode'; import * as path from "path"; +import * as fs from "fs"; +import * as utils from "./utils"; class MindMapPreview { + context: vscode.ExtensionContext; view: vscode.WebviewPanel; editingEditor!: vscode.TextEditor; + isDisposed: boolean = false; + + // Configure initialization here. + configureWebviewScripts(webviewScripts: string[]) { + webviewScripts.push("d3.js"); + webviewScripts.push("transform.min.js"); + webviewScripts.push("view.min.js"); + return webviewScripts; + } + + configureDisposables(disposables: vscode.Disposable[]) { + disposables.push(vscode.workspace.onDidChangeTextDocument(() => { + this.updatePreview(); + })); + disposables.push(this.view.webview.onDidReceiveMessage((message) => { + this.onMessageReceived(message); + }, null, this.context.subscriptions)); + return disposables; + } constructor(context: vscode.ExtensionContext) { + this.context = context; + this.view = vscode.window.createWebviewPanel( "mindMapPreview", "Mind Map Preview", @@ -18,67 +42,80 @@ class MindMapPreview { } ); - this.view.webview.html = ` - - - - - - - - - - - - - - - - - `; - const editingEditor = vscode.window.activeTextEditor; - if (editingEditor === undefined) { return; } + if (editingEditor === undefined) { + vscode.window.showWarningMessage("Sorry, the active text editor is not valid."); + return; + } this.editingEditor = editingEditor; - const editingEvent = vscode.workspace.onDidChangeTextDocument(() => { - this.updatePreview(); + this.initialize(); + this.isDisposed = false; + } + + initialize() { + this.initializeWebviewHtml(); + this.registerDisposables(); + } + + initializeWebviewHtml() { + let loadingScriptHtml: string[] = []; + this.configureWebviewScripts([]).forEach(path => { + loadingScriptHtml.push(``); }); + const html: string = fs.readFileSync(path.join(this.getHtmlAssetPath("mind-map-preview-webview.template.html"))).toString("utf-8"); + this.view.webview.html = html.replace(//g, loadingScriptHtml.join("\r\n")); + } + + registerDisposables() { + const disposables: vscode.Disposable[] = this.configureDisposables([]); this.view.onDidDispose( () => { - editingEvent.dispose(); + disposables.forEach(disposable => { + disposable.dispose(); + }); + this.isDisposed = true; }, null, - context.subscriptions + this.context.subscriptions ); } + getHtmlAssetPath(filename: string) { + return path.join(this.context.extensionPath, 'html', filename); + } + + onMessageReceived(message: any) { + switch (message.command) { + case "saveSvgData": { + this.onSvgDataReceived(message.html); + break; + } + } + } + + onSvgDataReceived(html: string) { + const editor = vscode.window.activeTextEditor; + if (editor === undefined) { + vscode.window.showWarningMessage("Sorry, the active text editor is not valid."); + return; + } + const fsPath = editor.document.uri.fsPath; + const tempFile = path.dirname(fsPath); + + const filename = utils.getFileNameWithoutExtension(path.basename(fsPath)); + let tempImage = path.resolve(tempFile, filename + '.svg'); + fs.writeFileSync(tempImage, html); + } + updatePreview() { const data = this.editingEditor.document.getText(); - this.view.webview.postMessage(data); + this.view.webview.postMessage({ "command": "renderMarkdown", "data": data }); + } + + exportSvg() { + this.view.webview.postMessage({ "command": "saveSvg" }); } } diff --git a/src/modules.d.ts b/src/modules.d.ts deleted file mode 100644 index 316d34b..0000000 --- a/src/modules.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module 'markmap-lib/dist/transform'; \ No newline at end of file diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..38ba811 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,9 @@ +export function getFileNameWithoutExtension(filename: string) { + var pattern = /\.[A-Za-z]+$/; + let ansMatch = pattern.exec(filename); + if (ansMatch !== null) { + return (filename.slice(0, ansMatch.index)); + } else { + return filename; + } +}