Pisanie wtyczki natywnej¶
Minimalna wtyczka natywna to jedna klasa, jedno makro fabryki, jeden plik JSON
i krótki CMakeLists.txt. Możesz ją napisać w całości poza drzewem źródeł,
w oparciu o Plugin SDK — bez checkoutu źródeł MTE.
Natywna czy Python?
Ta strona opisuje wtyczki natywne C++ (kompilowane do .dll/.so/.dylib
i ładowane przez loader Qt). Jeśli wolisz dostarczyć folder plików .py,
które edytor uruchamia jako podproces, zobacz
Wtyczki w Pythonie — ta sama powierzchnia
PluginApi, inny backend, kompilator niepotrzebny.
Wersja robocza
Ten przewodnik opiera się na PLUGIN_ARCHITECTURE.md; przed poleganiem na
nich zweryfikuj dokładną nazwę pakietu SDK oraz argumenty mte_add_plugin()
względem dostarczonego SDK.
1. Zaimplementuj 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. Wyeksportuj fabrykę (natywny 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. Opisz ją w 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 }
]
}
Zarówno tutejszy apiVersion, jak i ten zwracany przez info() muszą być
równe MTE_PLUGIN_API_VERSION, inaczej host odmówi załadowania wtyczki.
Towarzyszą mu dwa opcjonalne klucze:
apiMinorVersion(domyślnie0) — najniższa wersja minor API hosta, jakiej potrzebuje Twoja wtyczka. Host, któregoMTE_PLUGIN_API_MINOR_VERSIONjest niższe, wyświetla wtyczkę z komunikatem „Wymaga nowszej wersji OctoEdit" i jej nie ładuje. Host sprawdza tę wartość z manifestu, zanim cokolwiek załaduje, a potem jeszcze razPluginInfo::apiMinorVersionzinfo()— ta domyślnie równa się minor nagłówków, z którymi kompilowałeś, więc nie zmieniaj jej, chyba że wiesz, że nie używasz niczego nowszego. Zobacz Wersjonowanie.requires(domyślnie[]) — identyfikatory wtyczek, bez których Twoja wtyczka nie może działać, na przykład["org.mte.lsp"]. Tylko identyfikatory: nie ma zakresu wersji ani formy opcjonalnej — wtyczka, z którą po prostu działasz lepiej, tu nie trafia; rozmawiaj z nią w czasie działania przez zdarzenia i rejestry providerów. Edytor inicjalizuje Twoje zależności przed Tobą, niezależnie odorder, i zamyka je po Tobie. Gdy któraś z nich jest nieobecna, wyłączona, wymaga nieaktywnej licencji albo się nie załadowała, Twoja wtyczka w ogóle nie jest ładowana, a Preferencje ▸ Wtyczki mówią, której wtyczki potrzebuje i dlaczego („Wymaga wtyczki LSP Provider, która jest wyłączona"). Cykl blokuje każdą wtyczkę, która do niego należy. Ten sam klucz znaczy to samo wplugin.jsonwtyczki w Pythonie.
Uznanie dołączonych bibliotek — thirdParty¶
Jeśli Twoja wtyczka dołącza lub linkuje komponent zewnętrzny, zadeklaruj go w
opcjonalnej tablicy thirdParty, aby edytor mógł wypełnić obowiązki
atrybucyjne:
"thirdParty": [
{ "name": "Qt WebEngine", "license": "LGPL-3.0",
"url": "https://doc.qt.io/qt-6/qtwebengine-index.html",
"file": "QtWebEngine-LGPLv3.txt" }
]
Każdy wpis wymaga pola name (wpisy bez niego są pomijane); license, url
i file są opcjonalne. Teksty licencji należą do Twojej wtyczki — dostarcz
je obok wtyczki w Plugins/Licenses/<your-plugin-id>/, gdzie file to nazwa
pliku. Okno O programie wyświetla komponenty thirdParty każdej
zainstalowanej wtyczki i kieruje użytkowników do tego folderu; rdzeń edytora
nigdy nie przechowuje tekstów licencji zewnętrznych za wtyczkę. (Dołączony
HtmlPreviewPlugin, który osadza QtWebEngine + Chromium, jest przykładem
referencyjnym.)
4. Zbuduj ją¶
Użyj helpera CMake z SDK:
find_package(MTEPluginSDK REQUIRED)
mte_add_plugin(NAME HelloWorldPlugin
SOURCES Src/HelloWorldPlugin.cpp
# TRANSLATIONS Translations/HelloWorld_en.ts ...
)
Wymagania do kompilacji¶
Wtyczka natywna jest ładowana do procesu edytora, więc musi być zbudowana toolchainem zgodnym binarnie z buildem edytora, dla którego jest przeznaczona. Poniżej wymagania dla bieżącego wydania (zbudowanego z Qt 6.11.2):
| Windows | macOS | |
|---|---|---|
| Kompilator | Visual Studio 2022, toolset MSVC 14.44 lub starszy 14.x (VS 2015–2022 dzielą jedno ABI C++); działa też clang-cl. Wtyczek z MinGW / GCC nie da się załadować. |
Apple clang z Xcode (Xcode 27, Apple clang 21.0.0); tylko arm64 |
| Konfiguracja | Release, dynamiczny runtime (/MD, domyślne ustawienie CMake). Wtyczkę Debug loader odrzuca; wtyczka ze statycznym runtime (/MT) powoduje awarię, gdy pamięć przekracza granicę wtyczki |
Release; deployment target 14.4 (jak edytor) |
| Qt | Qt 6.11, zestaw msvc2022_64. Wtyczka zbudowana ze starszym wydaniem 6.x ładuje się; zbudowana z nowszym może się nie załadować |
Qt 6.11, ta sama architektura |
| Standard C++ | C++20 (nagłówki API używają std::span i konceptów) |
C++20 |
| CMake | 3.16+ | 3.16+ |
| API wtyczek | MTE_PLUGIN_API_VERSION z SDK dostarczonego z docelową wersją edytora |
jak obok |
Dwie konsekwencje na Windows, o których warto wiedzieć:
- Visual C++ Redistributable na maszynie użytkownika musi być co najmniej tak nowy jak najnowszy toolset MSVC użyty przez edytor lub dowolną załadowaną wtyczkę. Budowanie wtyczki toolsetem nowszym niż edytor podnosi to wymaganie dla Twoich użytkowników; budowanie toolsetem edytora lub starszym nie.
- Wersja Windows SDK użyta do kompilacji nie wpływa na zgodność z edytorem; decyduje tylko o tym, które API Windows wtyczka może wywołać, a edytor obsługuje Windows 10 1809 i nowsze.
A na macOS:
- Edytor jest dostarczany wyłącznie jako arm64; wtyczka tylko
x86_64nie załaduje się (binarka uniwersalna jest w porządku). Zostaw deployment target 14.4: wtyczkę zbudowaną dla nowszego minimalnego macOS systemowy loader odrzuci na starszych Macach, a runtime'em jest systemowa libc++, więc kwestia redistributable nie występuje. - Odwołuj się do frameworków Qt przez
@rpath, żeby wtyczka użyła kopii dołączonych wOctoEdit.app. Zestawy Qt, których frameworki mają bezwzględne nazwy instalacyjne (np. z Homebrew), wymagająinstall_name_toolna zbudowanej wtyczce przed wysyłką; inaczej wtyczka szuka Qt pod ścieżką z maszyny budującej.
Nic z tego nie dotyczy wtyczek w Pythonie: działają w osobnym procesie i nie dzielą z edytorem żadnego interfejsu binarnego.
5. Zainstaluj i uruchom¶
Spakuj zbudowaną bibliotekę + plugin.json do archiwum <name>.mteplugin i
zainstaluj przez Preferencje ▸ Wtyczki ▸ Zainstaluj wtyczkę... (pakiet jest
walidowany — manifest, bezpieczeństwo archiwum oraz metadane osadzone w
binarium — zanim cokolwiek zostanie zmienione), albo wrzuć pliki ręcznie do
jednego z wykrywanych katalogów wtyczek (zobacz
Przegląd architektury). Uruchom edytor ponownie;
w razie potrzeby włącz wtyczkę w Preferencje ▸ Wtyczki.
Dalsze kroki¶
- Przegląd API wtyczek — cykl życia, tokeny i pełna tabela usług
- Polecenia i menu
- Doki, karty i pasek stanu
- Strony ustawień
- Zdarzenia
- Tłumaczenia