mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-10-01 17:29:29 +05:30
feat(plugins): add export-format registration hook to plugin API
Add context.formats.registerExportFormat(id, opts) to PluginContext,
backed by a new FormatRegistry (mirrors PluginRegistry's Map-based
shape). Plugins register namespaced (${pluginId}:${id}) export
formats with a label/extension/handler; the writing-studio built-in
plugin registers a trivial "sprint-summary" .txt export as a
worked example.
The plugin system lives entirely in the renderer process while the
Export menu is built in main.js, so wiring formats into the menu
required a small IPC round-trip: renderer sends format metadata to
main after plugin load (main rebuilds the menu via the already-
idempotent createMenu()), and a menu click sends the resolved save
path back to the renderer, which is the only process holding the
plugin's handler function.
Amit Haridas
This commit is contained in:
@@ -29,6 +29,7 @@ class WritingStudioPlugin extends PluginAPI {
|
||||
|
||||
this._registerCommands(context);
|
||||
this._registerStatusBar(context);
|
||||
this._registerExportFormats(context);
|
||||
}
|
||||
|
||||
_registerCommands(context) {
|
||||
@@ -120,6 +121,42 @@ class WritingStudioPlugin extends PluginAPI {
|
||||
});
|
||||
}
|
||||
|
||||
// Example usage of context.formats.registerExportFormat (Task 17): adds
|
||||
// a "Writing Studio Summary" entry to the Export menu that writes a
|
||||
// plain-text snapshot of today's sprint/goal progress instead of going
|
||||
// through Pandoc. Doubles as documentation for how a plugin can offer
|
||||
// its own export target.
|
||||
_registerExportFormats(context) {
|
||||
const { sprintEngine, goalTracker } = this;
|
||||
|
||||
context.formats.registerExportFormat('sprint-summary', {
|
||||
label: 'Writing Studio Summary (.txt)',
|
||||
extension: 'txt',
|
||||
handler: async (markdownContent, outputPath) => {
|
||||
const fs = require('fs');
|
||||
const goal = context.settings.get('dailyGoal') || 1000;
|
||||
const progress = goalTracker.getDailyProgress(goal);
|
||||
const streak = goalTracker.getStreak(goal);
|
||||
const wordCount = (markdownContent || '').split(/\s+/).filter(Boolean).length;
|
||||
|
||||
const lines = [
|
||||
'Writing Studio Summary',
|
||||
'=======================',
|
||||
`Generated: ${new Date().toISOString()}`,
|
||||
'',
|
||||
`Document word count: ${wordCount}`,
|
||||
`Daily goal: ${goal}`,
|
||||
`Words written today: ${progress.written} (${progress.pct}%)`,
|
||||
`Current streak: ${streak} day(s)`,
|
||||
`Sprint active: ${sprintEngine.isActive() ? 'yes' : 'no'}`,
|
||||
'',
|
||||
];
|
||||
|
||||
fs.writeFileSync(outputPath, lines.join('\n'), 'utf-8');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
deactivate() {
|
||||
if (this._sprintInterval) clearInterval(this._sprintInterval);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,14 @@
|
||||
"shortcut": "Ctrl+Alt+G"
|
||||
}
|
||||
],
|
||||
"statusBar": { "indicators": ["sprint-timer", "word-goal"] }
|
||||
"statusBar": { "indicators": ["sprint-timer", "word-goal"] },
|
||||
"exportFormats": [
|
||||
{
|
||||
"id": "sprint-summary",
|
||||
"label": "Writing Studio Summary (.txt)",
|
||||
"extension": "txt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"settings": [
|
||||
{ "key": "dailyGoal", "type": "number", "default": 1000, "label": "Daily word goal" },
|
||||
|
||||
Reference in New Issue
Block a user