257 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			257 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| var obsidian = require('obsidian');
 | |
| var child_process = require('child_process');
 | |
| var path = require('path');
 | |
| 
 | |
| function _interopNamespaceDefault(e) {
 | |
|     var n = Object.create(null);
 | |
|     if (e) {
 | |
|         Object.keys(e).forEach(function (k) {
 | |
|             if (k !== 'default') {
 | |
|                 var d = Object.getOwnPropertyDescriptor(e, k);
 | |
|                 Object.defineProperty(n, k, d.get ? d : {
 | |
|                     enumerable: true,
 | |
|                     get: function () { return e[k]; }
 | |
|                 });
 | |
|             }
 | |
|         });
 | |
|     }
 | |
|     n.default = e;
 | |
|     return Object.freeze(n);
 | |
| }
 | |
| 
 | |
| var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
 | |
| 
 | |
| const DEFAULT_SETTINGS = {
 | |
|     quartoPath: 'quarto',
 | |
|     enableQmdLinking: true,
 | |
|     quartoTypst: '',
 | |
|     emitCompilationLogs: true, // Default is to emit logs
 | |
| };
 | |
| class QmdAsMdPlugin extends obsidian.Plugin {
 | |
|     constructor() {
 | |
|         super(...arguments);
 | |
|         this.activePreviewProcesses = new Map();
 | |
|     }
 | |
|     async onload() {
 | |
|         console.log('Plugin is loading...');
 | |
|         try {
 | |
|             await this.loadSettings();
 | |
|             console.log('Settings loaded:', this.settings);
 | |
|             if (this.settings.enableQmdLinking) {
 | |
|                 this.registerQmdExtension();
 | |
|             }
 | |
|             this.addSettingTab(new QmdSettingTab(this.app, this));
 | |
|             console.log('Settings tab added successfully');
 | |
|             this.addRibbonIcon('eye', 'Toggle Quarto Preview', async () => {
 | |
|                 const activeView = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
 | |
|                 if (activeView?.file && this.isQuartoFile(activeView.file)) {
 | |
|                     console.log(`Toggling preview for: ${activeView.file.path}`);
 | |
|                     await this.togglePreview(activeView.file);
 | |
|                 }
 | |
|                 else {
 | |
|                     new obsidian.Notice('Current file is not a Quarto document');
 | |
|                 }
 | |
|             });
 | |
|             console.log('Ribbon icon added');
 | |
|             this.addCommand({
 | |
|                 id: 'toggle-quarto-preview',
 | |
|                 name: 'Toggle Quarto Preview',
 | |
|                 callback: async () => {
 | |
|                     const activeView = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
 | |
|                     if (activeView?.file && this.isQuartoFile(activeView.file)) {
 | |
|                         console.log(`Command: Toggling preview for ${activeView.file.path}`);
 | |
|                         await this.togglePreview(activeView.file);
 | |
|                     }
 | |
|                     else {
 | |
|                         new obsidian.Notice('Current file is not a Quarto document');
 | |
|                     }
 | |
|                 },
 | |
|                 hotkeys: [{ modifiers: ['Ctrl', 'Shift'], key: 'p' }],
 | |
|             });
 | |
|             console.log('Commands added');
 | |
|         }
 | |
|         catch (error) {
 | |
|             console.error('Error loading plugin:', error);
 | |
|             new obsidian.Notice('Failed to load QmdAsMdPlugin. Check the developer console for details.');
 | |
|         }
 | |
|     }
 | |
|     onunload() {
 | |
|         console.log('Plugin is unloading...');
 | |
|         this.stopAllPreviews();
 | |
|     }
 | |
|     async loadSettings() {
 | |
|         this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
 | |
|     }
 | |
|     async saveSettings() {
 | |
|         await this.saveData(this.settings);
 | |
|     }
 | |
|     isQuartoFile(file) {
 | |
|         return file.extension === 'qmd';
 | |
|     }
 | |
|     registerQmdExtension() {
 | |
|         console.log('Registering .qmd as markdown...');
 | |
|         this.registerExtensions(['qmd'], 'markdown');
 | |
|         console.log('.qmd registered as markdown');
 | |
|     }
 | |
|     async togglePreview(file) {
 | |
|         if (this.activePreviewProcesses.has(file.path)) {
 | |
|             await this.stopPreview(file);
 | |
|         }
 | |
|         else {
 | |
|             await this.startPreview(file);
 | |
|         }
 | |
|     }
 | |
|     async startPreview(file) {
 | |
|         if (this.activePreviewProcesses.has(file.path)) {
 | |
|             console.log(`Preview already running for: ${file.path}`);
 | |
|             return; // Preview already running
 | |
|         }
 | |
|         try {
 | |
|             const abstractFile = this.app.vault.getAbstractFileByPath(file.path);
 | |
|             if (!abstractFile || !(abstractFile instanceof obsidian.TFile)) {
 | |
|                 new obsidian.Notice(`File ${file.path} not found`);
 | |
|                 return;
 | |
|             }
 | |
|             const filePath = this.app.vault.adapter.getFullPath(abstractFile.path);
 | |
|             const workingDir = path__namespace.dirname(filePath);
 | |
|             console.log(`Resolved file path: ${filePath}`);
 | |
|             console.log(`Working directory: ${workingDir}`);
 | |
|             const envVars = {
 | |
|                 ...process.env,
 | |
|             };
 | |
|             if (this.settings.quartoTypst.trim()) {
 | |
|                 envVars.QUARTO_TYPST = this.settings.quartoTypst.trim();
 | |
|                 console.log(`QUARTO_TYPST set to: ${envVars.QUARTO_TYPST}`);
 | |
|             }
 | |
|             const quartoProcess = child_process.spawn(this.settings.quartoPath, ['preview', filePath], {
 | |
|                 cwd: workingDir,
 | |
|                 env: envVars,
 | |
|             });
 | |
|             let previewUrl = null;
 | |
|             quartoProcess.stdout?.on('data', (data) => {
 | |
|                 const output = data.toString();
 | |
|                 if (this.settings.emitCompilationLogs) {
 | |
|                     console.log(`Quarto Preview Output: ${output}`);
 | |
|                 }
 | |
|                 if (output.includes('Browse at')) {
 | |
|                     const match = output.match(/Browse at\s+(http:\/\/[^\s]+)/);
 | |
|                     if (match && match[1]) {
 | |
|                         previewUrl = match[1];
 | |
|                         new obsidian.Notice(`Preview available at ${previewUrl}`);
 | |
|                         const leaf = this.app.workspace.getLeaf('tab');
 | |
|                         leaf.setViewState({
 | |
|                             type: 'webviewer',
 | |
|                             active: true,
 | |
|                             state: {
 | |
|                                 url: previewUrl,
 | |
|                             },
 | |
|                         });
 | |
|                         this.app.workspace.revealLeaf(leaf);
 | |
|                     }
 | |
|                 }
 | |
|             });
 | |
|             quartoProcess.stderr?.on('data', (data) => {
 | |
|                 if (this.settings.emitCompilationLogs) {
 | |
|                     console.error(`Quarto Preview Error: ${data}`);
 | |
|                 }
 | |
|             });
 | |
|             quartoProcess.on('close', (code) => {
 | |
|                 if (code !== null && code !== 0) {
 | |
|                     new obsidian.Notice(`Quarto preview process exited with code ${code}`);
 | |
|                 }
 | |
|                 this.activePreviewProcesses.delete(file.path);
 | |
|             });
 | |
|             this.activePreviewProcesses.set(file.path, quartoProcess);
 | |
|             new obsidian.Notice('Quarto preview started');
 | |
|         }
 | |
|         catch (error) {
 | |
|             console.error('Failed to start Quarto preview:', error);
 | |
|             new obsidian.Notice('Failed to start Quarto preview');
 | |
|         }
 | |
|     }
 | |
|     async stopPreview(file) {
 | |
|         const quartoProcess = this.activePreviewProcesses.get(file.path);
 | |
|         if (quartoProcess) {
 | |
|             if (!quartoProcess.killed) {
 | |
|                 quartoProcess.kill();
 | |
|             }
 | |
|             this.activePreviewProcesses.delete(file.path);
 | |
|             new obsidian.Notice('Quarto preview stopped');
 | |
|         }
 | |
|     }
 | |
|     stopAllPreviews() {
 | |
|         this.activePreviewProcesses.forEach((quartoProcess, filePath) => {
 | |
|             if (!quartoProcess.killed) {
 | |
|                 quartoProcess.kill();
 | |
|             }
 | |
|             this.activePreviewProcesses.delete(filePath);
 | |
|         });
 | |
|         if (this.activePreviewProcesses.size > 0) {
 | |
|             new obsidian.Notice('All Quarto previews stopped');
 | |
|         }
 | |
|     }
 | |
| }
 | |
