diff --git a/confirm-modal.ts b/confirm-modal.ts new file mode 100644 index 0000000..f3bb87d --- /dev/null +++ b/confirm-modal.ts @@ -0,0 +1,42 @@ +import { App, Modal, Setting } from "obsidian"; + +export class ConfirmModal extends Modal { + existingFilename: string; + onSubmit: (doOverwrite: boolean) => void; + + constructor(app: App, existingFilename: string, onSubmit: (result: boolean) => void) { + super(app); + this.existingFilename = existingFilename; + this.onSubmit = onSubmit; + } + + onOpen() { + let { contentEl } = this; + contentEl.setText(this.existingFilename + " already exists. Do you want to replace it?"); + + new Setting(contentEl) + .addButton((btn) => + btn + .setButtonText("Cancel") + .setCta() + .onClick(() => { + this.close(); + this.onSubmit(false); + })); + + new Setting(contentEl) + .addButton((btn) => + btn + .setButtonText("Replace") + .setCta() + .onClick(() => { + this.close(); + this.onSubmit(true); + })); + } + onClose() { + let { contentEl } = this; + contentEl.empty(); + } + +} \ No newline at end of file diff --git a/global.ts b/global.ts index 8051291..852b95c 100644 --- a/global.ts +++ b/global.ts @@ -1,5 +1,6 @@ import * as fs from 'fs'; +import * as path from 'path'; export interface PandocPluginSettings { // Show a command like `pandoc -o Output.html -t html -f commonmark Input.md` @@ -30,6 +31,8 @@ export interface PandocPluginSettings { extraArguments: string, // Export from HTML or from markdown? exportFrom: 'html' | 'md', + // If the output file already exists add an integer increment to the filename. eg. MyNote.docx => MyNote1.docx + overwriteMode: 'overwrite' | 'confirm' | 'increment', } export const DEFAULT_SETTINGS: PandocPluginSettings = { @@ -46,19 +49,28 @@ export const DEFAULT_SETTINGS: PandocPluginSettings = { outputFolder: null, extraArguments: '', exportFrom: 'html', + overwriteMode: 'overwrite' } -export function replaceFileExtension(file: string, ext: string): string { - // Source: https://stackoverflow.com/a/5953384/4642943 - let pos = file.lastIndexOf('.'); - return file.substr(0, pos < 0 ? file.length : pos) + '.' + ext; +export function replaceFileExtension(filename: string, ext: string): string { + return path.basename(filename, path.extname(filename)) + '.' + ext; } export async function fileExists(path: string): Promise { try { - const stats = await fs.promises.stat(path); - return stats && stats.isFile(); - } catch (e) { + await fs.promises.access(path) + return true + } catch { return false; } } + +export async function getUniqueFilename (filename: string, increment: number = 0): Promise { + const name = path.join( + path.dirname(filename), + `${path.basename(filename, path.extname(filename))}${increment || ""}${path.extname(filename)}`); + if((await fileExists(name))){ + return getUniqueFilename(filename, increment + 1); + } + return name; +} diff --git a/main.ts b/main.ts index ec9fc8c..5170289 100644 --- a/main.ts +++ b/main.ts @@ -9,16 +9,23 @@ import * as fs from 'fs'; import * as path from 'path'; +import * as YAML from 'yaml'; +import * as temp from 'temp'; import { Notice, Plugin, FileSystemAdapter, MarkdownView } from 'obsidian'; import { lookpath } from 'lookpath'; import { pandoc, inputExtensions, outputFormats, OutputFormat, needsLaTeX, needsPandoc } from './pandoc'; -import * as YAML from 'yaml'; -import * as temp from 'temp'; - +import { ConfirmModal } from "./confirm-modal"; import render from './renderer'; import PandocPluginSettingTab from './settings'; -import { PandocPluginSettings, DEFAULT_SETTINGS, replaceFileExtension } from './global'; +import { + PandocPluginSettings, + DEFAULT_SETTINGS, + replaceFileExtension, + fileExists, + getUniqueFilename +} from './global'; + export default class PandocPlugin extends Plugin { settings: PandocPluginSettings; features: { [key: string]: string | undefined } = {}; @@ -85,7 +92,36 @@ export default class PandocPlugin extends Plugin { this.features['pdflatex'] = this.settings.pdflatex || await lookpath('pdflatex'); } + // noinspection FallThroughInSwitchStatementJS async startPandocExport(inputFile: string, format: OutputFormat, extension: string, shortName: string) { + + let outputFile: string = replaceFileExtension(inputFile, extension); + + if (this.settings.outputFolder) { + outputFile = path.join(this.settings.outputFolder, path.basename(outputFile)); + } + + switch(this.settings.overwriteMode){ + case 'increment': + outputFile = await getUniqueFilename(outputFile); + //fall through + case 'overwrite': + await this.doPandocExport(inputFile, format, outputFile, shortName); + break; + case 'confirm': + if(await fileExists(outputFile)) { + new ConfirmModal(this.app, outputFile, (doOverwrite) => { + if(doOverwrite) { + this.doPandocExport(inputFile, format, outputFile, shortName); + } //else do nothing + }).open(); + } else { //file doesn't exist yet + await this.doPandocExport(inputFile, format, outputFile, shortName); + } + } + } + + private async doPandocExport(inputFile: string, format: OutputFormat, outputFile: string, shortName: string) { new Notice(`Exporting ${inputFile} to ${shortName}`); // Instead of using Pandoc to process the raw Markdown, we use Obsidian's @@ -93,18 +129,14 @@ export default class PandocPlugin extends Plugin { // This allows us to more easily deal with Obsidian specific Markdown syntax. // However, we provide an option to use MD instead to use citations - let outputFile: string = replaceFileExtension(inputFile, extension); - if (this.settings.outputFolder) { - outputFile = path.join(this.settings.outputFolder, path.basename(outputFile)); - } const view = this.app.workspace.getActiveViewOfType(MarkdownView); - + try { let error, command; switch (this.settings.exportFrom) { case 'html': { - const { html, metadata } = await render(this, view, inputFile, format); + const {html, metadata} = await render(this, view, inputFile, format); if (format === 'html') { // Write to HTML file @@ -121,7 +153,7 @@ export default class PandocPlugin extends Plugin { file: 'STDIN', contents: html, format: 'html', metadataFile, pandoc: this.settings.pandoc, pdflatex: this.settings.pdflatex }, - { file: outputFile, format }, + {file: outputFile, format}, this.settings.extraArguments.split('\n') ); error = result.error; @@ -135,7 +167,7 @@ export default class PandocPlugin extends Plugin { file: inputFile, format: 'markdown', pandoc: this.settings.pandoc, pdflatex: this.settings.pdflatex }, - { file: outputFile, format }, + {file: outputFile, format}, this.settings.extraArguments.split('\n') ); error = result.error; diff --git a/settings.ts b/settings.ts index 55d94b7..7393293 100644 --- a/settings.ts +++ b/settings.ts @@ -139,6 +139,21 @@ export default class PandocPluginSettingTab extends PluginSettingTab { await this.plugin.saveSettings(); })); + new Setting(containerEl) + .setName("Overwrite Mode") + .setDesc("Controls what happens when the target output file already exists at the destination") + .addDropdown(dropdown => dropdown + .addOptions({ + "overwrite": "Overwrite existing file", + "confirm": "Confirm before overwriting existing file", + "increment": "Add numerical increment to avoid overwrite", + }) + .setValue(this.plugin.settings.overwriteMode) + .onChange(async (value: string) => { + this.plugin.settings.overwriteMode = value as 'overwrite' | 'confirm' | 'increment'; + await this.plugin.saveSettings(); + })); + new Setting(containerEl) .setName("Extra Pandoc arguments") .setDesc("Add extra command line arguments so you can use templates or bibliographies. Newlines are turned into spaces")