ctx — kontext zásuvného modulu¶
register(ctx) dostáva jediný argument: PluginContext. Sprístupňuje nižšie uvedené služby
(celú plochu IPluginContext, ktorá sa zmestí do modelu mimo procesu). Každá z nich je malou
triedou v Pythone, ktorú pracovný proces stavia nad kanálom RPC; zdrojové kódy sú
v 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
Dve časti natívneho kontraktu zatiaľ nemajú náprotivok v Pythone: poskytovatelia hoveru (prioritné pásma hoveru sa preto na moduly v Pythone nevzťahujú) a poskytovatelia kontextovej ponuky editora (preto ani oblasť text / okraj kontextovej ponuky). Na obe sa odpovedá, kým používateľ čaká, a to si vyžaduje rovnaké zaobchádzanie s termínmi, aké majú poskytovatelia dopĺňania, než bude cesta k pracovnému procesu a späť bezpečná.
Neukladajte si ctx do globálnej premennej s tým, že ho použijete neskôr — hoci sú atribúty
počas života zásuvného modulu stabilné, berte ctx ako viazané na jednu registráciu. Ak ich
potrebujete, ponechajte si odkazy na jednotlivé služby (napríklad log = ctx.log).
commands¶
Dekorátor, ktorý zaregistruje príkaz a obalenú volateľnú funkciu naviaže ako jeho obslužný kód.
id(str, povinné): jedinečný identifikátor v štýle reverzného DNS (napr."wordcount.count"). Tie isté pravidlá ako vplugin.json— musí byť globálne jedinečný.title(str, povinné): čitateľný popis zobrazený všade, kde sa príkaz objaví (ponuky, paleta príkazov).shortcut(str, voliteľné): prenosný predvolený reťazec so skratkou, napr."Ctrl+Alt+W".Ctrlsa automaticky mapuje na hlavný modifikátor platformy (Cmdna macOS). Nechajte prázdne, ak žiadnu nechcete. Používateľ ju môže premapovať alebo zrušiť v Predvoľby ▸ Skratky; pri príkazoch viazaných na ponuku uplatní premapovanie hostiteľ za vás.category(str, voliteľné): voľný popis na zoskupenie — zobrazuje sa ako kategória príkazu v Mapovaní skratiek.scope(str, voliteľné):""/"application"(predvolené — hostiteľ skratku naviaže na akciu ponuky daného príkazu) alebo"pluginWindow"pri kombináciách žijúcich v rozhraní vlastnenom zásuvným modulom: hostiteľ príkaz iba vypíše v mapovaní; pri zostavovaní svojich widgetov si prečítajtectx.commands.effective_shortcut(id)a pri udalosti"command.shortcutChanged"priradenie uplatnite znova.
Skratka, ktorá práve platí po premapovaní používateľom a po vyriešení konfliktov ("" = bez
priradenia alebo neznáme). Z obslužného kódu sa dá bezpečne volať.
Obalená funkcia neprijíma žiadne argumenty a nič nevracia. Výnimky vnútri nej zachytí pracovný proces a zaznamená ich na stderr; editor nezhavarujú.
@ctx.commands.command(id="wordcount.count",
title="Count Words",
shortcut="Ctrl+Alt+W",
category="Text")
def _count():
ctx.status.show("counted")
Ako to funguje vnútri: strana Pythonu si lokálne pridelí handlerId, zaregistruje zavolanie na
spojení RPC a vyšle hostiteľovi commands.registerCommand. Keď používateľ príkaz aktivuje
(kliknutím v ponuke, skratkou, paletou), hostiteľ pošle RPC callback a vaša funkcia sa spustí.
Id príkazov platia v celom procese, nie v rámci zásuvného modulu. Predchádzajte kolíziám tým,
že id opatríte svojím menným priestorom v tvare reverzného DNS (wordcount.…).
menus¶
Cesty v ponukách používajú ako oddeľovač /. Najľavejší segment je hlavnou ponukou (Plugins,
Tools, …); medziľahlé segmenty vytvárajú podponuky na požiadanie; posledný segment je popisom
položky.
ctx.menus.add_item(path, command_id)¶
path(str):"Top/Sub/…/Label". Medziľahlé podponuky sa vytvoria, ak neexistujú.command_id(str): id predtým zaregistrovaného príkazu. Kliknutím na položku sa príkaz zavolá.
Vracia nepriehľadný reťazec handlerId. Ponechajte si ho, ak budete neskôr potrebovať položku
odregistrovať cez unsubscribe (vo fáze 1 zriedkavé).
Najľavejší segment (vyššie "Plugins") musí zodpovedať poľu title niektorej z vašich položiek
menus[] v plugin.json, aby sa umiestnenie v paneli ponuky prevzalo.
ctx.menus.add_separator(path)¶
Vloží oddeľovač do existujúcej podponuky.
ctx.menus.set_item_checked(handler_id, checked)¶
Premení predtým pridanú položku na začiarkavaciu a nastaví jej stav — štandardná zvyklosť pre trvalý prepínač zapnuté/vypnuté s viditeľnou značkou začiarknutia.
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)
Prvé volanie položku povýši na začiarkavaciu; ďalšie volania už iba prepínajú značku. Odovzdanie
handler_id, ktoré hostiteľ nepozná, je tichou prázdnou operáciou (dá sa bezpečne volať aj po
zahodení vášho tokenu, napríklad z oneskoreného zavolania počas ukončovania).
ctx.menus.set_item_enabled(handler_id, enabled)¶
Zapne alebo zosivie predtým pridanú položku. Použite to, keď príkaz potrebuje splnenú podmienku — niečo na zatvorenie, niečo na obnovenie — aby ponuka ukázala, že položka nie je dostupná, namiesto toho, aby ponúkala niečo, čo potichu neurobí nič.
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)
Vypnutá položka ostáva viditeľná, ale nedá sa vyvolať ani kliknutím, ani skratkou. Volanie je
idempotentné, takže si predchádzajúci stav nikdy nemusíte pamätať, a neznáme handler_id je
tichou prázdnou operáciou, ako vyššie. Položky sú na začiatku zapnuté: jedno volanie hneď po
add_item nastaví položku, ktorá pri spustení nie je dostupná.
events¶
Prihláste sa na odber udalostí editora. Dve rovnocenné rozhrania — odporúčajú sa pohodlné
dekorátory; surové subscribe() je k dispozícii, ak chcete tému vypočítať za behu.
Pohodlné dekorátory¶
@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}")
Obalená funkcia prijíma jeden argument: typovanú dátovú triedu zodpovedajúcu danej téme. Úplnú tabuľku téma ↔ dátová trieda nájdete v Referencii udalostí.
Surové API¶
handler_id = ctx.events.subscribe("document.saved", _saved)
# later:
ctx.events.unsubscribe(handler_id)
Dostupné pohodlné vlastnosti (všetko dekorátory):
| Vlastnosť | Vyvolá sa pri |
|---|---|
on_document_opened |
Otvorení dokumentu v karte |
on_document_closed |
Zatvorení dokumentu |
on_document_saved |
Zapísaní dokumentu na disk |
on_selection_changed |
Presune kurzora alebo výberu v aktívnom dokumente |
on_active_document_changed |
Zmene karty v popredí |
on_document_modified_changed |
Prepnutí príznaku čistý/zmenený (modified: bool) |
on_text_changed |
Každej úprave (position, added_bytes, removed_bytes) — držte to triviálne |
on_settings_changed |
Uplatnení Predvolieb (scope: "" v celom editore, "plugins/<id>") |
on_theme_changed |
Prepnutí alebo úprave motívu (variant) — načítajte farby ctx.theme znova |
on_workspace_root_changed |
Otvorení či zatvorení priečinka pracovného priestoru (root) |
on_workspace_files_changed |
Zmene množiny súborov pracovného priestoru (files) |
on_host_window_shown |
Raz za spustenie, po prvej snímke — naplánujte sem pomalú prácu pri štarte |
on_app_about_to_quit |
Zatváraní editora — posledná šanca niečo spustiť |
on_command_shortcut_changed |
Zmene skutočnej skratky príkazu (premapovanie používateľom, import mapy klávesov, riešenie konfliktu); obsah: command_id, sequence ("" = bez priradenia) |
Neznáme názvy tém vyvolajú pri odbere ValueError. Odberatelia sa môžu spustiť po príslušnom
natívnom obslužnom kóde; berte doručovanie udalostí ako informatívne, nie záväzné.
Zverejňovanie¶
ctx.events.publish(topic, payload) rozošle udalosť natívnym aj pythonovským odberateľom —
prijímajú sa iba dve témy pracovného priestoru (workspace.rootChanged,
workspace.filesChanged); čokoľvek iné vyvolá ValueError. Pozri
Referenciu udalostí.
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")
Každá úroveň zodpovedá hostiteľskému ILogger. Riadky majú predponu [python:<plugin.id>],
takže sa váš výstup v diagnostickom logu editora dá nájsť:
Zo zásuvného modulu nikdy nevolajte print() — stdout pracovného procesu je kanálom RPC a zápis
do neho protokol poškodí. ctx.log.* je jediný schválený spôsob, ako vypisovať diagnostický
text.
status¶
Odošle dočasné upozornenie do stavového riadka.
message(str): čo sa má zobraziť. Iba krátke reťazce — stavový riadok má pevnú šírku.timeout_ms(int, predvolene 0): ako dlho ho nechať na obrazovke;0nechá hostiteľa zvoliť rozumnú predvoľbu (niekoľko sekúnd).level(str, predvolene"info"):"info"/"warning"/"error". Vyššie úrovne môžu minimálny čas na obrazovke o niečo predĺžiť, aby chybu hneď nezmazala rutinná informácia.
ctx.status.show sa odošle a ďalej sa oň nestaráte. Ak hostiteľ nemá viditeľný stavový riadok
(bezhlavá alebo minimálna zostava), volanie sa potichu zahodí. ctx.status.clear() zmaže
dočasné upozornenie, ktoré je práve na obrazovke.
Trvalé segmenty¶
Na živý stav (počet slov, stav servera) použite segment, ktorý vlastníte a obnovujete — upozornenie nikdy neprebije a naopak:
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 zoraďuje segmenty zásuvných modulov zľava doprava (nižšie = viac vľavo; pri zhode sa
zachová poradie registrácie). Ukončenie zásuvného modulu odstráni všetko, čo si ešte drží.
editor¶
Plný synchrónny prístup k aktívnym dokumentom. Každá metóda blokuje volajúce vlákno, kým hostiteľ
neodpovie (zvyčajne mikrosekundy, keď sú pracovný proces a editor na jednom počítači). Dá sa
volať z ktoréhokoľvek obslužného kódu príkazu či udalosti; nikdy nie zo zavolania typu
async def (pozri poznámku o vláknach navrchu tejto stránky).
Výpis dokumentov¶
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
Prístup k bufferu¶
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 sa vyhýba ťahaniu celého bufferu cez RPC, keď potrebujete iba jeho časť — pri
zoraďovaní či transformácii veľkých súborov ho uprednostnite.
Výber¶
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?
Kurzor¶
pos = ctx.editor.caret(doc) # mte.EditorPosition(line, column)
ctx.editor.set_caret(doc, mte.EditorPosition(line=7, column=3))
Operácie so súbormi¶
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 je jediné volanie na „prenes používateľa tam“ (chyba
zostavenia, rámec zásobníka, výsledok hľadania): otvorí súbor alebo aktivuje
jeho kartu, umiestni kurzor bez výberu, rozbalí zbalenie, ktoré riadok
skrýva, posunie riadok do zobrazenia — na stred, ak bol mimo obrazovky — a
odovzdá fokus editoru. Riadok a stĺpec sa počítajú od 0 (stĺpec v bajtoch
UTF-8) a orezávajú sa, nikdy sa neodmietajú; vracia id dokumentu, alebo 0,
keď sa súbor nepodarilo otvoriť, a vtedy sa nič nepohlo. reveal_line iba
ukáže riadok: nepresunie kurzor, neprepne kartu a nezoberie fokus.
Záložky, označenia, zvýrazňovanie URL¶
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
Hľadanie¶
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". Úplný zoznam polí nájdete v mte.SearchOptions.
Prírastkové hľadanie (vzor rastie, ako používateľ píše, od pripnutej kotvy):
ctx.editor.set_incremental_search_anchor(doc)
hit = ctx.editor.incremental_search(doc, "TOD", opts) # MatchRange
Odsadenie a syntax¶
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
Rozdelené zobrazenie a skupiny kariet¶
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
Dokument zobrazený v dvoch tablách je jeden dokument s jedným id, takže group_of() dokáže
pomenovať iba jedno z jeho miest. groups_of() ich uvedie všetky a show_document_in_group()
vytvorí druhé zdieľané zobrazenie — to isté, čo robí Zobraziť > Rozdeliť dokument vpravo,
takže sa nevyvolá udalosť document_opened.
ctx.editor dnes zrkadlí natívne IEditorService jedna k jednej.
languages¶
Farebné zvýrazňovanie syntaxe je funkciou jadra — hostiteľ rozpozná jazyk dokumentu a zafarbí ho
bez akéhokoľvek zásuvného modulu. ctx.languages je spôsob, ako sa pridať: vypísať, čo hostiteľ
pozná, prečítať alebo prekryť jazyk dokumentu, znova spustiť rozpoznávanie a prispieť celými
definíciami jazykov.
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 má rovnaký tvar ako dodávaný súbor colorizers/*.json (prípadne celý slovník
definition=): lexer pomenúva existujúci lexer backendu (hostiteľ za behu žiadne nové lexery
nezíska), styles mapuje názvy štýlov tohto lexera na sémantické kategórie a keywords
adresuje jeho zoznamy slov popisom priehradiek daného lexera — hostiteľ obidve vyhodnotí presne
tak ako pri dodávanom súbore, takže id mechanizmu nikdy nevypisujete. Zaregistrovaním už
existujúceho id sa pôvodné nahradí na tak dlho, ako držíte id popisovača; ukončenie zásuvného
modulu stiahne všetko, čo si ešte drží.
document_settings¶
Nastavenia v rozsahu dokumentu iba na čítanie, ktoré ukladajú .editorconfig projektu ako vrstvu
nad vaše ctx.settings. Pre kľúč k a dokument doc vyhodnotí čítanie
mte.<plugin.id>.<k> zo súboru .editorconfig platného pre tento dokument, potom sa vráti
k ctx.settings a napokon k vašej predvolenej hodnote:
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?
Zápisy idú cez ctx.settings — nikdy nie späť do .editorconfig.
diagnostics¶
Posielajte pre dokument vlnovky a značky na okraji — zo statického analyzátora, z jazykového
servera, z logu zostavenia. Hostiteľ ich vykreslí; vy sa zobrazenia nikdy nedotknete.
Zverejnenie nahradí všetko, čo ste predtým zverejnili pre danú dvojicu (dokument, zdroj),
takže zakaždým posielajte celú množinu:
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 je povinný — práve on drží vašu množinu oddelene od množín ostatných producentov
(zásuvného modulu LSP, kontroly pravopisu) v tom istom dokumente. Závažnosti:
SEVERITY_ERROR / SEVERITY_WARNING / SEVERITY_INFORMATION / SEVERITY_HINT. Posuny sú
polootvorené bajtové rozsahy [start, end).
theme¶
Zaregistrujte farby, ktoré vykresľuje vaše vlastné rozhranie, ako pomenované kategórie z motívu; Editor motívov ich automaticky vypíše a prekrytia používateľa putujú tam a späť v súbore motívu:
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)
Pri ctx.events.on_theme_changed zavolajte resolve_color znova.
compare¶
Otvorte (alebo zamerajte) zobrazenie porovnania editora vedľa seba nad dvoma zdrojmi. Každá
strana je súbor na disku (path=), doslovný text (content=) alebo obidve (zobrazí sa obsah,
cesta dáva uchovávaniu relácie obnoviteľnú identitu):
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
Vracia False, keď sa niektorá strana nedá prečítať.
settings¶
Trvalé typované úložisko kľúč/hodnota s rozsahom plugins/<your.id>/ na strane hostiteľa.
Všetky metódy sú synchrónne; typ pri get aj set sa odvodí z typu predvolenej hodnoty
v Pythone.
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
Typy:
Typ hodnoty default v Pythone |
Prenosový typ | Návratový typ z get() |
|---|---|---|
bool |
bool |
bool |
int (nie bool) |
int |
int |
float |
double |
float |
str (alebo None) |
string |
str |
Ďalej:
ctx.settings.contains("wrap") # bool
ctx.settings.remove("stale_key")
ctx.settings.sync() # optional; host also syncs on shutdown
Na zmeny urobené v dialógu Predvoľby reagujte prihlásením na settings.changed
(ctx.events.on_settings_changed; pozri Referenciu udalostí).
app_settings¶
Pohľad na konfiguráciu celej aplikácie iba na čítanie. Známe názvy kľúčov sú vyexportované ako
konštanty v mte.keys (zrkadlia hlavičku C++ PluginApi/AppSettingsKeys.h, ktorá ostáva
záväzným zoznamom):
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"
Metódy na zápis, remove() a sync() na ctx.app_settings vyvolajú RuntimeError — pohľad je
zámerne iba na čítanie.
completions¶
Zaregistrujte poskytovateľa dopĺňania, ktorý sa zapojí do vyskakovacieho okna editora:
@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)]
Obalená volateľná funkcia sa vyvolá pri každom stlačení klávesu (alebo pri Ctrl+Space), ktorého
dokument zodpovedá filtru jazykov. Polia na req:
| Pole | Typ | Význam |
|---|---|---|
document |
int |
Upravovaný dokument |
prefix |
str |
Časť slova bezprostredne pred kurzorom |
position |
int |
Bajtový posun kurzora |
language_id |
str |
Id zvýrazňovača ("python", "cpp", …) |
manual |
bool |
True, keď používateľ stlačil Ctrl+Space; False pri automatickom vyvolaní |
Vráťte zoznam mte.CompletionItem (prípadne obyčajné reťazce či slovníky s
{text, detail, kind}). Druhy: mte.KIND_KEYWORD / KIND_WORD / KIND_SYMBOL /
KIND_SNIPPET / KIND_UNKNOWN.
Termín
Hostiteľ posiela vášmu poskytovateľovi požiadavku na stlačenie klávesu s termínom ~30 ms. Ak ho vaše zavolanie nestihne, vyskakovacie okno sa pri tomto stlačení zobrazí bez vašich kandidátov. Akýkoľvek nákladný index si vybudujte na pozadí a odpovedajte z vyrovnávacej pamäte — v zavolaní nikdy nerobte vstupno-výstupné operácie. Sieťové dopĺňanie v štýle LSP patrí do budúcej asynchrónnej plochy, nie sem.
languages=[] (alebo vynechané) znamená „každý dokument“. Viacero poskytovateľov na jeden
zásuvný modul je povolených; každý dekorátor registruje vlastného.
data_dir¶
Vracia zapisovateľný priečinok pre daný zásuvný modul, ktorý už hostiteľ za vás vytvoril.
Používajte ho na vyrovnávacie pamäte, indexy a všetky údaje, ktoré vlastníte.
ctx.diagnostics_dir() podobne vracia zdieľaný priečinok s pádmi a logmi (pre vás iba na
čítanie — zapisuje doň nástroj na hlásenie pádov).
docks¶
Deklaratívne ukotviteľné panely — rozhranie bočného panela zostavené zo špecifikácie formulára,
nie z widgetov Qt. Slovník tvorcov nájdete v mte.ui.
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¶
Zaregistruje ukotviteľný panel. Vracia id panela (pridelené automaticky, keď je id None).
id(str, voliteľné) — stabilný identifikátor, ktorýmctx.ui.getactx.ui.setadresujú ovládacie prvky vnútri tohto panela. Ak ho nezadáte, hostiteľ pridelí idpy-dock/Na vráti ho.title(str) — zobrazuje sa v hlavičke panela.area(str) —"left"/"right"/"top"/"bottom". Neznáme hodnoty sa vrátia k"right".form(dict) — špecifikácia zostavená tvorcami zmte.ui.initially_visible(bool) — či sa panel zobrazí po načítaní zásuvného modulu. PredvoleneTrue. Pri paneli, ktorý pri štarte nemá vyskočiť, odovzdajteFalsea zobrazte ho neskôr cezset_panel_visible.proportional_size(float) — predvolená veľkosť panela ako podiel hlavného okna: jeho šírky v oblastiach"left"/"right", jeho výšky v"top"/"bottom".0.0(predvolená hodnota) zachováva pixelové správanie, ktoré chce nástrojový panel — panel si drží svoju veľkosť a zmena veľkosti okna sa ho nedotkne. Zlomok ako0.4je to, čo chce náhľad: maximalizácia okna panel rozšíri spolu s ním. Vaša je len predvolená hodnota; len čo používateľ pretiahne oddeľovač panela, hostiteľ jeho podiel prijme a zapamätá si ho. Hodnoty mimo rozsah sa obmedzia a hostiteľ zachová minimálny rozmer pre panel aj editor. Úplné pravidlá nájdete priproportionalSize.tab_group(str) — panely s rovnakým neprázdnym id skupiny v rovnakejareazdieľajú jeden dok ako karty, namiesto aby ležali vedľa seba. Dajte mu menný priestor ako id panela ("renamer/panels"). Iba predvolené usporiadanie: rozloženie uložené používateľom má prednosť. PozritabGroup.
ctx.docks.is_panel_visible(handler_id) -> bool¶
Či je panel pridaný cez add_panel otvorený — panel schovaný ako karta za
iným sa počíta ako otvorený; panel zaregistrovaný s initially_visible=False
a nikdy nezobrazený, zatvorený panel a neznáme id nie. Kombinujte ho so
set_panel_visible, ak chcete zobraziť svoje panely počas úlohy a potom
vrátiť, čo mal používateľ:
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)¶
Zobrazí alebo skryje panel pridaný cez add_panel. Zobrazenie panel zároveň vynesie nad panely,
s ktorými zdieľa oblasť, takže príkaz, ktorý svoj panel „otvára“, ho naozaj postaví pred
používateľa. Je idempotentné — tú istú hodnotu môžete pokojne opakovať, netreba sledovať žiadny
stav; pri neznámom id sa potichu ignoruje.
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¶
Pridelí id obslužného kódu na prepojenie poľa on_change ovládacieho prvku s volateľnou funkciou
v Pythone. Zavolanie dostane novú hodnotu ako reťazec; logické ovládacie prvky doručujú
"true" / "false", číselné doručujú celé číslo ako reťazec.
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)])
Id obslužných kódov on_change majú predponu py-dock-cb/N a nikdy nekolidujú s id obslužných
kódov príkazov, udalostí ani dopĺňania.
Zavolanie prebieha v slučke udalostí pracovného procesu, NIE v zásobe vlákien — držte ho rýchle.
Použite ctx.log, zmeňte malý stav v pamäti alebo spustite nadväzujúci príkaz; nerobte tu ťažkú
prácu.
line_markers¶
Symboly na okraji a podfarbenie celých riadkov pripojené k riadkom dokumentu, ktoré sledujú úpravy používateľa — zarážky, šípka aktuálneho príkazu, pásy zmien — a nárok na kliknutie do stĺpca záložiek. Natívnu službu a všetky jej pravidlá opisuje stránka Značky riadkov a kliknutie na okraj.
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=)—glyphje jedna z hodnôtmte.GLYPH_NONE(iba podfarbenie),GLYPH_CIRCLE,GLYPH_CIRCLE_HOLLOW,GLYPH_CIRCLE_BAR,GLYPH_ARROW,GLYPH_STRIP; farby sú id kategórií, ktoré ste zaregistrovali cezctx.theme. Editor má pre všetky moduly spolu iba niekoľko slotov na značky, takže volanie môže zlyhať — vtedy vyvoláRpcError. Svoje druhy registrujte raz, vregister().add_marker(kind, doc, line)— riadok počítaný od 0, neorezávaný: riadok mimo dokumentu vráti 0 a nič neumiestni.- Značky sa posúvajú so svojimi riadkami, prežijú opätovné načítanie na
rovnakom čísle riadka a miznú so svojím dokumentom — svoje značky pridávajte
znova v
ctx.events.on_document_opened.
Kliknutie na okraj¶
@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()
Každé kliknutie ľavým tlačidlom do stĺpca záložiek sa zverejní ako
margin.clicked (document, line, margin = "symbol", modifiers —
bity mte.MODIFIER_SHIFT / MODIFIER_CONTROL / MODIFIER_ALT /
MODIFIER_META). Predvolene editor pri ňom tiež prepne záložku; kým niektorý
modul drží claim_margin_click(), nerobí to a kliknutie prenechá modulom.
ctx.line_markers.release(claim) kliknutie vráti.
settings_page¶
Pridáva stránku do dialógu Predvoľby editora. Ten istý slovník špecifikácie formulára ako pri
ukotviteľných paneloch; to isté uchovávanie cez 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, povinné) — cesta v strome Predvolieb oddelená lomkami, napr."Plugins/My Plugin". Vnorené kategórie prídu ako uzly stromu.title(str, povinné) — nadpis zobrazený nad stránkou.form(dict, povinné) — špecifikácia zostavená tvorcami zmte.ui.scope(str, voliteľné) — rozsah udalosti vyslanej vSettingsChangedpo tom, čo používateľ stlačí OK alebo Použiť.
Vracia id obslužného kódu.
Zrušiť zmeny NEVRÁTI
Ovládacie prvky s binds="settings:<key>" sa uchovávajú priebežne počas úprav používateľom,
takže stlačenie Zrušiť v dialógu Predvoľby ich nevráti späť. Je to známe obmedzenie fázy
3; budúce spresnenie podkladové nastavenia obalí vyrovnávacím zástupcom.
ui¶
Číta a zapisuje hodnoty ovládacích prvkov vnútri panelov, ktoré ste už zaregistrovali. Hodnoty sú na prenosovej úrovni vždy reťazcami.
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]¶
Prečíta aktuálnu hodnotu ovládacieho prvku. Vracia None, keď je panel alebo prvok neznámy (nie
je to chyba — None aj "" berte ako „prázdne“).
- Label / Button / LineEdit / ComboBox — vracia text.
- Checkbox — vracia
"true"alebo"false". - NumberSpin — vracia celé číslo ako desiatkový reťazec.
- List — vracia text práve vybranej položky (prázdny, keď nie je nič vybrané).
ctx.ui.set(panel_id, control_id, value) -> bool¶
Zapíše hodnotu do ovládacieho prvku programovo. Vracia True, keď sa zápis podaril, a False,
keď je panel či prvok neznámy alebo sa hodnota nedá previesť (napríklad necelé číslo poslané do
NumberSpin).
Pythonovské True a False sa pred odoslaním prevedú na "true" a "false"; všetko ostatné
prejde cez str().
Zápis cez set zo strany hostiteľa NEVYVOLÁ znova zavolanie on_change daného prvku, takže
môžete svoje widgety aktualizovať z obslužného kódu príkazu bez nekonečných slučiek.
Zhrnutie väzieb za behu (fáza 3)¶
| Pole špecifikácie formulára | Správanie za behu |
|---|---|
id="…" |
Adresuje ovládací prvok z ctx.ui.get a ctx.ui.set. |
binds="settings:<key>" |
Číta počiatočnú hodnotu z ctx.settings; pri každej úprave používateľom zapisuje späť. |
on_click="<cmd>" |
Tlačidlá po kliknutí vyvolajú zaregistrované id príkazu. |
on_change=handler |
Pri úprave používateľom vyvolá zavolanie zaregistrované cez ctx.docks.on_change(...). |
Tie isté pravidlá platia pre ukotviteľné panely aj pre stránky Predvolieb.