| class QmdSettingTab extends obsidian.PluginSettingTab {
 | |
|     constructor(app, plugin) {
 | |
|         super(app, plugin);
 | |
|         this.plugin = plugin;
 | |
|     }
 | |
|     display() {
 | |
|         const { containerEl } = this;
 | |
|         containerEl.empty();
 | |
|         console.log('Rendering settings tab...');
 | |
|         containerEl.createEl('h2', { text: 'Quarto Preview Settings' });
 | |
|         new obsidian.Setting(containerEl)
 | |
|             .setName('Quarto Path')
 | |
|             .setDesc('Path to Quarto executable (e.g., quarto, /usr/local/bin/quarto)')
 | |
|             .addText((text) => text
 | |
|             .setPlaceholder('quarto')
 | |
|             .setValue(this.plugin.settings.quartoPath)
 | |
|             .onChange(async (value) => {
 | |
|             console.log(`Quarto path changed to: ${value}`);
 | |
|             this.plugin.settings.quartoPath = value;
 | |
|             await this.plugin.saveSettings();
 | |
|         }));
 | |
|         new obsidian.Setting(containerEl)
 | |
|             .setName('Enable Editing Quarto Files')
 | |
|             .setDesc('By default, plugin allows editing .qmd files. Disable this feature if there is a conflict with .qmd editing enabled by another plugin')
 | |
|             .addToggle((toggle) => toggle
 | |
|             .setValue(this.plugin.settings.enableQmdLinking)
 | |
|             .onChange(async (value) => {
 | |
|             console.log(`Enable QMD Editing setting changed to: ${value}`);
 | |
|             this.plugin.settings.enableQmdLinking = value;
 | |
|             if (value) {
 | |
|                 this.plugin.registerQmdExtension();
 | |
|             }
 | |
|         }));
 | |
|         new obsidian.Setting(containerEl)
 | |
|             .setName('QUARTO_TYPST Variable')
 | |
|             .setDesc('Define the QUARTO_TYPST environment variable (leave empty to unset)')
 | |
|             .addText((text) => text
 | |
|             .setPlaceholder('e.g., typst_path')
 | |
|             .setValue(this.plugin.settings.quartoTypst)
 | |
|             .onChange(async (value) => {
 | |
|             console.log(`QUARTO_TYPST set to: ${value}`);
 | |
|             this.plugin.settings.quartoTypst = value;
 | |
|             await this.plugin.saveSettings();
 | |
|         }));
 | |
|         new obsidian.Setting(containerEl)
 | |
|             .setName('Emit Compilation Logs')
 | |
|             .setDesc('Toggle whether to emit detailed compilation logs in the console')
 | |
|             .addToggle((toggle) => toggle
 | |
|             .setValue(this.plugin.settings.emitCompilationLogs)
 | |
|             .onChange(async (value) => {
 | |
|             console.log(`Emit Compilation Logs set to: ${value}`);
 | |
|             this.plugin.settings.emitCompilationLogs = value;
 | |
|             await this.plugin.saveSettings();
 | |
|         }));
 | |
|         console.log('Settings tab rendered successfully');
 | |
|     }
 | |
| }
 | |
| 
 | |
| module.exports = QmdAsMdPlugin;
 | |
| 
 | |
| 
 | |
| /* nosourcemap */ |