Scrivere un plugin nativo¶
Un plugin nativo minimo è una classe, una macro di fabbrica, un file JSON e un
breve CMakeLists.txt. Puoi scriverlo interamente fuori dall'albero dei
sorgenti, appoggiandoti all'SDK per plugin: non serve una copia dei sorgenti di
MTE.
Nativo o Python?
Questa pagina tratta i plugin nativi in C++ (compilati in un
.dll/.so/.dylib e caricati dal caricatore Qt). Se preferisci
distribuire una cartella di file .py che l'editor avvia come
sottoprocesso, vedi Plugin Python — stessa
superficie di PluginApi, backend diverso, nessun compilatore richiesto.
Bozza
Questa guida è basata su PLUGIN_ARCHITECTURE.md; verifica il nome esatto
del pacchetto SDK e gli argomenti di mte_add_plugin() rispetto all'SDK
distribuito prima di farci affidamento.
1. Implementa IPlugin¶
#include <PluginApi/IPlugin.h>
#include <PluginApi/IPluginContext.h>
class HelloWorldPlugin : public MTE::plugin::IPlugin {
public:
MTE::plugin::PluginInfo info() const override {
return { "org.mte.helloworld", "Hello World", "1.0.0",
"Example Vendor", "Says hi.", MTE_PLUGIN_API_VERSION };
}
bool initialize(MTE::plugin::IPluginContext& ctx) override {
m_cmd = ctx.commands().registerCommand(
{ "helloworld.sayHi", "Say Hi", "Ctrl+Alt+H", "Hello" },
[&ctx] { ctx.log().log(MTE::plugin::LogLevel::Info, "Hi!"); });
m_menu = ctx.menus().addItem("Plugins/Say Hi", "helloworld.sayHi");
return true;
}
void shutdown() noexcept override {} // tokens tear down automatically
private:
MTE::plugin::CommandToken m_cmd;
MTE::plugin::MenuToken m_menu;
};
2. Esporta la fabbrica (backend Qt nativo)¶
#include <PluginApi/Qt/PluginQtGlue.h>
class HelloWorldFactory : public QObject, public MTE::plugin::IPluginFactory {
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.mte.IPluginFactory/1" FILE "plugin.json")
Q_INTERFACES(MTE::plugin::IPluginFactory)
public:
std::unique_ptr<MTE::plugin::IPlugin> create() override {
return std::make_unique<HelloWorldPlugin>();
}
};
3. Descrivilo in plugin.json¶
{
"id": "org.mte.helloworld",
"name": "Hello World",
"version": "1.0.0",
"apiVersion": 1,
"entry": "native",
"requires": [],
"order": 600,
"menus": [
{ "title": "Plugins", "barPriority": 570, "itemPriority": 100 }
]
}
L'apiVersion qui e quella restituita da info() devono essere entrambe
uguali a MTE_PLUGIN_API_VERSION, altrimenti l'host rifiuta di caricare il
plugin.
La accompagnano due chiavi facoltative:
apiMinorVersion(predefinito0) — la versione minor minima dell'API dell'host di cui il tuo plugin ha bisogno. Un host la cuiMTE_PLUGIN_API_MINOR_VERSIONè inferiore elenca il plugin con «Richiede una versione più recente di OctoEdit» e non lo carica. L'host controlla questo valore del manifesto prima di caricare qualsiasi cosa, e poi di nuovoPluginInfo::apiMinorVersionrestituito dainfo(): quest'ultimo vale per impostazione predefinita la minor degli header con cui hai compilato, quindi non toccarlo a meno che tu non sappia di non usare nulla di più recente. Vedi Versionamento.requires(predefinito[]) — gli id dei plugin senza i quali il tuo plugin non può funzionare, per esempio["org.mte.lsp"]. Solo id: non c'è un intervallo di versioni né una forma facoltativa — un plugin con cui il tuo funziona semplicemente meglio non va qui; dialoga con lui in fase di esecuzione tramite eventi e registri di fornitori. L'editor inizializza le tue dipendenze prima di te, qualunque cosa dicaorder, e le arresta dopo di te. Se una di esse manca, è disattivata, richiede una licenza non attiva o non è stata caricata, il tuo plugin non viene caricato affatto, e Preferenze ▸ Estensioni dice di quale plugin ha bisogno e perché («Richiede l'estensione LSP Provider, che è disattivata»). Un ciclo blocca ogni plugin che ne fa parte. La stessa chiave ha lo stesso significato nelplugin.jsondi un plugin Python.
Attribuire le librerie incluse — thirdParty¶
Se il tuo plugin include o collega un componente di terze parti, dichiaralo in un
array facoltativo thirdParty, così che l'editor possa onorarne gli obblighi di
attribuzione:
"thirdParty": [
{ "name": "Qt WebEngine", "license": "LGPL-3.0",
"url": "https://doc.qt.io/qt-6/qtwebengine-index.html",
"file": "QtWebEngine-LGPLv3.txt" }
]
Ogni voce richiede un name (le voci che ne sono prive vengono scartate);
license, url e file sono facoltativi. I testi delle licenze appartengono
al tuo plugin: distribuiscili accanto al plugin sotto
Plugins/Licenses/<your-plugin-id>/, dove file è il solo nome del file. La
finestra Informazioni elenca i componenti thirdParty di ogni plugin
installato e indirizza gli utenti a quella cartella; il nucleo non porta mai con
sé i testi di terze parti di un plugin. (Il plugin incluso HtmlPreviewPlugin,
che incorpora QtWebEngine + Chromium, è l'esempio di riferimento.)
4. Compilalo¶
Usa l'ausilio CMake dell'SDK:
find_package(MTEPluginSDK REQUIRED)
mte_add_plugin(NAME HelloWorldPlugin
SOURCES Src/HelloWorldPlugin.cpp
# TRANSLATIONS Translations/HelloWorld_en.ts ...
)
Requisiti di compilazione¶
Un plugin nativo viene caricato nel processo dell'editor, quindi dev'essere compilato con una toolchain binariamente compatibile con la build dell'editor a cui è destinato. Questi sono i requisiti per la versione attuale (compilata con Qt 6.11.2):
| Windows | macOS | |
|---|---|---|
| Compilatore | Visual Studio 2022, toolset MSVC 14.44 o un 14.x più vecchio (VS 2015–2022 condividono un'unica ABI C++); va bene anche clang-cl. Le build MinGW / GCC non possono essere caricate. |
Apple clang da Xcode (Xcode 27, Apple clang 21.0.0); solo arm64 |
| Configurazione di compilazione | Release, runtime dinamico (/MD, il valore predefinito di CMake). Un plugin Debug viene rifiutato dal caricatore; un plugin con runtime statico (/MT) va in crash quando la memoria attraversa il confine del plugin |
Release; deployment target 14.4 (lo stesso dell'editor) |
| Qt | Qt 6.11, kit msvc2022_64. Un plugin compilato con una minor 6.x più vecchia si carica; uno compilato con una minor più recente potrebbe non caricarsi |
Qt 6.11, stessa architettura |
| Standard C++ | C++20 (le intestazioni dell'API usano std::span e i concept) |
C++20 |
| CMake | 3.16+ | 3.16+ |
| API per plugin | la MTE_PLUGIN_API_VERSION dell'SDK distribuito con la versione dell'editor a cui punti |
idem |
Due conseguenze che vale la pena conoscere su Windows:
- Il Visual C++ Redistributable installato sulla macchina dell'utente deve essere almeno recente quanto il più recente toolset MSVC usato dall'editor o da un qualsiasi plugin caricato. Compilare il tuo plugin con un toolset più recente di quello dell'editor alza quel requisito per i tuoi utenti; compilarlo con il toolset dell'editor o con uno più vecchio no.
- La versione del Windows SDK con cui compili non influisce sulla compatibilità con l'editor; decide soltanto quali API di Windows il tuo plugin può chiamare, e l'editor supporta Windows 10 1809 e successivi.
E su macOS:
- L'editor viene distribuito solo per arm64; un plugin solo
x86_64non può essere caricato (un binario universale va bene). Mantieni il deployment target a 14.4: un plugin compilato per un macOS minimo più recente viene rifiutato dal caricatore di sistema sui Mac più vecchi e, poiché il runtime è la libc++ del sistema operativo stesso, non si pone alcuna questione di redistributable. - Fai riferimento ai framework Qt tramite
@rpath, così che il plugin prenda le copie incluse dentroOctoEdit.app. I kit Qt i cui framework portano nomi di installazione assoluti (per esempio quelli di Homebrew) richiedonoinstall_name_toolsul plugin compilato prima della distribuzione; altrimenti il plugin cercherà Qt nel percorso della macchina di compilazione.
Niente di tutto ciò vale per i plugin Python: girano in un processo separato e non condividono alcuna interfaccia binaria con l'editor.
5. Installa ed esegui¶
Puoi comprimere la libreria compilata + plugin.json come <name>.mteplugin e
installarlo tramite Preferenze ▸ Estensioni ▸ Installa estensione... (il pacchetto viene
validato — manifest, sicurezza dell'archivio e metadati incorporati nel binario
— prima che venga toccato alcunché), oppure depositare i file a mano in una
cartella di plugin individuata (vedi
Panoramica dell'architettura). Riavvia l'editor e,
se serve, abilitalo in Preferenze ▸ Estensioni.
Prossimi passi¶
- Panoramica dell'API per plugin — ciclo di vita, token e la tabella completa dei servizi
- Comandi e menu
- Pannelli, schede e barra di stato
- Pagine delle impostazioni
- Eventi
- Traduzioni