Přeskočit obsah

Psaní nativního zásuvného modulu

Minimální nativní zásuvný modul je jedna třída, jedno tovární makro, jeden soubor JSON a krátký CMakeLists.txt. Můžete jej napsat zcela mimo strom proti sadě Plugin SDK — checkout zdrojů MTE není potřeba.

Nativní, nebo Python?

Tato stránka pokrývá nativní moduly v C++ (přeložené do .dll/.so/.dylib a načítané zavaděčem Qt). Chcete-li raději dodat složku souborů .py, které editor spustí jako podproces, podívejte se na zásuvné moduly v Pythonu — tatáž plocha PluginApi, jiný backend, žádný překladač.

Koncept

Tento průvodce vychází z PLUGIN_ARCHITECTURE.md; přesný název balíčku SDK a argumenty mte_add_plugin() si před spoléháním na ně ověřte proti dodané sadě SDK.

1. Implementujte 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. Exportujte továrnu (nativní backend Qt)

#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. Popište jej v 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 }
  ]
}

Hodnota apiVersion zde i ta vracená z info() se musí obě rovnat MTE_PLUGIN_API_VERSION, jinak hostitel modul odmítne načíst.

K tomu patří dva volitelné klíče:

  • apiMinorVersion (výchozí 0) — nejnižší minor verze API hostitele, kterou váš modul potřebuje. Hostitel, jehož MTE_PLUGIN_API_MINOR_VERSION je nižší, zobrazí modul se stavem »Vyžaduje novější verzi aplikace OctoEdit« a nenačte ho. Hostitel tuto hodnotu z manifestu zkontroluje dřív, než cokoli načte, a potom ještě jednou PluginInfo::apiMinorVersion z info() — ta má ve výchozím stavu minor verzi hlaviček, proti kterým jste kompilovali, takže na ni nesahejte, pokud nevíte, že nepoužíváte nic novějšího. Viz Verzování.
  • requires (výchozí []) — ID modulů, bez kterých váš modul nemůže fungovat, například ["org.mte.lsp"]. Jen ID: neexistuje rozsah verzí ani volitelná forma — modul, se kterým váš jen funguje lépe, sem nepatří; komunikujte s ním za běhu přes události a registry poskytovatelů. Editor inicializuje vaše závislosti před vámi bez ohledu na order a ukončuje je po vás. Když některá z nich chybí, je vypnutá, vyžaduje licenci, která není aktivní, nebo se nenačetla, váš modul se vůbec nenačte a Předvolby ▸ Zásuvné moduly řeknou, který modul potřebuje a proč (»Vyžaduje zásuvný modul LSP Provider, který je vypnutý«). Cyklus zablokuje každý modul, který do něj patří. Stejný klíč znamená totéž v plugin.json modulu v Pythonu.

Uvedení dodávaných knihoven — thirdParty

Pokud váš modul přibaluje nebo linkuje komponentu třetí strany, deklarujte ji ve volitelném poli thirdParty, aby editor mohl dostát povinnostem uvádět autorství:

"thirdParty": [
  { "name": "Qt WebEngine", "license": "LGPL-3.0",
    "url": "https://doc.qt.io/qt-6/qtwebengine-index.html",
    "file": "QtWebEngine-LGPLv3.txt" }
]

Každá položka potřebuje name (položky bez něj se zahodí); license, url a file jsou volitelné. Texty licencí vlastní váš modul — dodejte je vedle modulu pod Plugins/Licenses/<your-plugin-id>/, kde file je název souboru. Okno O aplikaci vypisuje komponenty thirdParty každého nainstalovaného modulu a odkazuje uživatele na onu složku; jádro za modul jeho texty třetích stran nikdy nenese. (Referenčním příkladem je dodávaný HtmlPreviewPlugin, který vkládá QtWebEngine a Chromium.)

4. Sestavte jej

Použijte pomocníka CMake ze sady SDK:

find_package(MTEPluginSDK REQUIRED)
mte_add_plugin(NAME HelloWorldPlugin
    SOURCES Src/HelloWorldPlugin.cpp
    # TRANSLATIONS Translations/HelloWorld_en.ts ...
)

Požadavky na sestavení

Nativní zásuvný modul se načítá do procesu editoru, takže musí být sestaven sadou nástrojů binárně kompatibilní se sestavením editoru, na které míří. Toto jsou požadavky pro současné vydání (sestavené s Qt 6.11.2):

Windows macOS
Překladač Visual Studio 2022, sada nástrojů MSVC 14.44 nebo starší 14.x (VS 2015–2022 sdílejí jedno ABI pro C++); funguje i clang-cl. Sestavení pomocí MinGW či GCC se nenačte. Apple clang z Xcode (Xcode 27, Apple clang 21.0.0); pouze arm64
Konfigurace sestavení Release, dynamický runtime (/MD, výchozí v CMake). Modul v konfiguraci Debug zavaděč odmítne; modul se statickým runtimem (/MT) spadne, jakmile paměť překročí hranici modulu Release; cíl nasazení 14.4 (stejný jako u editoru)
Qt Qt 6.11, kit msvc2022_64. Modul sestavený proti starší podverzi 6.x se načte; sestavený proti novější podverzi se načíst nemusí Qt 6.11, tatáž architektura
Standard C++ C++20 (hlavičky rozhraní používají std::span a koncepty) C++20
CMake 3.16+ 3.16+
Rozhraní modulů hodnota MTE_PLUGIN_API_VERSION sady SDK dodané s verzí editoru, na kterou míříte totéž

Ve Windows stojí za to znát dva důsledky:

  • Visual C++ Redistributable nainstalovaný na stroji uživatele musí být alespoň tak nový jako nejnovější sada nástrojů MSVC použitá editorem nebo kterýmkoli načteným modulem. Sestavení vašeho modulu novější sadou nástrojů, než má editor, tento požadavek vašim uživatelům zvyšuje; sestavení sadou editoru nebo starší nikoli.
  • Verze Windows SDK, proti které překládáte, kompatibilitu s editorem neovlivňuje; rozhoduje pouze o tom, která rozhraní Windows může váš modul volat, a editor podporuje Windows 10 1809 a novější.

A na macOS:

  • Editor se dodává pouze jako arm64; modul jen pro x86_64 se načíst nemůže (univerzální binárka je v pořádku). Držte cíl nasazení na 14.4: modul sestavený pro novější minimální macOS odmítne na starších Macích systémový zavaděč, a runtimem je vlastní libc++ operačního systému, takže otázka redistribuovatelného balíčku vůbec nevzniká.
  • Na frameworky Qt se odkazujte přes @rpath, aby modul převzal kopie zabalené uvnitř OctoEdit.app. Kity Qt, jejichž frameworky nesou absolutní instalační názvy (například ty z Homebrew), vyžadují před dodáním install_name_tool na sestaveném modulu; jinak modul hledá Qt v cestě sestavovacího stroje.

Na moduly v Pythonu se nic z toho nevztahuje: běží v samostatném procesu a s editorem nesdílejí žádné binární rozhraní.

5. Nainstalujte a spusťte

Buď sestavenou knihovnu a plugin.json zabalte do zipu jako <name>.mteplugin a nainstalujte přes Předvolby ▸ Zásuvné moduly ▸ Instalovat zásuvný modul... (balíček se ověří — manifest, bezpečnost archivu i vložená metadata binárky — dřív, než se čehokoli dotkne), nebo soubory ručně vložte do některého prohledávaného adresáře modulů (viz Přehled architektury). Restartujte editor; v případě potřeby jej zapněte v Předvolby ▸ Zásuvné moduly.

Dále