mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-10-01 09:19:34 +05:30
- AI Assistant plugin: multi-provider chat (OpenAI/Anthropic/Ollama/LM Studio), summarize/improve/translate commands, proofread via ai:analyze; calls proxied through main so API keys stay out of the renderer - Collaboration plugin: anchor-based comments in .comments/ sidecars with drift detection and F8 navigation - Local knowledge base: [[wiki-links]] with click-to-create + Backlinks panel - Crash recovery: debounced session snapshots with restore prompt on launch - Version history: pre-save snapshots, History panel with restore/diff/delete - Real PDF encryption: swap pdf-lib for @cantoo/pdf-lib (probe-driven UI) - XLSX export (native workbooks via JSZip), ODT headers/footers + page size - Offline KaTeX (bundled CSS+fonts), local-first PlantUML rendering - Editor: vim mode toggle, snippet Tab-expansion, zen word-goal setter, writing heatmap, writing-studio panels wired with rail icons - Quick Note global scratchpad (Ctrl+Alt+Q), markdownconverter:// deep links, REPL first-run confirmation - Fix: Ctrl+Shift+P collision, pandoc converter availability check, CLI dangling --css/--reference-doc flags, dead converter button 8 new test suites; 613 tests green; lint clean
109 lines
3.8 KiB
JavaScript
109 lines
3.8 KiB
JavaScript
class PluginContext {
|
|
/**
|
|
* @param {object} deps - Injected dependencies
|
|
* @param {string} deps.pluginId - Plugin unique ID (for namespacing)
|
|
* @param {object} deps.sidebar - SidebarManager.registerPanel
|
|
* @param {object} deps.commands - CommandPalette.register
|
|
* @param {object} deps.statusBar - StatusBar.registerIndicator
|
|
* @param {object} deps.eventBus - EventBus instance
|
|
* @param {object} deps.settings - { get, set, onChanged }
|
|
* @param {object} deps.editor - { getContent, getSelection, insertAtCursor, onContentChanged }
|
|
* @param {object} deps.ipc - { invoke, on }
|
|
* @param {object} deps.exportHooks - { preHooks: [], postHooks: [] }
|
|
* @param {object} deps.formatRegistry - FormatRegistry instance ({ register, get, getAll })
|
|
*/
|
|
constructor(deps) {
|
|
const {
|
|
pluginId,
|
|
sidebar,
|
|
commands,
|
|
statusBar,
|
|
eventBus,
|
|
settings,
|
|
editor,
|
|
ipc,
|
|
exportHooks,
|
|
formatRegistry,
|
|
} = deps;
|
|
|
|
this.sidebar = {
|
|
registerPanel: (id, opts) => sidebar.registerPanel(`${pluginId}:${id}`, opts),
|
|
};
|
|
|
|
this.commands = {
|
|
register: (id, label, handler, shortcut) => {
|
|
const safeHandler = (...args) => {
|
|
try {
|
|
handler(...args);
|
|
} catch (err) {
|
|
console.error(`[Plugin:${pluginId}] Command "${id}" error:`, err);
|
|
}
|
|
};
|
|
commands.register(`${pluginId}:${id}`, label, safeHandler, shortcut);
|
|
},
|
|
};
|
|
|
|
this.statusBar = {
|
|
registerIndicator: (id, opts) => statusBar.registerIndicator(`${pluginId}:${id}`, opts),
|
|
};
|
|
|
|
this.settings = {
|
|
get: (key) => settings.get(`plugins.${pluginId}.${key}`),
|
|
set: (key, value) => settings.set(`plugins.${pluginId}.${key}`, value),
|
|
onChanged: (key, cb) => settings.onChanged(`plugins.${pluginId}.${key}`, cb),
|
|
};
|
|
|
|
this.editor = {
|
|
getContent: () => editor.getContent(),
|
|
getSelection: () => editor.getSelection(),
|
|
insertAtCursor: (text) => editor.insertAtCursor(text),
|
|
onContentChanged: (cb) => editor.onContentChanged(cb),
|
|
// Current tab's file path (null for untitled tabs) — plugins that store
|
|
// sidecar data (comments, snapshots, …) key off this.
|
|
getCurrentFilePath: () => (editor.getCurrentFilePath ? editor.getCurrentFilePath() : null),
|
|
// Scroll the active editor to a 1-based line and place the cursor there
|
|
jumpToLine: (line) => {
|
|
if (editor.jumpToLine) editor.jumpToLine(line);
|
|
},
|
|
// 1-based line of the primary cursor
|
|
getCurrentLine: () => (editor.getCurrentLine ? editor.getCurrentLine() : 1),
|
|
};
|
|
|
|
this.events = {
|
|
on: (event, handler) => eventBus.on(event, handler),
|
|
off: (event, handler) => eventBus.off(event, handler),
|
|
emit: (event, payload) => eventBus.emit(event, payload),
|
|
hasHandler: (event) => eventBus.hasHandler(event),
|
|
};
|
|
|
|
this.ipc = {
|
|
invoke: (channel, ...args) => ipc.invoke(channel, ...args),
|
|
on: (channel, handler) => ipc.on(channel, handler),
|
|
};
|
|
|
|
this.exports = {
|
|
registerPreHook: (handler) => {
|
|
if (exportHooks) exportHooks.preHooks.push(handler);
|
|
},
|
|
registerPostHook: (handler) => {
|
|
if (exportHooks) exportHooks.postHooks.push(handler);
|
|
},
|
|
};
|
|
|
|
this.formats = {
|
|
/**
|
|
* Register a plugin-provided export format. It is namespaced as
|
|
* `${pluginId}:${id}` so plugins can't collide with each other or
|
|
* with the built-in Pandoc-backed formats.
|
|
* @param {string} id - Format id, unique within this plugin.
|
|
* @param {object} opts - { label, extension, handler: async (markdownContent, outputPath, options) => void }
|
|
*/
|
|
registerExportFormat: (id, opts) => {
|
|
if (formatRegistry) formatRegistry.register(`${pluginId}:${id}`, opts);
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
module.exports = { PluginContext };
|