Architecture overview¶
The plugin subsystem is built from three components, all under Components/:
| Component | Visibility | Responsibility |
|---|---|---|
PluginApi |
Public | Pure abstract interfaces + value types. No Qt, no Scintilla, no MTE-internal headers — only the standard library. |
PluginHost |
Internal | Loads, owns, and dispatches plugins. Qt is an implementation detail here (it uses QPluginLoader behind the scenes). |
Plugins |
First-party | Example/built-in plugins; each its own CMake target depending only on PluginApi (and Qt, when using the native backend). |
Design principles¶
- Backend-agnostic contract. All
PluginApitypes live innamespace MTE::pluginand must not include any Qt, Scintilla, or MTE-internal header. This is what lets a future Python backend fulfil the same contract with no Qt impedance. - No third-party types across the public API. Plugins never see Scintilla or
Qt types; the host adapts between the internal
IEditorViewand the publicIEditorService. - RAII everywhere. Registering a command, menu item, dock panel, or event
subscription returns a token/subscription handle. Destroying it unregisters
the contribution. Plugins hold their tokens as members so everything is torn
down automatically in
shutdown().
Lifecycle¶
Every plugin implements a single interface, IPlugin:
class IPlugin {
public:
virtual ~IPlugin() = default;
virtual PluginInfo info() const = 0;
virtual bool initialize(IPluginContext& ctx) = 0;
virtual void shutdown() noexcept = 0;
};
info()returns POD metadata (id,name,version,vendor,description,apiVersion).initialize(ctx)receives anIPluginContextservice locator. The plugin grabs the services it needs and registers its commands, menus, panels, and event subscriptions.shutdown()runs on the way out; because contributions are RAII tokens, the default teardown is usually just letting members destruct.
No hot reload
Enabling, disabling, installing, and uninstalling a plugin all take effect on the next launch. The host never loads or unloads plugin code while running — this keeps the model simple and sidesteps the Windows "cannot delete a loaded DLL" problem.
Discovery¶
The host scans, in order:
<exe-dir>/Plugins/— bundled first-party plugins.<AppLocalData>/Plugins/— the per-user install directory.- Paths from the
MTE_PLUGIN_PATHenvironment variable.
Each directory is scanned for loose libraries and one level of immediate
subdirectories (the per-plugin <id>/ layout an installer produces). Discovery
does not recurse deeper.