import { convertMd } from "./markdown/markdown-pdf"; import { exportByType } from "./markdown/html-export"; import { spawn } from 'child_process'; import { copyFileSync, existsSync, lstatSync, mkdirSync } from 'fs'; import { homedir } from 'os'; import { join, parse, resolve } from 'path'; import * as vscode from 'vscode'; import { Holder } from './markdown/holder'; import path = require('path'); export class MarkdownService { constructor(private context: vscode.ExtensionContext) { } public async exportPdfByHtml(uri: vscode.Uri, html: string) { vscode.window.showInformationMessage("Starting export markdown to pdf.") await exportByType(uri.fsPath.replace(".md",".pdf"), html, 'pdf', this.getConfig()) vscode.window.showInformationMessage("Export markdown to pdf success!") } public async exportPdf(uri: vscode.Uri) { vscode.window.showInformationMessage("Starting export markdown to pdf.") await convertMd({ markdownFilePath: uri.fsPath, config: this.getConfig() }) vscode.window.showInformationMessage("Export markdown to pdf success!") } public getConfig() { return { "type": [ "pdf" ], "outputDirectory": "", "outputDirectoryRelativePathFile": false, "styles": [], "stylesRelativePathFile": false, "includeDefaultStyles": true, "highlight": true, "highlightStyle": "", "breaks": false, "markdown-it-include": true, "executablePath": this.getChromiumPath(), "scale": 1, "displayHeaderFooter": true, "headerTemplate": "
", "footerTemplate": "
/
", "printBackground": true, "orientation": "portrait", "pageRanges": "", "format": "A4", "width": "", "height": "", "margin": "1cm", "quality": 100, "clip": { "height": null }, "omitBackground": false }; } private paths: { [index: string]: string } = { stable: "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe", beta: "C:\\Program Files (x86)\\Microsoft\\Edge Beta\\Application\\msedge.exe", dev: "C:\\Program Files (x86)\\Microsoft\\Edge Dev\\Application\\msedge.exe", canary: join(homedir(), "AppData\\Local\\Microsoft\\Edge SxS\\Application\\msedge.exe"), } private getChromiumPath() { for (const pathName in this.paths) { const path = this.paths[pathName]; if (existsSync(path)) { console.debug(`using edge path is ${path}`) return path; } } try { const chromePath = require('chrome-finder')(); console.debug(`using chrome path is ${chromePath}`) return chromePath; } catch (e) { vscode.window.showErrorMessage("Not chromium found, export fail.") throw new Error() } } public async loadClipboardImage() { const document = vscode.window.activeTextEditor?.document if (document && parse(document.uri.fsPath).ext.toLowerCase() != ".md") { vscode.commands.executeCommand("editor.action.clipboardPasteAction") return } if (await vscode.env.clipboard.readText() == "") { const uri: vscode.Uri | null = document ? document.uri : Holder.activeUrl if (uri == null) { return } const rePath = `image/${parse(uri.fsPath).name}/${new Date().getTime()}.png`; const imagePath = `${resolve(uri.fsPath, "..")}/${rePath}`.replace(/\\/g, "/"); const dir = path.dirname(imagePath) if (!existsSync(dir)) { mkdirSync(dir, { recursive: true }) } this.saveClipboardImageToFileAndGetPath(imagePath, (savedImagePath) => { if (!savedImagePath) return; if (savedImagePath === 'no image') { vscode.window.showErrorMessage('There is not an image in the clipboard.'); return; } if (savedImagePath.startsWith("copyed:")) { const copyedFile = savedImagePath.replace("copyed:", ""); if (!existsSync(copyedFile)) { vscode.window.showErrorMessage(`Coped file ${copyedFile} not found!`); return; } if (lstatSync(copyedFile).isDirectory()) { vscode.window.showErrorMessage('Not support paster directory.'); } else { copyFileSync(copyedFile, imagePath) } } const editor = vscode.window.activeTextEditor; if (editor) { editor?.edit(edit => { let current = editor.selection; if (current.isEmpty) { edit.insert(current.start, `![](${rePath})`); } else { edit.replace(current, `![](${rePath})`); } }); } else { vscode.env.clipboard.writeText(`![](${rePath})`) vscode.commands.executeCommand("editor.action.clipboardPasteAction") } }) } else { vscode.commands.executeCommand("editor.action.clipboardPasteAction") } } private saveClipboardImageToFileAndGetPath(imagePath: string, cb: (value: string) => void) { if (!imagePath) return; let platform = process.platform; if (platform === 'win32') { // Windows const scriptPath = path.join(this.context.extensionPath, '/lib/pc.ps1'); const powershell = spawn('powershell', [ '-noprofile', '-noninteractive', '-nologo', '-sta', '-executionpolicy', 'unrestricted', '-windowstyle', 'hidden', '-file', scriptPath, imagePath ]); powershell.on('exit', function (code, signal) { }); powershell.stdout.on('data', function (data) { cb(data.toString().trim()); }); } else if (platform === 'darwin') { // Mac let scriptPath = path.join(this.context.extensionPath, './lib/mac.applescript'); let ascript = spawn('osascript', [scriptPath, imagePath]); ascript.on('exit', function (code, signal) { }); ascript.stdout.on('data', function (data) { cb(data.toString().trim()); }); } else { // Linux let scriptPath = path.join(this.context.extensionPath, './lib/linux.sh'); let ascript = spawn('sh', [scriptPath, imagePath]); ascript.on('exit', function (code, signal) { }); ascript.stdout.on('data', function (data) { let result = data.toString().trim(); if (result == "no xclip") { vscode.window.showInformationMessage('You need to install xclip command first.'); return; } cb(result); }); } } }