fix(renderer): add ensureEditor fallback and fix pandoc export path

1. Source editor blank: Added ensureEditor() method with try-catch that
   lazily creates the CodeMirror editor when setEditorContent is called
   if the initial DOMContentLoaded creation failed or was skipped.
   Replaced inline createEditor calls in createTabElements and
   DOMContentLoaded with ensureEditor().

2. Export via pandoc failing: runPandocCmd parsed the full path
   /bin/linux/pandoc as the command, then prepended it to args because
   parsed.command !== 'pandoc'. This caused pandoc to receive its own
   binary path as the first input file. Fix: use path.basename() to
   check if the command ends with 'pandoc' (or 'pandoc.exe').

Amit Haridas
This commit is contained in:
2026-06-03 20:44:00 +05:30
parent fff15d8d3e
commit 515126f1a3
2 changed files with 45 additions and 54 deletions
+3 -1
View File
@@ -242,7 +242,9 @@ function runPandoc(args, callback) {
function runPandocCmd(cmdString, callback) { function runPandocCmd(cmdString, callback) {
const parsed = parseCommand(cmdString); const parsed = parseCommand(cmdString);
// Skip 'pandoc' if it's the first element (command itself) // Skip 'pandoc' if it's the first element (command itself)
const args = parsed.command === 'pandoc' ? parsed.args : [parsed.command, ...parsed.args]; // Use path.basename to handle full paths like bin/linux/pandoc
const cmdBase = path.basename(parsed.command).replace(/\.exe$/i, '');
const args = cmdBase === 'pandoc' ? parsed.args : [parsed.command, ...parsed.args];
const pandocPath = getPandocPath(); const pandocPath = getPandocPath();
execFile(pandocPath, args, { maxBuffer: 10 * 1024 * 1024 }, callback); execFile(pandocPath, args, { maxBuffer: 10 * 1024 * 1024 }, callback);
} }
+42 -53
View File
@@ -490,38 +490,7 @@ class TabManager {
document.querySelector('.editor-container').appendChild(tabContent); document.querySelector('.editor-container').appendChild(tabContent);
// Initialize CodeMirror editor // Initialize CodeMirror editor
const editorContainer = document.getElementById(`editor-cm-${tab.id}`); this.ensureEditor(tab);
if (editorContainer) {
const isDark = document.body.className.includes('dark');
tab.editorView = createEditor(editorContainer, {
content: tab.content,
onChange: (newContent) => {
tab.content = newContent;
tab.isDirty = true;
// Dynamically enable/disable Large File Mode on edit
if (newContent.length > 1024 * 1024) {
if (!tab.largeFileMode) {
tab.largeFileMode = true;
this.isPreviewVisible = false;
this.updatePreviewVisibility();
notifyUser('Large content detected (>1MB). Large File Mode enabled to maintain peak responsiveness. Live preview auto-render is disabled.', 'warning');
}
} else {
tab.largeFileMode = false;
}
this.updatePreview(tab.id);
this.updateWordCount();
this.updateTabBar();
if (outlinePanelContainer?._refreshOutline) outlinePanelContainer._refreshOutline();
},
onUpdate: (view) => {
this.updateCursorPosition(view);
if (outlinePanelContainer?._setActiveHeading) outlinePanelContainer._setActiveHeading(view.state.doc.lineAt(view.state.selection.main.head).number);
},
isDark,
showLineNumbers: this.showLineNumbers,
});
}
} }
switchToTab(tabId) { switchToTab(tabId) {
@@ -1492,9 +1461,47 @@ class TabManager {
return tab?.content || ''; return tab?.content || '';
} }
// Ensure a tab has a CodeMirror editor (lazy creation fallback)
ensureEditor(tab) {
if (tab.editorView) return true;
const editorContainer = document.getElementById(`editor-cm-${tab.id}`);
if (!editorContainer) {
console.error(`[ensureEditor] editor-cm-${tab.id} not found in DOM`);
return false;
}
try {
const isDark = document.body.className.includes('dark');
tab.editorView = createEditor(editorContainer, {
content: tab.content,
onChange: (newContent) => {
tab.content = newContent;
tab.isDirty = true;
this.updatePreview(tab.id);
this.updateWordCount();
this.updateTabBar();
if (outlinePanelContainer?._refreshOutline) outlinePanelContainer._refreshOutline();
},
onUpdate: (view) => {
this.updateCursorPosition(view);
if (outlinePanelContainer?._setActiveHeading) outlinePanelContainer._setActiveHeading(view.state.doc.lineAt(view.state.selection.main.head).number);
},
isDark,
showLineNumbers: this.showLineNumbers,
});
console.log(`[ensureEditor] Created editor for tab ${tab.id}`);
return true;
} catch (err) {
console.error(`[ensureEditor] Failed to create editor for tab ${tab.id}:`, err);
return false;
}
}
// Set content in editor // Set content in editor
setEditorContent(tabId, content) { setEditorContent(tabId, content) {
const tab = this.tabs.get(tabId); const tab = this.tabs.get(tabId);
if (!tab?.editorView) {
this.ensureEditor(tab);
}
if (tab?.editorView) { if (tab?.editorView) {
tab.editorView.dispatch({ tab.editorView.dispatch({
changes: { from: 0, to: tab.editorView.state.doc.length, insert: content } changes: { from: 0, to: tab.editorView.state.doc.length, insert: content }
@@ -1908,27 +1915,9 @@ document.addEventListener('DOMContentLoaded', async () => {
}); });
// Initialize CodeMirror for the initial tab (tab 1) // Initialize CodeMirror for the initial tab (tab 1)
const initialEditorContainer = document.getElementById('editor-cm-1'); const initialTab = tabManager.tabs.get(1);
if (initialEditorContainer) { if (initialTab) {
const tab = tabManager.tabs.get(1); tabManager.ensureEditor(initialTab);
const isDark = document.body.className.includes('dark');
tab.editorView = createEditor(initialEditorContainer, {
content: tab.content,
onChange: (newContent) => {
tab.content = newContent;
tab.isDirty = true;
tabManager.updatePreview(tab.id);
tabManager.updateWordCount();
tabManager.updateTabBar();
if (outlinePanelContainer?._refreshOutline) outlinePanelContainer._refreshOutline();
},
onUpdate: (view) => {
tabManager.updateCursorPosition(view);
if (outlinePanelContainer?._setActiveHeading) outlinePanelContainer._setActiveHeading(view.state.doc.lineAt(view.state.selection.main.head).number);
},
isDark,
showLineNumbers: tabManager.showLineNumbers,
});
} }
// Request current theme // Request current theme