Events reference¶
Every event the host publishes for native plugins (PluginEvents.h)
reaches Python too, with one exception noted below. Each topic delivers a
small typed dataclass to your handler. The dataclasses are defined in
Python/mte/events.py and are importable from the top-level mte
package.
Topic ↔ dataclass table¶
| Topic | Payload dataclass | Fields | Decorator |
|---|---|---|---|
document.opened |
mte.DocumentOpened |
document: int, path: str |
on_document_opened |
document.closed |
mte.DocumentClosed |
document: int |
on_document_closed |
document.saved |
mte.DocumentSaved |
document: int |
on_document_saved |
document.encodingChanged |
mte.DocumentEncodingChanged |
document: int, encoding: mte.DocumentEncoding |
on_document_encoding_changed |
document.lineEndingChanged |
mte.DocumentLineEndingChanged |
document: int, ending: mte.LineEnding |
on_document_line_ending_changed |
document.modifiedChanged |
mte.DocumentModifiedChanged |
document: int, modified: bool |
on_document_modified_changed |
document.activeChanged |
mte.ActiveDocumentChanged |
document: int |
on_active_document_changed |
text.changed |
mte.TextChanged |
document, position, added_bytes, removed_bytes |
on_text_changed |
selection.changed |
mte.SelectionChanged |
document: int |
on_selection_changed |
settings.changed |
mte.SettingsChanged |
scope: str ("" = editor-wide, "plugins/<id>") |
on_settings_changed |
theme.changed |
mte.ThemeChanged |
variant: str ("light" / "dark" / "") |
on_theme_changed |
margin.clicked |
mte.MarginClicked |
document: int, line: int, margin: str ("symbol"), modifiers: int (bits mte.MODIFIER_SHIFT / MODIFIER_CONTROL / MODIFIER_ALT / MODIFIER_META) — a click in the bookmark column, see ctx.line_markers |
on_margin_clicked |
workspace.rootChanged |
mte.WorkspaceRootChanged |
root: str ("" = folder closed) |
on_workspace_root_changed |
workspace.filesChanged |
mte.WorkspaceFilesChanged |
files: list[mte.WorkspaceFile] (path, display_path) |
on_workspace_files_changed |
command.shortcutChanged |
mte.CommandShortcutChanged |
command_id: str, sequence: str |
on_command_shortcut_changed |
host.windowShown |
mte.HostWindowShown |
(no fields) — once per run, after the first frame | on_host_window_shown |
app.aboutToQuit |
mte.AppAboutToQuit |
(no fields) | on_app_about_to_quit |
document is an opaque integer id assigned by the host. Compare ids
with ==; do not persist them across editor restarts. text.changed
fires on every edit — keep that handler trivial.
Subscribe via sugar decorator¶
Recommended — the decorator name matches the topic and the payload type is inferred:
import mte
def register(ctx):
@ctx.events.on_document_saved
def _saved(ev: mte.DocumentSaved):
ctx.log.info(f"saved doc {ev.document}")
@ctx.events.on_document_opened
def _opened(ev: mte.DocumentOpened):
ctx.log.info(f"opened {ev.document} at {ev.path}")
@ctx.events.on_app_about_to_quit
def _quit(_ev: mte.AppAboutToQuit):
ctx.log.info("editor is closing")
Subscribe via the raw API¶
def _saved(ev):
ctx.log.info(f"saved {ev.document}")
handler_id = ctx.events.subscribe("document.saved", _saved)
- Returns the locally-allocated
handler_id(a"py-ev/N"string). - Unknown topics raise
ValueErrorat subscribe time — no silent noop.
Unsubscribe when you no longer care:
Note: after unsubscribe the host stops delivering the topic to you,
but the worker's local dispatcher keeps its entry until the plugin
shuts down. Do not rely on unsubscribe for memory cleanup — it's a
policy signal, not a garbage-collection primitive.
Delivery semantics¶
- Events fire after the corresponding action has completed. On
document.saved, the file is already on disk. Ondocument.closed, the document id is already invalid. - Multiple subscribers to the same topic all fire, in undefined order.
- Exceptions raised in your handler are caught by the worker and
written to stderr (visible in the host's log as
[worker stderr] …). A misbehaving handler does not stop other subscribers from firing. - Payload dataclasses are immutable; do not mutate
evfields.
Publishing¶
ctx.events.publish(topic, payload) puts an event on the shared bus, where
native and Python subscribers alike receive it. Only the two topics that are
meant to be published by a plugin are accepted — the workspace pair, which
the Workspace plugin broadcasts for Find in Files and the Command Palette:
ctx.events.publish("workspace.rootChanged", {"root": "/home/me/project"})
ctx.events.publish("workspace.filesChanged", {"files": [
{"path": "/home/me/project/a.txt", "displayPath": "a.txt"},
]})
Any other topic raises ValueError: the rest are the host's own statements
of fact (a document was saved, the theme did change) that a plugin has no
business asserting. For plugin-to-plugin messaging beyond these, register a
command and have the other side invoke it.
Not available¶
Two host events have no Python topic:
document.aboutToSave: the host publishes it synchronously with the save blocked until every subscriber returns, and honouring that over the worker RPC needs the same deadline treatment as completion providers before it is safe. Native plugins can use it today.DocumentAboutToClose— native-only by design. Its whole promise is that the document can still be read inside the handler, and delivery to a Python plugin is asynchronous, so the handler would run after the close. Usedocument.closedinstead, and keep whatever you need about a document up to date from the earlier events rather than reading it at close time.