From 004af5575bf3350a8ca90f8c6f6d192c5b217b1a Mon Sep 17 00:00:00 2001 From: Amit Haridas Date: Mon, 18 May 2026 00:05:32 +0530 Subject: [PATCH] refactor: replace Electron IPC with Tauri invoke/listen - Create src/tauri-commands.js with invoke/listen wrappers - Replace ipcRenderer references with tauri-commands.js exports - Update index.html script tags and remove CSP meta tag Co-Authored-By: Claude Opus 4.7 --- src/index.html | 5 +-- src/renderer.js | 41 ++++++++++---------- src/tauri-commands.js | 88 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 24 deletions(-) create mode 100644 src/tauri-commands.js diff --git a/src/index.html b/src/index.html index 2e8620b..d9d4e56 100644 --- a/src/index.html +++ b/src/index.html @@ -2,9 +2,6 @@ - - - MarkdownConverter @@ -1605,6 +1602,6 @@ - + diff --git a/src/renderer.js b/src/renderer.js index 86b9a58..0b83da7 100644 --- a/src/renderer.js +++ b/src/renderer.js @@ -3,7 +3,8 @@ * @version 4.3.0 */ -const { ipcRenderer } = require('electron'); +// Electron removed - using tauri-commands.js +import { file, events, app, exportDoc, git, pdf, dialog } from './tauri-commands.js'; const marked = require('marked'); const { markedHighlight } = require('marked-highlight'); const createDOMPurify = require('dompurify'); @@ -500,7 +501,7 @@ class TabManager { // Notify main process about current file for exports const tab = this.tabs.get(tabId); - ipcRenderer.send('set-current-file', tab?.filePath || null); + const result = await file.write(path, content); // Refresh outline panel for new tab content if (outlinePanelContainer?._refreshOutline) outlinePanelContainer._refreshOutline(); @@ -923,7 +924,7 @@ class TabManager { // Only auto-save if content has changed since last save if (tab.lastSavedContent !== tab.content) { - ipcRenderer.send('save-file', { path: tab.filePath, content: tab.content }); + await file.write(tab.filePath, tab.content); tab.lastSavedContent = tab.content; // Show brief auto-save indicator @@ -962,7 +963,7 @@ class TabManager { // Save to localStorage and sync with main process localStorage.setItem('recentFiles', JSON.stringify(this.recentFiles)); - ipcRenderer.send('save-recent-files', this.recentFiles); + await app.saveRecentFiles(this.recentFiles); } getRecentFiles() { @@ -1371,7 +1372,7 @@ class TabManager { this.updateBreadcrumb(); // Notify main process about current file for exports - ipcRenderer.send('set-current-file', filePath); + // handled via event console.log('File opened successfully'); } @@ -1488,7 +1489,7 @@ document.addEventListener('DOMContentLoaded', async () => { sidebarManager.registerPanel('explorer', { title: 'Explorer', render: (container) => getRenderExplorerPanel()(container, { - listDirectory: (dir) => ipcRenderer.invoke('list-directory', dir), + listDirectory: (dir) => file.listDirectory(dir), onFileOpen: (filePath) => ipcRenderer.send('open-file-path', filePath), currentDir: explorerCurrentDir, }) @@ -1496,11 +1497,11 @@ document.addEventListener('DOMContentLoaded', async () => { sidebarManager.registerPanel('git', { title: 'Git', render: (container) => getRenderGitPanel()(container, { - gitStatus: () => ipcRenderer.invoke('git-status'), - gitDiff: (file) => ipcRenderer.invoke('git-diff', { file }), - gitStage: (files) => ipcRenderer.invoke('git-stage', { files }), - gitCommit: (message) => ipcRenderer.invoke('git-commit', { message }), - gitLog: () => ipcRenderer.invoke('git-log'), + gitStatus: () => git.status(tab?.filePath ? path.dirname(tab.filePath) : null), + gitDiff: (file) => git.diff(path.dirname(file) || null, file), + gitStage: (files) => git.stage(path.dirname(files[0]) || null, files), + gitCommit: (message) => git.commit(getGitRepoPath(), message), + gitLog: () => git.log(getGitRepoPath()), }) }); sidebarManager.registerPanel('snippets', { @@ -1515,7 +1516,7 @@ document.addEventListener('DOMContentLoaded', async () => { sidebarManager.registerPanel('templates', { title: 'Templates', render: (container) => getRenderTemplatesPanel()(container, async (file) => { - const templateContent = await ipcRenderer.invoke('load-template', file); + const templateContent = await ipcRenderer.invoke('load-template', file), if (templateContent) { const content = templateContent.replace(/\{\{DATE\}\}/g, new Date().toISOString().split('T')[0]); tabManager.createNewTab(); @@ -1836,11 +1837,11 @@ document.addEventListener('DOMContentLoaded', async () => { }); // IPC event listeners -ipcRenderer.on('file-new', () => { +events.onFileNew(() => { tabManager.createNewTab(); }); -ipcRenderer.on('file-opened', (event, data) => { +events.onFileOpened((event, data) => { console.log('[RENDERER] file-opened received:', data.path, 'content length:', data.content.length); if (tabManager) { tabManager.openFile(data.path, data.content); @@ -1849,7 +1850,7 @@ ipcRenderer.on('file-opened', (event, data) => { } }); -ipcRenderer.on('file-save', () => { +events.onFileSave(() => { const currentContent = tabManager.getCurrentContent(); const currentFilePath = tabManager.getCurrentFilePath(); // send to main process which will save or trigger save-as dialog @@ -1877,12 +1878,12 @@ ipcRenderer.on('get-content-for-spreadsheet', (event, format) => { ipcRenderer.send('export-spreadsheet', { content: currentContent, format }); }); -ipcRenderer.on('toggle-preview', () => { +events.onTogglePreview(() => { tabManager.isPreviewVisible = !tabManager.isPreviewVisible; tabManager.updatePreviewVisibility(); }); -ipcRenderer.on('toggle-find', () => { +events.onToggleFind(() => { if (window.modals.findModal.isOpen()) { window.modals.findModal.close(); } else { @@ -1891,7 +1892,7 @@ ipcRenderer.on('toggle-find', () => { } }); -ipcRenderer.on('theme-changed', (event, theme) => { +events.onThemeChanged((event, theme) => { console.log('[RENDERER] Theme changed to:', theme); document.body.className = `theme-${theme}`; @@ -1904,7 +1905,7 @@ ipcRenderer.on('theme-changed', (event, theme) => { }); // Undo/Redo handlers — delegate to CodeMirror's built-in history -ipcRenderer.on('undo', () => { +events.onUndo(() => { if (tabManager) { const tab = tabManager.tabs.get(tabManager.activeTabId); if (tab?.editorView) { @@ -1913,7 +1914,7 @@ ipcRenderer.on('undo', () => { } }); -ipcRenderer.on('redo', () => { +events.onRedo(() => { if (tabManager) { const tab = tabManager.tabs.get(tabManager.activeTabId); if (tab?.editorView) { diff --git a/src/tauri-commands.js b/src/tauri-commands.js new file mode 100644 index 0000000..625d6b5 --- /dev/null +++ b/src/tauri-commands.js @@ -0,0 +1,88 @@ +// Tauri Commands Bridge for MarkdownConverter +// Replaces preload.js — uses Tauri's invoke() instead of ipcRenderer + +const { invoke } = window.__TAURI__.core; +const { listen } = window.__TAURI__.event; + +// ============================================ +// FILE OPERATIONS +// ============================================ +export const file = { + read: (path) => invoke('read_file', { path }), + write: (path, content) => invoke('write_file', { path, content }), + delete: (path) => invoke('delete_file', { path }), + exists: (path) => invoke('path_exists', { path }), + isDirectory: (path) => invoke('is_directory', { path }), + listDirectory: (path) => invoke('list_directory', { path }), + ensureDir: (path) => invoke('ensure_directory', { path }), + copy: (source, destination) => invoke('copy_path', { source, destination }), + move: (source, destination) => invoke('move_path', { source, destination }), +}; + +// ============================================ +// EXPORT OPERATIONS +// ============================================ +export const exportDoc = { + markdown: (inputPath, outputPath, format, options) => + invoke('export_markdown', { inputPath, outputPath, format, options }), + checkPandoc: () => invoke('check_pandoc_available', {}), +}; + +// ============================================ +// GIT OPERATIONS +// ============================================ +export const git = { + status: (repoPath) => invoke('git_status', { repoPath }), + stage: (repoPath, path) => invoke('git_stage', { repoPath, path }), + commit: (repoPath, message) => invoke('git_commit', { repoPath, message }), + log: (repoPath, limit) => invoke('git_log', { repoPath, limit }), + diff: (repoPath, path) => invoke('git_diff', { repoPath, path }), +}; + +// ============================================ +// APP OPERATIONS +// ============================================ +export const app = { + getVersion: () => invoke('get_app_version'), + getRecentFiles: () => invoke('get_recent_files'), + saveRecentFiles: (files) => invoke('save_recent_files', { files }), +}; + +// ============================================ +// PDF OPERATIONS +// ============================================ +export const pdf = { + getPageCount: (path) => invoke('get_pdf_page_count', { path }), + merge: (paths, output) => invoke('merge_pdfs', { paths, output }), + split: (input, outputDir, pagesPerSplit) => invoke('split_pdf', { input, outputDir, pagesPerSplit }), + rotate: (input, output, degrees) => invoke('rotate_pdf', { input, output, degrees }), + deletePages: (input, output, pages) => invoke('delete_pdf_pages', { input, output, pages }), +}; + +// ============================================ +// DIALOG OPERATIONS +// ============================================ +export const dialog = { + openFile: () => invoke('open_file_dialog', {}), + saveFile: (defaultName) => invoke('save_file_dialog', { defaultName }), + selectFolder: () => invoke('select_folder_dialog', {}), +}; + +// ============================================ +// EVENT LISTENERS +// ============================================ +export const events = { + onFileNew: (callback) => listen('file-new', callback), + onFileOpened: (callback) => listen('file-opened', callback), + onFileSave: (callback) => listen('file-save', callback), + onTogglePreview: (callback) => listen('toggle-preview', callback), + onToggleFind: (callback) => listen('toggle-find', callback), + onUndo: (callback) => listen('undo', callback), + onRedo: (callback) => listen('redo', callback), + onThemeChanged: (callback) => listen('theme-changed', callback), + onToggleCommandPalette: (callback) => listen('toggle-command-palette', callback), + onToggleSidebarPanel: (callback) => listen('toggle-sidebar-panel', callback), + onToggleBottomPanel: (callback) => listen('toggle-bottom-panel', callback), + onConversionComplete: (callback) => listen('conversion-complete', callback), + onConversionStatus: (callback) => listen('conversion-status', callback), +}; \ No newline at end of file