Files
markdown-converter/src/plugins/plugin-context.js
T
amitwh c4dcbd8caf feat: v4.6.0 — AI assistant, collaboration, knowledge base, and 15 more features
- 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
2026-09-05 20:48:39 +05:30

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 };