ctx — programtilleggets kontekst¶
register(ctx) mottar ett argument: en PluginContext. Den blottlegger tjenestene
nedenfor (hele den IPluginContext-flaten som passer til modellen med en egen prosess).
Hver er en liten Python-klasse som arbeideren bygger oppå RPC-kanalen; kildekoden er
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
To deler av den innebygde kontrakten har ennå ingen motpart i Python: hover-leverandører (så prioritetsbåndene for hover gjelder ikke for Python-programtillegg) og leverandører for redigererens kontekstmeny (så heller ikke kontekstmenyens område tekst / marg). Begge besvares mens brukeren venter, og det krever den samme behandlingen med frister som fullføringsleverandørene har, før en tur-retur til arbeideren er trygg.
Lagre ikke ctx i en global variabel i påvente av å bruke den senere — selv om
attributtene er stabile programtilleggets levetid ut, så behandl ctx som noe som hører
til registreringen. Behold henvisninger til de enkelte tjenestene du trenger (log =
ctx.log, for eksempel).
commands¶
En dekorator som registrerer en kommando og binder den innpakkede funksjonen som behandleren dens.
id(str, påkrevd): en entydig identifikator i omvendt DNS-stil (for eksempel"wordcount.count"). Samme regler som iplugin.json— må være globalt entydig.title(str, påkrevd): den lesbare merkelappen som vises overalt der kommandoen kommer til syne (menyer, kommandopaletten).shortcut(str, valgfri): den flyttbare standardhurtigtasten, for eksempel"Ctrl+Alt+W".Ctrloversettes av seg selv til plattformens viktigste modifikator (Cmdpå macOS). La den stå tom for ingen. Brukeren kan gi den en ny binding eller ingen under Innstillinger ▸ Hurtigtaster; for menybundne kommandoer tar verten omtildelingen i bruk for deg.category(str, valgfri): en fritt formulert grupperingsmerkelapp — vises som kommandoens kategori i hurtigtasttildelingen.scope(str, valgfri):""/"application"(standard — verten binder hurtigtasten på kommandoens menyhandling) eller"pluginWindow"for tastekombinasjoner som hører hjemme i et grensesnitt programtillegget eier: verten bare lister kommandoen i tildelingen; lesctx.commands.effective_shortcut(id)når du bygger kontrollene dine, og ta den i bruk på nytt ved hendelsen"command.shortcutChanged".
Den hurtigtasten som faktisk gjelder etter brukerens omtildeling og løsningen av
konflikter ("" = uten binding eller ukjent). Trygt å kalle fra behandlere.
Den innpakkede funksjonen tar ingen argumenter og gir ingenting tilbake. Unntak inne i den fanges av arbeideren og noteres til stderr; de får ikke redigereren til å krasje.
@ctx.commands.command(id="wordcount.count",
title="Count Words",
shortcut="Ctrl+Alt+W",
category="Text")
def _count():
ctx.status.show("counted")
Under panseret: Python-siden tildeler en handlerId lokalt, registrerer tilbakekallet på
RPC-forbindelsen og sender commands.registerCommand til verten. Når brukeren aktiverer
kommandoen (et menyklikk, hurtigtasten, paletten), sender verten et callback-RPC, og
funksjonen din kjører.
Kommando-id-er gjelder for hele prosessen, ikke per programtillegg. Sett ditt omvendte
DNS-navnerom foran id-ene dine (wordcount.…) for å unngå kollisjoner.
menus¶
Menystier bruker / som skilletegn. Det ytterste venstre leddet er en øverste meny
(Plugins, Tools …); mellomliggende ledd lager undermenyer ved behov; det siste leddet
er postens merkelapp.
ctx.menus.add_item(path, command_id)¶
path(str):"Øverst/Under/…/Merkelapp". Mellomliggende undermenyer lages ved behov.command_id(str): id-en til en kommando som er registrert tidligere. Et klikk på posten kaller kommandoen.
Gir en ugjennomsiktig handlerId-tekststreng tilbake. Behold den om du senere trenger å
gjøre unsubscribe på posten (sjelden i fase 1).
Det ytterste venstre leddet ("Plugins" ovenfor) må passe til title i en av
menus[]-postene dine i plugin.json, så plasseringen på menylinjen blir med.
ctx.menus.add_separator(path)¶
Setter inn en skillelinje i en undermeny som alt finnes.
ctx.menus.set_item_checked(handler_id, checked)¶
Gjør den posten som er lagt til tidligere, om til en avkryssbar menypost og setter tilstanden dens — det vanlige idiomet for en varig av/på-bryter som viser et synlig kryss.
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)
Det første kallet gjør posten avkryssbar; de følgende kallene snur bare krysset. Å gi en
handler_id verten ikke kjenner, gjør i stillhet ingenting (trygt å kalle etter at
symbolet ditt er droppet, for eksempel fra et forsinket tilbakekall som utløses under
nedstengningen).
ctx.menus.set_item_enabled(handler_id, enabled)¶
Slår en post som er lagt til tidligere, av eller på. Bruk den når kommandoen trenger en forutsetning — noe å lukke, noe å gjenopprette — så menyen viser at den ikke er tilgjengelig, i stedet for å tilby en post som i stillhet ikke gjør noe.
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)
En post som er slått av, blir værende synlig, men kan ikke utløses, verken med et klikk
eller med hurtigtasten sin. Kallet kan gjentas, så du aldri trenger å huske den forrige
tilstanden, og en ukjent handler_id gjør i stillhet ingenting, som ovenfor. Poster
begynner påslått: ett kall rett etter add_item setter opp en post som ikke er
tilgjengelig ved oppstart.
events¶
Abonner på redigererhendelser. To likeverdige API-er — de lette dekoratorene anbefales;
den rå subscribe() er der om du vil regne ut emnet under kjøringen.
Lette dekoratorer¶
@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}")
Den innpakkede funksjonen tar ett argument: en typet dataklasse som svarer til emnet. Se Hendelsesdokumentasjonen for hele tabellen over emne ↔ dataklasse.
Det rå API-et¶
handler_id = ctx.events.subscribe("document.saved", _saved)
# later:
ctx.events.unsubscribe(handler_id)
Tilgjengelige lette egenskaper (alle sammen dekoratorer):
| Egenskap | Utløses ved |
|---|---|
on_document_opened |
Et dokument ble åpnet i en fane |
on_document_closed |
Et dokument ble lukket |
on_document_saved |
Et dokument ble skrevet til disken |
on_selection_changed |
Markøren eller merkingen flyttet seg i det aktive dokumentet |
on_active_document_changed |
Den fremste fanen endret seg |
on_document_modified_changed |
Flagget for ren eller endret snudde (modified: bool) |
on_text_changed |
Hver endring (position, added_bytes, removed_bytes) — hold den helt enkel |
on_settings_changed |
Innstillingene ble tatt i bruk (scope: "" hele redigereren, "plugins/<id>") |
on_theme_changed |
Temaet ble byttet eller endret (variant) — les fargene fra ctx.theme på nytt |
on_workspace_root_changed |
En arbeidsområdemappe ble åpnet eller lukket (root) |
on_workspace_files_changed |
Arbeidsområdets sett av filer endret seg (files) |
on_host_window_shown |
Én gang per kjøring, etter det første bildet — legg tregt oppstartsarbeid i kø her |
on_app_about_to_quit |
Redigereren lukkes — siste sjanse til å kjøre |
on_command_shortcut_changed |
En kommandos faktiske hurtigtast endret seg (brukerens omtildeling, et importert tastaturoppsett eller en løst konflikt); innhold: command_id, sequence ("" = uten binding) |
Ukjente emnenavn kaster ValueError ved abonneringen. Abonnenter kan kjøre etter den
tilsvarende innebygde behandleren; behandl leveringen av hendelser som opplysende og ikke
som avgjørende.
Å publisere¶
ctx.events.publish(topic, payload) kringkaster til både innebygde og Python-abonnenter —
det tas bare imot for de to arbeidsområdeemnene (workspace.rootChanged,
workspace.filesChanged); alt annet kaster ValueError. Se
Hendelsesdokumentasjonen.
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")
Hvert nivå svarer til vertens ILogger. Linjer får prefikset [python:<plugin.id>], så
utdataene dine kan finnes i redigererens diagnostikklogg:
Bruk aldri print() fra et programtillegg — arbeiderens stdout er RPC-kanalen, og å skrive
til den ødelegger protokollen. ctx.log.* er den eneste godkjente måten å sende ut
diagnostisk tekst på.
status¶
Send en forbigående melding til statuslinjen.
message(str): det som skal vises. Bare korte tekststrenger — statuslinjen har en fast bredde.timeout_ms(int, 0 som standard): hvor lenge den skal bli stående på skjermen;0lar verten velge en fornuftig standard (noen få sekunder).level(str,"info"som standard):"info"/"warning"/"error". Høyere nivåer kan holde tiden på skjermen litt lenger, så en feil ikke straks viskes ut av en rutinemessig info-melding.
ctx.status.show sender og glemmer. Har verten ingen synlig statuslinje (et hodeløst eller
minimalt bygg), kastes kallet i stillhet. ctx.status.clear() fjerner den forbigående
meldingen som står på skjermen.
Varige avsnitt¶
Til levende tilstand (en ordtelling, en tjenerstatus) skal du bruke et avsnitt du eier selv og oppdaterer — det ødelegger aldri en melding, og omvendt:
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 ordner programtilleggenes avsnitt fra venstre mot høyre (lavere = lenger til
venstre; uavgjorte beholder registreringsrekkefølgen). Når et programtillegg stenges ned,
fjernes alt det fortsatt holder.
editor¶
Full synkron tilgang til det aktive dokumentet eller de aktive dokumentene. Hver metode
sperrer den kallende tråden inntil verten svarer (typisk mikrosekunder når arbeideren og
redigereren deler en maskin). Lovlig fra enhver kommando- eller hendelsesbehandler;
aldri fra et async def-tilbakekall (se merknaden om tråder øverst på denne siden).
Å liste dokumenter¶
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
Tilgang til bufferen¶
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 unngår å dra hele bufferen over RPC-en når du bare trenger et stykke —
foretrekk den til sortering og omforming i store filer.
Merking¶
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?
Markør¶
pos = ctx.editor.caret(doc) # mte.EditorPosition(line, column)
ctx.editor.set_caret(doc, mte.EditorPosition(line=7, column=3))
Filhandlinger¶
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 er det ene kallet for «ta brukeren dit» (en byggefeil, en
stakkramme, et søketreff): det åpner filen eller aktiverer fanen dens,
plasserer markøren uten merking, folder ut en bretting som skjuler linjen,
ruller linjen inn i visningen — sentrert når den var utenfor skjermen — og gir
redigereren fokus. Linje og kolonne telles fra 0 (kolonnen i UTF-8-byte) og
avgrenses, avvises aldri; det returnerer dokument-ID-en, eller 0 når filen
ikke kunne åpnes, og da har ingenting flyttet seg. reveal_line viser bare en
linje: det flytter ikke markøren, bytter ikke fane og tar ikke fokus.
Bokmerker, merker og URL-utheving¶
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
Søk¶
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". Se mte.SearchOptions for hele
listen av felter.
Inkrementelt søk (utvid mønsteret mens brukeren skriver, fra et fastholdt anker):
ctx.editor.set_incremental_search_anchor(doc)
hit = ctx.editor.incremental_search(doc, "TOD", opts) # MatchRange
Innrykk og syntaks¶
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
Delt visning og fanegrupper¶
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
Et dokument som vises i to ruter, er ett dokument med én id, så group_of() kan bare
navngi den ene av plassene sine. groups_of() melder dem alle, og
show_document_in_group() lager enda en delt visning — det samme som Vis > Del
dokumentet gjør, så det reises ingen document_opened-hendelse.
ctx.editor speiler nå den innebygde IEditorService én til én.
languages¶
Syntaksfarging er en kjernefunksjon — verten finner ut et dokuments språk og farger det
uten noe programtillegg. ctx.languages lar deg være med: list det verten kjenner, les
eller overstyr et dokuments språk, kjør bestemmelsen på nytt, og bidra med hele
språkdefinisjoner.
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 tar den samme formen som en medfølgende colorizers/*.json-fil (eller en hel
definition=-ordbok): lexer navngir en leksikograf som alt finnes i backenden (verten
får ingen nye leksikografer under kjøringen), styles knytter den leksikografens egne
stilnavn til meningsbærende kategorier, og keywords adresserer ordlistene dens etter
leksikografens egen plassbeskrivelse — verten slår opp begge deler nøyaktig som for en
medfølgende fil, så du aldri staver motorens id-er. Å registrere en id som alt finnes,
erstatter den så lenge du holder behandler-id-en; når programtillegget stenges ned, trekkes
alt det fortsatt holder, tilbake.
document_settings¶
Skrivebeskyttede innstillinger avgrenset til dokumentet, som legger et prosjekts
.editorconfig oppå dine egne ctx.settings. For en nøkkel k og et dokument doc
finner et oppslag mte.<plugin.id>.<k> i den .editorconfig-filen som gjelder for det
dokumentet, faller så tilbake på ctx.settings og deretter på standardverdien din:
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?
Skrivninger går gjennom ctx.settings — aldri tilbake i .editorconfig.
diagnostics¶
Skyv bølgelinjer og margtegn ut for et dokument — fra en statisk analysator, en språkserver
eller en byggelogg. Verten tegner dem; du rører aldri visningen. Å publisere erstatter alt
du tidligere har publisert for det paret av (dokument, kilde), så send hele settet hver
gang:
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 er påkrevd — det er dét som holder settet ditt atskilt fra andre produsenters
(LSP-programtillegget, stavekontrollen) på det samme dokumentet. Alvorsgrader:
SEVERITY_ERROR / SEVERITY_WARNING / SEVERITY_INFORMATION / SEVERITY_HINT.
Posisjoner er halvåpne [start, end)-byteområder.
theme¶
Registrer de fargene ditt eget grensesnitt tegner, som navngitte kategorier som kan inngå i temaer; Temaredigereren lister dem av seg selv, og brukerens overstyringer lagres og leses igjen i temafilen:
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)
Les resolve_color på nytt ved ctx.events.on_theme_changed.
compare¶
Åpne (eller gi fokus til) redigererens sammenligningsvisning side ved side over to kilder.
Hver side er en fil på disken (path=), bokstavelig tekst (content=) eller begge deler
(innholdet vises, og stien gir øktbevaringen en identitet som kan gjenopprettes):
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
Gir False tilbake når en side ikke kan leses.
settings¶
Et varig, typet nøkkel/verdi-lager, avgrenset til plugins/<your.id>/ hos verten. Alle
metodene er synkrone; get og set utledes av standardverdiens Python-type.
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
Typer:
Python-typen til default |
Type på ledningen | Typen get() gir tilbake |
|---|---|---|
bool |
bool |
bool |
int (ikke bool) |
int |
int |
float |
double |
float |
str (eller None) |
string |
str |
Dessuten:
ctx.settings.contains("wrap") # bool
ctx.settings.remove("stale_key")
ctx.settings.sync() # optional; host also syncs on shutdown
Reager på endringer som gjøres i innstillingsvinduet, ved å abonnere på settings.changed
(ctx.events.on_settings_changed; se Hendelsesdokumentasjonen).
app_settings¶
En skrivebeskyttet visning av redigererens oppsett for hele programmet. De velkjente
nøkkelnavnene eksporteres som konstanter i mte.keys (som speiler C++-hodefilen
PluginApi/AppSettingsKeys.h, som blir værende den avgjørende listen):
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"
Settere, remove() og sync() på ctx.app_settings kaster RuntimeError — visningen er
med vilje skrivebeskyttet.
completions¶
Registrer en fullføringsleverandør som er med i redigererens liste:
@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)]
Den innpakkede funksjonen kalles ved hvert tastetrykk (eller ved Ctrl+Mellomrom) der
dokumentet passer til språkfilteret. Felter på req:
| Felt | Type | Betydning |
|---|---|---|
document |
int |
Det dokumentet som redigeres |
prefix |
str |
Det ordstykket som står rett før markøren |
position |
int |
Markørens byteposisjon |
language_id |
str |
Fargeleggerens id ("python", "cpp" …) |
manual |
bool |
True når brukeren trykket Ctrl+Mellomrom; False ved automatisk utløsning |
Gi en liste av mte.CompletionItem tilbake (eller alminnelige tekststrenger eller ordbøker
med {text, detail, kind}). Typer: mte.KIND_KEYWORD / KIND_WORD / KIND_SYMBOL /
KIND_SNIPPET / KIND_UNKNOWN.
Frist
Verten sender leverandøren din en forespørsel per tastetrykk med en frist på omtrent 30 ms. Overskrider tilbakekallet ditt den, vises listen uten kandidatene dine for det tastetrykket. Bygg enhver dyr indeks i bakgrunnen, og svar fra et mellomlager — gjør aldri inn- og utdata i tilbakekallet. Nettverksfullføring i LSP-stil hører hjemme i en framtidig asynkron flate og ikke her.
languages=[] (eller ingenting) betyr «hvert dokument». Flere leverandører per
programtillegg er tillatt; hver dekorator registrerer sin egen.
data_dir¶
Gir den skrivbare mappen per programtillegg tilbake som verten alt har laget for deg. Bruk
den til mellomlagre, indekser og alle data du eier. ctx.diagnostics_dir() gir tilsvarende
den felles mappen for krasj og logger tilbake (skrivebeskyttet for deg — det er
krasjrapporteringen som skriver der).
docks¶
Deklarative dokkpaneler — et sidepanelgrensesnitt bygget av en skjemabeskrivelse og ikke av
Qt-kontroller. Se mte.ui for byggernes ordforråd.
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¶
Registrerer et dokkpanel. Gir panelets id tilbake (tildelt av seg selv når id er None).
id(str, valgfri) — en stabil identifikator somctx.ui.get/ctx.ui.setbruker til å adressere kontroller inne i dette panelet. Gir du ikke en, tildeler verten enpy-dock/N-id og gir den tilbake.title(str) — vises på panelets overskrift.area(str) —"left"/"right"/"top"/"bottom". Ukjente verdier faller tilbake på"right".form(dict) — en beskrivelse bygget medmte.ui-byggerne.initially_visible(bool) — om dokken vises når programtillegget lastes inn.Truesom standard. GiFalsetil et panel som ikke skal sprette fram ved oppstart, og vis det så senere medset_panel_visible.proportional_size(float) — standardstørrelsen til panelet som en andel av hovedvinduet: av bredden i områdene"left"/"right", av høyden i"top"/"bottom".0.0(standardvalget) beholder den pikseloppførselen et verktøypanel vil ha — panelet holder størrelsen sin, og det å endre vindusstørrelsen lar det være. En brøk som0.4er hva en forhåndsvisning vil: det å maksimere vinduet gjør panelet bredere med det. Bare standarden er din; så snart brukeren drar skilleren til panelet, tar verten i bruk og husker andelen deres. Verdier utenfor området klemmes, og verten beholder en minste utstrekning for både panelet og editoren. De fullstendige reglene står underproportionalSize.tab_group(str) — paneler med den samme ikke-tomme gruppe-ID-en i det sammeareadeler én dokk som faner i stedet for å ligge side om side. Gi ID-en et navnerom som en panel-ID ("renamer/panels"). Bare standardoppstillingen: et oppsett brukeren har lagret, går foran. SetabGroup.
ctx.docks.is_panel_visible(handler_id) -> bool¶
Om et panel som er lagt til med add_panel, er åpent — et panel som
ligger som fane bak et annet, regnes som åpent; et som ble registrert med
initially_visible=False og aldri vist, et lukket panel og en ukjent ID gjør
det ikke. Bruk det sammen med set_panel_visible for å vise panelene dine
under en oppgave og så sette tilbake det brukeren hadde:
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)¶
Viser eller skjuler et panel som er lagt til med add_panel. Å vise det løfter også
panelet over de dokkene det deler område med, så en kommando som «åpner» panelet sitt,
virkelig setter det foran brukeren. Kan gjentas — gjenta den samme verdien fritt, det er
ingen tilstand å holde styr på; det ses i stillhet bort fra ved en ukjent id.
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¶
Tildeler en behandler-id for å knytte en kontrolls on_change-felt til en Python-funksjon.
Tilbakekallet mottar den nye verdien som en tekststreng; boolske kontroller leverer
"true" / "false", og tallkontroller leverer heltallet som en tekststreng.
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)])
Behandler-id-er for on_change har prefikset py-dock-cb/N og kolliderer aldri med
behandler-id-er for kommandoer, hendelser eller fullføringer.
Tilbakekallet kalles på arbeiderens hendelsesløkke og IKKE på trådpuljen — hold det raskt.
Bruk ctx.log, endre en liten tilstand i minnet, eller utløs en oppfølgende kommando; gjør
ikke tungt arbeid her.
line_markers¶
Margsymboler og farging av hele linjer, festet til dokumentlinjer som følger brukerens redigeringer — stoppunkter, en pil for gjeldende setning, endringsstriper — og kravet på klikket i bokmerkekolonnen. Den innebygde tjenesten og alle reglene dens er beskrevet under Linjemerker og margklikk.
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=)—glypher en avmte.GLYPH_NONE(bare farging),GLYPH_CIRCLE,GLYPH_CIRCLE_HOLLOW,GLYPH_CIRCLE_BAR,GLYPH_ARROW,GLYPH_STRIP; fargene er ID-er for kategorier du har registrert medctx.theme. Redigereren har bare noen få merkeplasser for alle programtillegg til sammen, så dette kan mislykkes — da kastesRpcError. Registrer typene dine én gang, iregister().add_marker(kind, doc, line)— linje talt fra 0, ikke avgrenset: en linje utenfor dokumentet returnerer 0 og plasserer ingenting.- Merker flytter seg med linjene sine, overlever en ny innlasting på samme
linjenummer og forsvinner med dokumentet sitt — legg til dine igjen i
ctx.events.on_document_opened.
Margklikket¶
@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()
Hvert venstreklikk i bokmerkekolonnen publiseres som margin.clicked
(document, line, margin = "symbol", modifiers — biter
mte.MODIFIER_SHIFT / MODIFIER_CONTROL / MODIFIER_ALT /
MODIFIER_META). Som standard slår redigereren også et bokmerke av eller på
ved klikket; så lenge et programtillegg holder claim_margin_click(), gjør
den ikke det og overlater klikket til programtilleggene.
ctx.line_markers.release(claim) gir klikket tilbake.
settings_page¶
Legger til en side under redigererens innstillingsvindu. Samme ordforråd for
skjemabeskrivelser som dokkpaneler; samme bevaring med 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, påkrevd) — en sti med skråstreker i innstillingstreet, for eksempel"Plugins/My Plugin". Nøstede kategorier kommer fram som noder i treet.title(str, påkrevd) — den overskriften som vises over siden.form(dict, påkrevd) — en beskrivelse bygget medmte.ui-byggerne.scope(str, valgfri) — det hendelsesomfanget som sendes ut vedSettingsChanged, etter at brukeren har trykket OK eller Bruk.
Gir behandler-id-en tilbake.
Avbryt ruller IKKE tilbake endringene
Kontroller med binds="settings:<key>" lagres med det samme mens brukeren
redigerer, så et trykk på Avbryt i innstillingsvinduet angrer dem ikke. Det er en
kjent begrensning i fase 3; en senere forfining vil legge de underliggende
innstillingene bak et mellomledd med buffer.
ui¶
Leser og skriver kontrollers verdier inne i paneler du alt har registrert. Verdier er alltid tekststrenger på ledningen.
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]¶
Leser en kontrolls gjeldende verdi. Gir None tilbake når panelet eller kontrollen er
ukjent (ikke en feil — behandl både None og "" som «tom»).
- Label / Button / LineEdit / ComboBox — gir teksten tilbake.
- Checkbox — gir
"true"eller"false"tilbake. - NumberSpin — gir heltallet tilbake som en desimaltekststreng.
- List — gir teksten på den merkede posten tilbake (tom når ingenting er merket).
ctx.ui.set(panel_id, control_id, value) -> bool¶
Skriver en verdi inn i en kontroll programmatisk. Gir True tilbake når skrivningen
lyktes, og False når panelet eller kontrollen er ukjent, eller verdien ikke kan omformes
(for eksempel et tall som ikke er et heltall, sendt til en NumberSpin).
Pythons True / False gjøres om til "true" / "false" før de sendes; alt annet går
gjennom str().
Et set fra verten utløser IKKE kontrollens on_change på nytt, så du kan oppdatere dine
egne kontroller fra en kommandobehandler uten uendelige løkker.
Sammendrag av bindinger under kjøringen (fase 3)¶
| Felt i skjemabeskrivelsen | Oppførsel under kjøringen |
|---|---|
id="…" |
Adresser kontrollen fra ctx.ui.get / ctx.ui.set. |
binds="settings:<key>" |
Leser startverdien fra ctx.settings; skriver tilbake ved hver endring fra brukeren. |
on_click="<cmd>" |
Knapper kaller den registrerte kommando-id-en ved et klikk. |
on_change=behandler |
Utløser det tilbakekallet som er registrert gjennom ctx.docks.on_change(...), ved en endring fra brukeren. |
De samme reglene gjelder for dokkpaneler og innstillingssider.