ctx — de plug-incontext¶
register(ctx) ontvangt één argument: een PluginContext. Dat stelt de diensten
hieronder beschikbaar (het hele vlak van IPluginContext dat in het model buiten
het proces past). Elk ervan is een kleine Python-klasse die de worker boven op het
RPC-kanaal bouwt; de broncode staat in Python/mte/.
def register(ctx):
ctx.commands # register/invoke commands
ctx.menus # add menu items & separators
ctx.events # subscribe to editor events
ctx.log # write to the host's diagnostics stream
ctx.status # post transient status-bar messages
ctx.editor # buffer / caret / selection / files / search / bookmarks / groups
ctx.languages # list languages, read / switch a document's language, contribute one
ctx.settings # per-plugin key/value store
ctx.app_settings # editor-wide read-only settings view (keys: mte.keys)
ctx.document_settings # .editorconfig-layered per-document reads
ctx.theme # themeable colour categories for your own UI
ctx.diagnostics # publish squiggles + margin glyphs
ctx.compare # open the side-by-side compare view
ctx.completions # register auto-completion providers
ctx.docks # declarative dock panels (+ set_panel_visible, is_panel_visible)
ctx.line_markers # margin glyphs / line tints that follow edits; the margin-click claim
ctx.settings_page # declarative Preferences pages
ctx.ui # runtime get/set for panel controls
Twee delen van het native contract hebben nog geen Python-tegenhanger: hover-leveranciers (de prioriteitsbanden van hover gelden dus niet voor Python-plug-ins) en leveranciers voor het contextmenu van de editor (het onderscheid tekst / marge in het contextmenu dus ook niet). Beide worden beantwoord terwijl de gebruiker wacht, en dat vergt dezelfde behandeling met een deadline die aanvullingsleveranciers hebben voordat een retour naar de worker veilig is.
Bewaar ctx niet in een globale variabele in de verwachting hem later te
gebruiken — hoewel de attributen stabiel zijn zolang de plug-in leeft, behandelt u
ctx als gebonden aan één registratie. Houd verwijzingen naar de afzonderlijke
diensten vast wanneer u ze nodig hebt (bijvoorbeeld log = ctx.log).
commands¶
Decorator die een opdracht registreert en de omhulde aanroepbare eraan koppelt als afhandelaar.
id(str, verplicht): unieke aanduiding in omgekeerde DNS-stijl (bijvoorbeeld"wordcount.count"). Dezelfde regels als inplugin.json— moet wereldwijd uniek zijn.title(str, verplicht): leesbaar label dat overal getoond wordt waar de opdracht opduikt (menu's, opdrachtenpalet).shortcut(str, optioneel): draagbare standaardsneltoetstekenreeks, bijvoorbeeld"Ctrl+Alt+W".Ctrlwordt automatisch aan de primaire modificatietoets van het platform gekoppeld (Cmdop macOS). Laat leeg voor geen. De gebruiker kan hem in Voorkeuren ▸ Sneltoetsen opnieuw toewijzen of loskoppelen; voor menu-gebonden opdrachten past de host de nieuwe toewijzing voor u toe.category(str, optioneel): vrij groeperingslabel — getoond als de categorie van de opdracht in de sneltoetstoewijzing.scope(str, optioneel):""/"application"(standaard — de host koppelt de sneltoets aan de menu-actie van de opdracht) of"pluginWindow"voor combinaties die in een interface wonen die de plug-in bezit: de host somt de opdracht alleen in de toewijzing op; leesctx.commands.effective_shortcut(id)terwijl u uw widgets bouwt en pas hem opnieuw toe bij de gebeurtenis"command.shortcutChanged".
De sneltoets die op dit moment geldt na het opnieuw toewijzen door de gebruiker en
het oplossen van conflicten ("" = losgekoppeld of onbekend). Veilig aan te
roepen vanuit afhandelaars.
De omhulde functie neemt geen argumenten en levert niets op. Uitzonderingen erin worden door de worker opgevangen en naar stderr genoteerd; ze laten de editor niet crashen.
@ctx.commands.command(id="wordcount.count",
title="Count Words",
shortcut="Ctrl+Alt+W",
category="Text")
def _count():
ctx.status.show("counted")
Onder de motorkap: de Python-kant kent lokaal een handlerId toe, registreert de
callback op de RPC-verbinding, en vuurt commands.registerCommand op de host af.
Wanneer de gebruiker de opdracht in gang zet (menuklik, sneltoets, palet) stuurt de
host een RPC callback en draait uw functie.
Opdracht-id's gelden voor het hele proces, niet per plug-in. Zet uw
omgekeerde DNS-naamruimte voor uw id's (wordcount.…) om botsingen te vermijden.
menus¶
Menupaden gebruiken / als scheiding. Het meest linkse segment is een menu van het
hoogste niveau (Plugins, Tools, …); tussenliggende segmenten maken submenu's
op verzoek; het laatste segment is het label van het item.
ctx.menus.add_item(path, command_id)¶
path(str):"Top/Sub/…/Label". Tussenliggende submenu's worden gemaakt wanneer ze niet bestaan.command_id(str): id van een eerder geregistreerde opdracht. Het item aanklikken roept de opdracht aan.
Levert een ondoorzichtige tekenreeks handlerId op. Houd die vast wanneer u het
item later moet uitschrijven met unsubscribe (zeldzaam in fase 1).
Het meest linkse segment ("Plugins" hierboven) moet overeenkomen met de title
van een van uw items in menus[] in plugin.json, zodat de plaats op de menubalk
opgepikt wordt.
ctx.menus.add_separator(path)¶
Voegt een scheiding in een bestaand submenu in.
ctx.menus.set_item_checked(handler_id, checked)¶
Maakt van het eerder toegevoegde item een aanvinkbaar menu-item en zet de aangevinkte staat ervan — het standaardpatroon voor een blijvende aan/uit-schakelaar die een zichtbaar vinkje toont.
item = ctx.menus.add_item("View/Auto-open Preview",
"myplugin.toggleAutoOpen")
# Seed the check mark from the persisted setting so it matches
# reality before the user opens the menu.
ctx.menus.set_item_checked(item, ctx.settings.get("autoOpen", True))
@ctx.commands.command(id="myplugin.toggleAutoOpen",
title="Toggle Auto-Open")
def _toggle():
on = not ctx.settings.get("autoOpen", True)
ctx.settings.set("autoOpen", on)
ctx.menus.set_item_checked(item, on)
De eerste aanroep maakt het item aanvinkbaar; latere aanroepen kantelen alleen het
vinkje. Een handler_id meegeven die de host niet kent is een stille
niet-bewerking (veilig aan te roepen nadat uw token losgelaten is, bijvoorbeeld
vanuit een vertraagde callback die tijdens het afsluiten afgaat).
ctx.menus.set_item_enabled(handler_id, enabled)¶
Schakelt een eerder toegevoegd item in of maakt het grijs. Gebruik het wanneer de opdracht een voorwaarde nodig heeft — iets om te sluiten, iets om te herstellen — zodat het menu toont dat het niet beschikbaar is in plaats van een item aan te bieden dat stilletjes niets doet.
item = ctx.menus.add_item("File/Close Thing", "myplugin.closeThing")
# Nothing to close yet:
ctx.menus.set_item_enabled(item, False)
# ... and from every place that changes the state the command needs:
ctx.menus.set_item_enabled(item, thing_is_open)
Een uitgeschakeld item blijft zichtbaar maar kan niet in gang gezet worden, niet
met een klik en niet met zijn sneltoets. De aanroep is idempotent, zodat u de
vorige staat nooit hoeft te onthouden, en een onbekende handler_id is een stille
niet-bewerking zoals hierboven. Items beginnen ingeschakeld: één aanroep vlak na
add_item zet een item klaar dat bij het starten niet beschikbaar is.
events¶
Schrijf u in op editorgebeurtenissen. Twee gelijkwaardige API's — de zoete
decorators zijn aanbevolen; de kale subscribe() is beschikbaar wanneer u het
onderwerp tijdens het draaien wilt berekenen.
Zoete decorators¶
@ctx.events.on_document_saved
def _saved(ev):
ctx.log.info(f"saved doc {ev.document}")
@ctx.events.on_document_opened
def _opened(ev):
ctx.log.info(f"opened {ev.path}")
De omhulde functie neemt één argument: een getypeerde dataclass die bij het onderwerp hoort. Zie de Naslag voor gebeurtenissen voor de volledige tabel onderwerp ↔ dataclass.
Kale API¶
handler_id = ctx.events.subscribe("document.saved", _saved)
# later:
ctx.events.unsubscribe(handler_id)
Beschikbare zoete eigenschappen (allemaal decorators):
| Eigenschap | Gaat af bij |
|---|---|
on_document_opened |
Document in een tabblad geopend |
on_document_closed |
Document gesloten |
on_document_saved |
Document naar de schijf geschreven |
on_selection_changed |
Cursor / selectie verplaatst in het actieve document |
on_active_document_changed |
Voorgrondtabblad gewijzigd |
on_document_modified_changed |
De vlag schoon/vuil is gekanteld (modified: bool) |
on_text_changed |
Elke bewerking (position, added_bytes, removed_bytes) — houd het triviaal |
on_settings_changed |
Voorkeuren toegepast (scope: "" hele editor, "plugins/<id>") |
on_theme_changed |
Thema gewisseld of bewerkt (variant) — lees de kleuren van ctx.theme opnieuw |
on_workspace_root_changed |
Werkruimtemap geopend / gesloten (root) |
on_workspace_files_changed |
Verzameling werkruimtebestanden gewijzigd (files) |
on_host_window_shown |
Eén keer per uitvoering, na het eerste beeld — plan hier traag opstartwerk |
on_app_about_to_quit |
De editor sluit — de laatste kans om iets te doen |
on_command_shortcut_changed |
De effectieve sneltoets van een opdracht is gewijzigd (opnieuw toewijzen door de gebruiker / toetsindeling importeren / conflict opgelost); inhoud: command_id, sequence ("" = losgekoppeld) |
Onbekende onderwerpnamen werpen bij het inschrijven een ValueError.
Inschrijvers kunnen na de bijbehorende inheemse afhandelaar draaien; behandel
het afleveren van gebeurtenissen als informatief, niet als gezaghebbend.
Publiceren¶
ctx.events.publish(topic, payload) zendt gelijkelijk naar inheemse en
Python-inschrijvers uit — alleen aanvaard voor de twee onderwerpen van de
werkruimte (workspace.rootChanged, workspace.filesChanged); al het andere
werpt een ValueError. Zie de
Naslag voor gebeurtenissen.
log¶
ctx.log.trace ("very-fine-grained")
ctx.log.debug ("dev-only detail")
ctx.log.info ("routine event")
ctx.log.warning("recoverable weirdness")
ctx.log.error ("something is wrong")
Elk niveau komt overeen met de ILogger van de host. Regels krijgen het
voorvoegsel [python:<plugin.id>], zodat uw uitvoer in het diagnostieklogboek
van de editor terug te vinden is:
Gebruik nooit print() vanuit een plug-in — de stdout van de worker is het
RPC-kanaal, en erin schrijven bederft het protocol. ctx.log.* is de enige
toegestane manier om diagnostische tekst uit te zenden.
status¶
Plaats een vluchtige melding op de statusbalk.
message(str): wat er getoond wordt. Alleen korte teksten — de statusbalk heeft een vaste breedte.timeout_ms(int, standaard 0): hoe lang hij op het scherm blijft;0laat de host een verstandige standaard kiezen (een paar seconden).level(str, standaard"info"):"info"/"warning"/"error". Hogere niveaus kunnen het minimum op het scherm iets langer vasthouden, zodat een fout niet meteen door een routinematig informatiebericht weggevaagd wordt.
ctx.status.show is afvuren-en-vergeten. Heeft de host geen zichtbare statusbalk
(een build zonder scherm of een minimale build), dan wordt de aanroep in stilte
verworpen. ctx.status.clear() wist welke vluchtige melding er ook op het scherm
staat.
Blijvende segmenten¶
Voor levende staat (een woordentelling, de status van een server) gebruikt u een segment dat u bezit en ververst — het overschrijft nooit een melding, en omgekeerd:
seg = ctx.status.add_segment("wordcount.total", priority=100)
seg.set_text("2,431 words")
seg.set_visible(False) # hide without giving it up
seg.remove() # take it off the bar (idempotent)
priority ordent de segmenten van plug-ins van links naar rechts (lager = verder
naar links; bij gelijke stand blijft de registratievolgorde). Het afsluiten van een
plug-in verwijdert alles wat nog vastgehouden wordt.
editor¶
Volledige synchrone toegang tot de actieve documenten. Elke methode blokkeert de
aanroepende thread totdat de host antwoordt (doorgaans microseconden wanneer de
worker en de editor dezelfde machine delen). Toegestaan vanuit elke afhandelaar van
een opdracht of een gebeurtenis; nooit vanuit een callback met async def (zie
de notitie over threads boven aan deze pagina).
Documenten opsommen¶
doc = ctx.editor.active_document() # 0 when no document is open
docs = ctx.editor.open_documents() # list[int]
ctx.editor.set_active_document(doc)
path = ctx.editor.file_path(doc) # str or None for untitled
Toegang tot de buffer¶
text = ctx.editor.text(doc) # whole buffer
slice = ctx.editor.text_range(doc, start, end) # [start, end) bytes
n = ctx.editor.length(doc) # int64
ctx.editor.set_text(doc, "...")
text_range vermijdt dat de hele buffer door de RPC getrokken wordt wanneer u
maar een stuk nodig hebt — geef er de voorkeur aan bij sorteren en transformeren
van grote bestanden.
Selectie¶
sel = ctx.editor.selection_range(doc) # mte.MatchRange(start, end)
s = ctx.editor.selected_text(doc)
ctx.editor.replace_selection(doc, "new text")
ctx.editor.set_selection(doc, mte.MatchRange(4, 9))
ranges = ctx.editor.selection_ranges(doc) # list[MatchRange]: one per caret
block = ctx.editor.is_rectangular_selection(doc) # Alt+drag column block?
Cursor¶
pos = ctx.editor.caret(doc) # mte.EditorPosition(line, column)
ctx.editor.set_caret(doc, mte.EditorPosition(line=7, column=3))
Bestandsbewerkingen¶
new_doc = ctx.editor.open_file("/path/to/file") # doc-id or 0 on failure
here = ctx.editor.open_file_at("/path/to/file", mte.EditorPosition(41, 0))
ctx.editor.reveal_line(doc, 120) # scroll there; caret and focus stay
ok = ctx.editor.save_document(doc)
closed = ctx.editor.close_document(doc) # prompts if modified; False = user cancelled
dirty = ctx.editor.is_modified(doc)
ctx.editor.set_modified(doc, True) # force the tab asterisk
ro = ctx.editor.is_read_only(doc) # e.g. Monitoring (tail -f) mode
enc = ctx.editor.document_encoding(doc) # mte.DocumentEncoding, e.g. UTF8_BOM
ctx.editor.set_document_encoding(doc, mte.DocumentEncoding.UTF8) # takes effect on the next save
eol = ctx.editor.line_ending(doc) # mte.LineEnding, e.g. CRLF
ctx.editor.set_line_ending(doc, mte.LineEnding.LF) # Enter inserts it; the next save writes it
scratch = ctx.editor.create_untitled("text", "Untitled-3") # new buffer, doc-id
sid = ctx.editor.stable_id(doc) # survives Save As; compare with ==
clip = ctx.editor.clipboard_text() # system clipboard, "" if no text
# Declare that you snapshot unsaved buffers (the host then stops asking
# "save changes?" when the window closes):
ctx.editor.set_unsaved_changes_preserved(True)
ctx.editor.unsaved_changes_preserved() # bool, global flag
open_file_at is de ene aanroep voor «breng de gebruiker daarheen» (een
bouwfout, een stackframe, een zoekresultaat): hij opent het bestand of
activeert het tabblad ervan, zet de cursor zonder selectie, klapt een vouw
open die de regel verbergt, scrolt de regel in beeld — gecentreerd als hij
buiten beeld stond — en geeft de editor de focus. Regel en kolom beginnen bij
0 (de kolom in UTF-8-bytes) en worden begrensd, nooit geweigerd; hij geeft de
document-id terug, of 0 als het bestand niet geopend kon worden, en dan is er
niets verschoven. reveal_line toont alleen een regel: hij verplaatst de
cursor niet, wisselt niet van tabblad en neemt de focus niet.
Bladwijzers, markeringen, URL-markering¶
ctx.editor.toggle_bookmark(doc, line) # 0-based line
lines = ctx.editor.bookmarked_lines(doc) # list[int]
nxt = ctx.editor.next_bookmark(doc, from_line, wrap=True) # -1 = none
prv = ctx.editor.previous_bookmark(doc, from_line, wrap=True)
ctx.editor.clear_bookmarks(doc)
ctx.editor.mark_range(doc, mte.MatchRange(4, 9)) # "mark" indicator
ctx.editor.clear_marks(doc)
ctx.editor.set_url_highlight_enabled(doc, True)
ctx.editor.is_url_highlight_enabled(doc)
url = ctx.editor.url_at_caret(doc) # "" when none
ctx.editor.open_url_at_caret(doc) # bool
Zoeken¶
opts = mte.SearchOptions(match_case=True, mode="regex")
hit = ctx.editor.find_in_range(doc, r"TODO\(.*\)", 0,
ctx.editor.length(doc), opts)
if hit.valid:
new_end = ctx.editor.replace_target(doc, hit, "DONE()", opts)
SearchOptions.mode: "normal" / "extended" / "regex".
SearchOptions.direction: "forward" / "backward". Zie mte.SearchOptions
voor de volledige veldenlijst.
Incrementeel zoeken (het patroon groeit terwijl de gebruiker typt, vanaf een vastgezet anker):
ctx.editor.set_incremental_search_anchor(doc)
hit = ctx.editor.incremental_search(doc, "TOD", opts) # MatchRange
Inspringing en syntaxis¶
style = ctx.editor.indentation(doc) # IndentationStyle(use_tabs, width)
ctx.editor.set_indentation(doc,
mte.IndentationStyle(use_tabs=False, width=2))
# Where word-wrapped continuation rows start:
# "left" (window edge) / "same" (align with the line; default) / "indent"
ctx.editor.set_wrap_indent(doc, "same")
mode = ctx.editor.wrap_indent(doc) # same strings back
lang = ctx.editor.colorizer_id(doc) # e.g. "python", "" if none
# Semantic classification from the active colorizer (cheap, no re-lex):
# list[mte.CategorySpan(start, length, category)] with category names
# "comment" / "string" / "keyword" / ... -- a spell checker keeps to
# comments and strings this way.
spans = ctx.editor.text_categories(doc, 0, ctx.editor.length(doc))
ctx.editor.trigger_completion(doc) # pop the list as if Ctrl+Space
Gesplitste weergave / tabbladgroepen¶
n = ctx.editor.group_count() # >= 1
g = ctx.editor.group_of(doc) # -1 if not open
w = ctx.editor.group_weights() # relative widths
ctx.editor.move_document_to_group(doc, 1) # creates trailing groups on demand
ctx.editor.set_group_weights([2, 1])
ctx.editor.set_document_tab_index(doc, 0) # reorder within its pane
gs = ctx.editor.groups_of(doc) # EVERY pane showing it
ctx.editor.show_document_in_group(doc, 1) # split it into pane 1
Een document dat in twee deelvensters getoond wordt is één document met één
id, dus group_of() kan maar een van zijn plekken noemen. groups_of() meldt ze
allemaal, en show_document_in_group() maakt een tweede gedeelde weergave —
hetzelfde wat Beeld > Document rechts splitsen doet, dus er wordt geen
gebeurtenis document_opened opgeworpen.
ctx.editor spiegelt de inheemse IEditorService inmiddels één op één.
languages¶
Syntaxiskleuring is een functie van de kern — de host herkent de taal van een
document en kleurt het zonder enige plug-in. ctx.languages laat u meedoen: somt
op wat de host kent, leest of overschrijft de taal van een document, voert de
herkenning opnieuw uit, en draagt hele taaldefinities bij.
for lang in ctx.languages.available(): # list[mte.LanguageInfo(id, name)]
...
lang_id = ctx.languages.language_for(doc) # "" when uncoloured
ok = ctx.languages.set_language_for(doc, "json") # "" clears; False = unknown
ctx.languages.auto_detect_for(doc) # undo a manual override
handler = ctx.languages.register(
id="mylang", name="My Language", lexer="cpp",
extensions=["mylang", "ml2"],
keywords=[{"group": "Primary keywords and identifiers",
"words": "if else while"}],
styles={"SCE_C_COMMENT": "comment", "SCE_C_STRING": "string"})
...
ctx.languages.unregister(handler) # restores what it displaced
register neemt dezelfde vorm als een meegeleverd bestand colorizers/*.json (of
een heel woordenboek definition=): lexer noemt een bestaande lexer van de
backend (de host krijgt tijdens het draaien geen nieuwe lexers), styles koppelt
de eigen stijlnamen van die lexer aan semantische categorieën, en keywords
spreekt zijn woordenlijsten aan met de eigen plaatsbeschrijving van de lexer — de
host lost beide precies op zoals bij een meegeleverd bestand, zodat u nooit
motor-id's hoeft uit te schrijven. Een id registreren die al bestaat vervangt die
zolang u de id van de afhandelaar vasthoudt; het afsluiten van de plug-in trekt in
wat nog vastgehouden wordt.
document_settings¶
Alleen-lezen instellingen met documentbereik die de .editorconfig van een
project over uw eigen ctx.settings leggen. Voor sleutel k en document doc
lost een lezing mte.<plugin.id>.<k> op uit de .editorconfig die op dat
document van toepassing is, valt dan terug op ctx.settings, en dan op uw
standaardwaarde:
wrap = ctx.document_settings.get_bool(doc, "wrap", False)
width = ctx.document_settings.get_int(doc, "width", 80)
ratio = ctx.document_settings.get_double(doc, "ratio", 1.0)
name = ctx.document_settings.get_string(doc, "profile", "")
ctx.document_settings.contains(doc, "wrap") # set in either layer?
Schrijfacties gaan via ctx.settings — nooit terug de .editorconfig in.
diagnostics¶
Duw golflijnen en margetekens voor een document — vanuit een statische
analysator, een taalserver, een bouwlogboek. De host tekent ze; u raakt de weergave
nooit aan. Publiceren vervangt alles wat u eerder voor dat paar
(document, bron) gepubliceerd hebt, dus stuur elke keer de volledige
verzameling:
ctx.diagnostics.publish(doc, "mylinter", [
mte.Diagnostic(start=12, end=18, message="unused variable",
severity=mte.SEVERITY_WARNING, code="W0612"),
])
ctx.diagnostics.publish(doc, "mylinter", []) # retract only your own
ctx.diagnostics.clear(doc) # clears EVERY producer's set on doc
source is verplicht — dat is wat uw verzameling gescheiden houdt van die van
andere producenten (de LSP-plug-in, de spellingcontrole) op hetzelfde document.
Ernstgraden: SEVERITY_ERROR / SEVERITY_WARNING / SEVERITY_INFORMATION /
SEVERITY_HINT. Verschuivingen zijn halfopen bytebereiken [start, end).
theme¶
Registreer de kleuren die uw eigen interface schildert als benoemde, tematiseerbare categorieën; de Thema-editor somt ze automatisch op en de overschrijvingen van de gebruiker gaan heen en weer in het themabestand:
h = ctx.theme.register_category("com.example.my/match", "Match highlight",
default_light=0xFFF3B0, default_dark=0x8A6D00)
rgb = ctx.theme.resolve_color("com.example.my/match") # 0xRRGGBB int
themed = ctx.theme.has_override("com.example.my/match")
variant = ctx.theme.active_variant() # "light" / "dark" / ""
cats = ctx.theme.categories() # list[mte.ThemeCategory]
ctx.theme.unregister_category(h)
Lees resolve_color opnieuw bij ctx.events.on_theme_changed.
compare¶
Opent (of brengt naar voren) de vergelijkingsweergave naast elkaar van de editor
over twee bronnen. Elke kant is een bestand op de schijf (path=), letterlijke
tekst (content=), of beide (de inhoud wordt getoond, het pad geeft de
sessiebewaring een herstelbare identiteit):
shown = ctx.compare.open(
mte.CompareSource("before", path="/tmp/a.txt"),
mte.CompareSource("after", content=new_text),
ignore_whitespace=True) # ignore_case / ignore_eol too
Levert False op wanneer een kant niet gelezen kan worden.
settings¶
Blijvende getypeerde sleutel/waarde-opslag, op de host beperkt tot
plugins/<your.id>/. Alle methoden zijn synchroon; get en set leiden het type af
uit het Python-type van de standaardwaarde.
ctx.settings.set("wrap", True)
ctx.settings.set("count", 42)
ctx.settings.set("theme", "dark")
wrap = ctx.settings.get("wrap", False) # returns bool
count = ctx.settings.get("count", 0) # returns int
theme = ctx.settings.get("theme", "light") # returns str
Typen:
Python-type van default |
Draadtype | Type dat get() oplevert |
|---|---|---|
bool |
bool |
bool |
int (niet-bool) |
int |
int |
float |
double |
float |
str (of None) |
string |
str |
Verder:
ctx.settings.contains("wrap") # bool
ctx.settings.remove("stale_key")
ctx.settings.sync() # optional; host also syncs on shutdown
Reageer op wijzigingen die in het venster Voorkeuren gemaakt worden door u in te
schrijven op settings.changed (ctx.events.on_settings_changed; zie de
Naslag voor gebeurtenissen).
app_settings¶
Alleen-lezen kijk op de configuratie van de hele toepassing. De bekende
sleutelnamen zijn als constanten in mte.keys uitgevoerd (een spiegel van de
C++-header PluginApi/AppSettingsKeys.h, die de gezaghebbende lijst blijft):
import mte
size = ctx.app_settings.get(mte.keys.EDITOR_FONT_SIZE, mte.keys.DEFAULT_EDITOR_FONT_SIZE)
family = ctx.app_settings.get(mte.keys.EDITOR_FONT_FAMILY, "") # "" = host default
theme = ctx.app_settings.get(mte.keys.UI_THEME, mte.keys.DEFAULT_UI_THEME) # "system"/"light"/"dark"
De setters, remove() en sync() op ctx.app_settings werpen een
RuntimeError — de kijk is met opzet alleen-lezen.
completions¶
Registreer een aanvullingsleverancier die aan de pop-up van de editor meedoet:
@ctx.completions.provider(languages=["python"])
def _complete(req: mte.CompletionRequest):
if not req.prefix:
return []
return [mte.CompletionItem(text=w, kind=mte.KIND_KEYWORD)
for w in ("hello", "hello_world", "helper")
if w.startswith(req.prefix)]
De omhulde aanroepbare wordt bij elke toetsaanslag (of bij Ctrl+Space) aangeroepen
waarvan het document op het taalfilter past. Velden op req:
| Veld | Type | Betekenis |
|---|---|---|
document |
int |
Document dat bewerkt wordt |
prefix |
str |
Woordfragment direct vóór de cursor |
position |
int |
Byteverschuiving van de cursor |
language_id |
str |
Colorizer-id ("python", "cpp", …) |
manual |
bool |
True wanneer de gebruiker Ctrl+Space indrukte; False bij automatisch afgaan |
Lever een lijst met mte.CompletionItem op (of gewone tekenreeksen, of
woordenboeken met {text, detail, kind}). Soorten: mte.KIND_KEYWORD /
KIND_WORD / KIND_SYMBOL / KIND_SNIPPET / KIND_UNKNOWN.
Deadline
De host stuurt uw leverancier een toetsaanslagverzoek met een deadline van ~30 ms. Mist uw callback die, dan verschijnt de pop-up voor die toetsaanslag zonder uw kandidaten. Bouw elke dure index op de achtergrond en antwoord uit de cache — doe nooit I/O in de callback. Netwerkaanvulling in LSP-stijl hoort in een toekomstig asynchroon vlak, niet hier.
languages=[] (of weggelaten) betekent «elk document». Meerdere leveranciers per
plug-in zijn toegestaan; elke decorator registreert de zijne.
data_dir¶
Levert de beschrijfbare map per plug-in op die de host al voor u gemaakt heeft.
Gebruik hem voor caches, indexen en alle gegevens die van u zijn.
ctx.diagnostics_dir() levert op dezelfde manier de gedeelde map voor crashes en
logboeken op (voor u alleen-lezen — de crashmelder schrijft daarheen).
docks¶
Declaratieve dokpanelen — een zijpaneelinterface die uit een
formulierspecificatie gebouwd wordt, niet uit Qt-widgets. Zie
mte.ui voor het vocabulaire van de bouwers.
from mte.ui import Column, Row, Label, LineEdit, Checkbox, Button
def register(ctx):
def _on_needle_changed(value: str) -> None:
ctx.log.info(f"needle -> {value!r}")
needle_handler = ctx.docks.on_change(_on_needle_changed)
panel_id = ctx.docks.add_panel(
id="renamer.panel",
title="Renamer",
area="right", # left / right / top / bottom
form=Column([
Label(text="Search:"),
LineEdit(id="needle", placeholder="text...",
binds="settings:lastNeedle",
on_change=needle_handler),
Checkbox(id="cs", label="Case sensitive",
binds="settings:caseSensitive"),
Row([Button(text="Run", on_click="renamer.run")]),
]),
)
ctx.docks.add_panel(*, id=None, title="", area="right", form, initially_visible=True, proportional_size=0.0, tab_group="") -> str¶
Registreert een dokpaneel. Levert de paneel-id op (automatisch toegekend wanneer
id None is).
id(str, optioneel) — stabiele aanduiding diectx.ui.get / ctx.ui.setgebruiken om besturingselementen binnen dit paneel aan te spreken. Levert u er geen, dan kent de host een idpy-dock/Ntoe en levert die op.title(str) — getoond in de kop van het dok.area(str) —"left"/"right"/"top"/"bottom". Onbekende waarden vallen terug op"right".form(dict) — een specificatie gebouwd met de bouwers vanmte.ui.initially_visible(bool) — of het dok getoond wordt wanneer de plug-in laadt. StandaardTrue. GeefFalsemee voor een paneel dat bij het starten niet moet opduiken en toon het later metset_panel_visible.proportional_size(float) — de standaardgrootte van het paneel als aandeel van het hoofdvenster: van de breedte in de gebieden"left"/"right", van de hoogte in"top"/"bottom".0.0(de standaard) houdt het pixelgedrag dat een gereedschapspaneel wil: het paneel houdt zijn grootte en het venster van grootte veranderen laat het met rust. Een breuk als0.4is wat een voorbeeld wil: het venster maximaliseren maakt het paneel ermee breder. Alleen de standaard is van u; zodra de gebruiker de scheiding van het paneel versleept, neemt de host zijn aandeel over en onthoudt het. Waarden buiten het bereik worden afgekapt, en de host houdt een minimale omvang voor zowel het paneel als de editor. De volledige regels staan bijproportionalSize.tab_group(str) — panelen met dezelfde niet-lege groeps-id in dezelfdeareadelen één dok als tabbladen in plaats van naast elkaar te staan. Geef de id een naamruimte zoals een paneel-id ("renamer/panels"). Alleen de standaardindeling: een door de gebruiker opgeslagen indeling gaat voor. ZietabGroup.
ctx.docks.is_panel_visible(handler_id) -> bool¶
Of een met add_panel toegevoegd paneel open is — een paneel dat als
tabblad achter een ander zit, telt als open; een paneel dat met
initially_visible=False is geregistreerd en nooit getoond, een gesloten
paneel en een onbekende id niet. Combineer het met set_panel_visible om je
panelen voor een taak te tonen en daarna terug te zetten wat de gebruiker had:
was_open = ctx.docks.is_panel_visible(panel)
ctx.docks.set_panel_visible(panel, True)
# ... when the task ends:
ctx.docks.set_panel_visible(panel, was_open)
ctx.docks.set_panel_visible(handler_id, visible)¶
Toont of verbergt een paneel dat met add_panel toegevoegd is. Tonen brengt het
paneel ook boven de dokken waarmee het een gebied deelt, zodat een opdracht die
haar paneel «opent» het werkelijk voor de gebruiker zet. Idempotent — herhaal
dezelfde waarde gerust, er valt geen staat te volgen; voor een onbekende id wordt
het in stilte genegeerd.
panel = ctx.docks.add_panel(id="mine.panel", title="Mine", form=form,
initially_visible=False)
@ctx.commands.command("mine.show", title="Show My Panel")
def _show():
ctx.docks.set_panel_visible(panel, True)
ctx.docks.on_change(callback) -> str¶
Kent een afhandelaars-id toe om het veld on_change van een besturingselement aan
een Python-aanroepbare te koppelen. De callback ontvangt de nieuwe waarde als
tekenreeks; booleaanse besturingselementen leveren "true" / "false", numerieke
leveren het gehele getal als tekenreeks.
def _on_volume(value: str) -> None:
ctx.log.info(f"volume={int(value)}")
handler = ctx.docks.on_change(_on_volume)
form = Column([NumberSpin(id="volume", default=5, on_change=handler)])
Afhandelaars-id's van on_change krijgen het voorvoegsel py-dock-cb/N en botsen
nooit met de id's van afhandelaars voor opdrachten, gebeurtenissen of
aanvullingen.
De callback wordt op de gebeurtenislus van de worker aangeroepen, NIET op de
threadpool — houd hem snel. Gebruik ctx.log, wijzig een kleine staat in het
geheugen, of vuur een vervolgopdracht af; doe hier geen zwaar werk.
line_markers¶
Margesymbolen en kleuringen van hele regels, vastgemaakt aan documentregels die de bewerkingen van de gebruiker volgen — onderbrekingspunten, een pijl voor de huidige instructie, wijzigingsstroken — en de claim op de klik in de bladwijzerkolom. De native dienst en al haar regels staan beschreven onder Regelmarkeringen en margeklik.
bp_colour = ctx.theme.register_category("myplugin.breakpoint", "Breakpoint",
default_light=0xCC0000,
default_dark=0xFF5555)
bp = ctx.line_markers.register_kind(glyph=mte.GLYPH_CIRCLE,
glyph_color="myplugin.breakpoint",
line_tint="", z_order=50)
marker = ctx.line_markers.add_marker(bp, doc, line) # 0 = refused
ctx.line_markers.line_of(marker) # where it is NOW; -1 = gone
ctx.line_markers.markers(bp, doc) # [mte.LineMarkerPlacement(id, line)]
ctx.line_markers.remove_marker(marker)
ctx.line_markers.clear_markers(bp, doc) # doc 0 = every document
ctx.line_markers.release(bp) # removes the kind and its markers
register_kind(glyph=, glyph_color=, line_tint=, z_order=)—glyphis een vanmte.GLYPH_NONE(alleen kleuring),GLYPH_CIRCLE,GLYPH_CIRCLE_HOLLOW,GLYPH_CIRCLE_BAR,GLYPH_ARROW,GLYPH_STRIP; de kleuren zijn id's van categorieën die je metctx.themehebt geregistreerd. De editor heeft voor alle plug-ins samen maar een paar markeringsplaatsen, dus dit kan mislukken — dan wordtRpcErroropgeworpen. Registreer je soorten één keer, inregister().add_marker(kind, doc, line)— regel vanaf 0, niet begrensd: een regel buiten het document geeft 0 terug en plaatst niets.- Markeringen bewegen mee met hun regels, overleven een herlading op
hetzelfde regelnummer en verdwijnen met hun document — voeg de jouwe
opnieuw toe in
ctx.events.on_document_opened.
De margeklik¶
@ctx.events.on_margin_clicked
def _clicked(ev): # mte.MarginClicked
if ev.modifiers & mte.MODIFIER_CONTROL:
edit_condition(ev.document, ev.line)
else:
toggle_breakpoint(ev.document, ev.line)
claim = ctx.line_markers.claim_margin_click()
Elke linkerklik in de bladwijzerkolom wordt gepubliceerd als
margin.clicked (document, line, margin = "symbol", modifiers —
bits mte.MODIFIER_SHIFT / MODIFIER_CONTROL / MODIFIER_ALT /
MODIFIER_META). Standaard schakelt de editor daarbij ook een bladwijzer om;
zolang een plug-in claim_margin_click() vasthoudt, doet hij dat niet en
laat hij de klik aan de plug-ins over. ctx.line_markers.release(claim)
geeft de klik terug.
settings_page¶
Voegt een pagina onder het venster Voorkeuren van de editor toe. Hetzelfde
vocabulaire voor formulierspecificaties als bij dokpanelen; dezelfde bewaring met
binds="settings:<key>".
from mte.ui import Column, Checkbox, NumberSpin
def register(ctx):
ctx.settings_page.register(
category="Plugins/Renamer", # slash-separated tree path
title="Renamer",
form=Column([
Checkbox(id="cs", label="Case sensitive by default",
binds="settings:caseSensitive"),
NumberSpin(id="results", default=100, min=1, max=10_000,
binds="settings:resultCap"),
]),
)
ctx.settings_page.register(*, category, title, form, scope="") -> str¶
category(str, verplicht) — door schuine strepen gescheiden pad in de boom van Voorkeuren, bijvoorbeeld"Plugins/My Plugin". Geneste categorieën komen als knooppunten in de boom aan.title(str, verplicht) — kop die boven de pagina getoond wordt.form(dict, verplicht) — een specificatie gebouwd met de bouwers vanmte.ui.scope(str, optioneel) — het gebeurtenisbereik dat bijSettingsChangeduitgezonden wordt nadat de gebruiker op OK / Toepassen drukt.
Levert de afhandelaars-id op.
Annuleren draait wijzigingen NIET terug
Besturingselementen met binds="settings:<key>" bewaren gretig terwijl de
gebruiker bewerkt, dus Annuleren in het venster Voorkeuren maakt ze niet
ongedaan. Dat is een bekende beperking van fase 3; een latere verfijning zal de
onderliggende instellingen in een bufferende proxy omhullen.
ui¶
Leest en schrijft waarden van besturingselementen binnen panelen die u al geregistreerd hebt. Op de draad zijn waarden altijd tekenreeksen.
def register(ctx):
panel_id = ctx.docks.add_panel(id="renamer.panel", ...)
@ctx.commands.command(id="renamer.echo", title="Echo needle")
def _echo():
needle = ctx.ui.get(panel_id, "needle") or ""
cs = (ctx.ui.get(panel_id, "cs") or "false") == "true"
ctx.status.show(f"needle={needle!r} case={cs}")
@ctx.commands.command(id="renamer.clear", title="Clear needle")
def _clear():
ctx.ui.set(panel_id, "needle", "")
ctx.ui.get(panel_id, control_id) -> Optional[str]¶
Leest de huidige waarde van een besturingselement. Levert None op wanneer het
paneel of het besturingselement onbekend is (geen fout — behandel zowel None als
"" als «leeg»).
- Label / Button / LineEdit / ComboBox — levert de tekst op.
- Checkbox — levert
"true"of"false"op. - NumberSpin — levert het gehele getal als decimale tekenreeks op.
- List — levert de tekst op van het op dat moment geselecteerde item (leeg wanneer er niets geselecteerd is).
ctx.ui.set(panel_id, control_id, value) -> bool¶
Schrijft programmatisch een waarde in een besturingselement. Levert True op
wanneer het schrijven gelukt is, False wanneer het paneel of het
besturingselement onbekend is of de waarde niet omgezet kan worden (bijvoorbeeld
een niet-geheel getal dat naar een NumberSpin gestuurd wordt).
De Python-booleans True / False worden vóór het versturen naar "true" /
"false" omgezet; al het overige gaat door str().
Een set die door de host aangestuurd wordt laat de callback on_change van het
besturingselement NIET opnieuw afgaan, zodat u uw eigen widgets vanuit een
opdrachtafhandelaar kunt bijwerken zonder oneindige lussen.
Samenvatting van de koppelingen tijdens het draaien (fase 3)¶
| Veld van de formulierspecificatie | Gedrag tijdens het draaien |
|---|---|
id="…" |
Spreek het besturingselement aan vanuit ctx.ui.get / ctx.ui.set. |
binds="settings:<key>" |
Leest de beginwaarde uit ctx.settings; schrijft bij elke bewerking van de gebruiker terug. |
on_click="<cmd>" |
Knoppen roepen bij een klik de geregistreerde opdracht-id aan. |
on_change=handler |
Laat bij een bewerking van de gebruiker de callback afgaan die via ctx.docks.on_change(...) geregistreerd is. |
Dezelfde regels gelden op dokpanelen en op Voorkeurenpagina's.