Skip to content

Settings & settings pages

Three related services cover configuration: ISettings (persistent key/value storage), IDocumentSettings (.editorconfig-layered reads), and ISettingsRegistry (a UI page in the Preferences dialog).

ISettings — persistent key/value config

ctx.settings() returns a store scoped to your plugin: the host roots it under plugins/<plugin.id>/, so short local key names never collide with the editor or other plugins. Keys use / as a path separator ("ui/fontSize").

class ISettings {
public:
    bool contains(std::string_view key) const;
    void remove(std::string_view key);

    // Typed accessors -- defaultValue is returned when the key is missing
    // or the stored value cannot convert to the requested type.
    bool         getBool  (std::string_view key, bool defaultValue = false) const;
    std::int64_t getInt   (std::string_view key, std::int64_t defaultValue = 0) const;
    double       getDouble(std::string_view key, double defaultValue = 0.0) const;
    std::string  getString(std::string_view key, std::string_view defaultValue = {}) const;
    std::vector<std::uint8_t> getBytes(std::string_view key) const;

    void setBool / setInt / setDouble / setString / setBytes(...);

    void sync();   // flush now; the host also syncs on shutdown
};
ctx.settings().setBool("wrap", true);
bool wrap = ctx.settings().getBool("wrap", false);

The default implementation is QSettings-backed (INI), but that is an implementation detail — the interface is Qt-free and a Python plugin uses the same store through ctx.settings.

App-wide settings (read-only)

ctx.appSettings() is a const view of the editor's own configuration. Use the key constants from PluginApi/AppSettingsKeys.h rather than hard-coding strings. To react to changes, subscribe to events::SettingsChanged (an empty scope means "anything changed").

Document-scoped settings (.editorconfig)

ctx.documentSettings() reads per-document values that layer a project's .editorconfig over your stored settings: for a key k it resolves mte.<plugin.id>.<k> from the .editorconfig sections applying to the document's path, falls back to ctx.settings(), then to your default. Writes always go through ctx.settings() — never back into .editorconfig.

A page in the Preferences dialog

The page interface is Qt-aware, so it lives in the opt-in header PluginApi/Qt/ISettingsPage.h:

class ISettingsPage {
public:
    std::string category() const;              // tree path, e.g. "Plugins/Hello World"
    std::string title() const;                 // page heading
    QWidget*    createWidget(QWidget* parent); // built lazily, at most once per dialog
    void        apply();                       // OK/Apply -> write widget state to ISettings
    void        reset();                       // Cancel/re-show -> reload from ISettings (optional)
    std::string scope() const;                 // published via events::SettingsChanged (optional)
};

Register it in initialize() and keep the token:

m_page = ctx.settingsRegistry().registerPage(
    std::make_unique<MySettingsPage>(ctx.settings()));
  • category() groups pages in the dialog's tree; intermediate segments create or reuse groups. Plugin pages conventionally live under "Plugins/<Name>".
  • apply() is where you persist; reset() is where you reload after a cancel. Don't write settings from widget signals — the dialog contract is deferred apply.
  • By convention scope() returns "plugins/<plugin.id>" so other code can react selectively to your page's changes via events::SettingsChanged.
  • The returned SettingsPageToken revokes the page (and frees it) on destruction — reset() it in shutdown() like every other token.

Localise every string on the page and ship all four catalogs — see Translations.

Python plugins

A Python plugin declares the equivalent page declaratively — a JSON form built with mte.ui passed to ctx.settings_page.register(...); values bound with binds="settings:<key>" persist to the same per-plugin store. See the Python ctx reference.