ctx — udvidelsesmodulets kontekst¶
register(ctx) modtager ét argument: en PluginContext. Den blotlægger tjenesterne
nedenfor (hele den IPluginContext-flade, der passer til modellen med en selvstændig
proces). Hver er en lille Python-klasse, som arbejderen bygger oven på 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 dele af den indbyggede kontrakt har endnu ingen modpart i Python: hover-leverandører (så prioritetsbåndene for hover gælder ikke for Python-moduler) og leverandører til editorens kontekstmenu (så heller ikke kontekstmenuens område tekst / margen). Begge besvares, mens brugeren venter, og det kræver den samme behandling med frister, som fuldførelsesleverandørerne har, før en rundtur til arbejderen er tryg.
Gem ikke ctx i en global variabel i forventning om at bruge den senere — selv om
attributterne er stabile udvidelsesmodulets liv ud, så behandl ctx som noget, der
hører til registreringen. Behold henvisninger til de enkelte tjenester, hvis du har
brug for dem (log = ctx.log, for eksempel).
commands¶
En dekorator, der registrerer en kommando og binder den indpakkede funktion som dens håndtering.
id(str, påkrævet): en entydig identifikator i omvendt DNS-stil (f.eks."wordcount.count"). Samme regler som iplugin.json— skal være globalt entydig.title(str, påkrævet): den læsbare mærkat, der vises overalt, hvor kommandoen kommer til syne (menuer, kommandopaletten).shortcut(str, valgfri): den flytbare standardgenvejstast, f.eks."Ctrl+Alt+W".Ctrloversættes af sig selv til platformens primære modifikator (Cmdpå macOS). Lad den stå tom for ingen. Brugeren kan tildele den en anden tast eller slet ingen under Indstillinger ▸ Genvejstaster; for menubundne kommandoer anvender værten omtildelingen for dig.category(str, valgfri): en frit formuleret grupperingsmærkat — vises som kommandoens kategori i genvejstastoversigten.scope(str, valgfri):""/"application"(standard — værten binder genvejstasten på kommandoens menuhandling) eller"pluginWindow"for tastekombinationer, der hører hjemme i en brugerflade, udvidelsesmodulet ejer: værten opregner kun kommandoen i oversigten; læsctx.commands.effective_shortcut(id), når du bygger dine kontroller, og anvend den igen ved hændelsen"command.shortcutChanged".
Den genvejstast, der faktisk gælder efter brugerens omtildeling og løsningen af
konflikter ("" = uden tildeling eller ukendt). Trygt at kalde fra håndteringer.
Den indpakkede funktion tager ingen argumenter og giver ingenting tilbage. Undtagelser inde i den opfanges af arbejderen og noteres til stderr; de får ikke editoren til at gå ned.
@ctx.commands.command(id="wordcount.count",
title="Count Words",
shortcut="Ctrl+Alt+W",
category="Text")
def _count():
ctx.status.show("counted")
Under motorhjelmen: Python-siden tildeler et handlerId lokalt, registrerer
tilbagekaldet på RPC-forbindelsen og sender commands.registerCommand til værten. Når
brugeren aktiverer kommandoen (et menuklik, genvejstasten, paletten), sender værten et
callback-RPC, og din funktion kører.
Kommando-id'er gælder for hele processen og ikke pr. udvidelsesmodul. Sæt dit
omvendte DNS-navnerum foran dine id'er (wordcount.…) for at undgå sammenstød.
menus¶
Menustier bruger / som skilletegn. Det yderste venstre led er en øverste menu
(Plugins, Tools …); mellemliggende led opretter undermenuer efter behov; det sidste
led er punktets mærkat.
ctx.menus.add_item(path, command_id)¶
path(str):"Øverst/Under/…/Mærkat". Mellemliggende undermenuer oprettes, hvis de ikke findes.command_id(str): id'et på en tidligere registreret kommando. Et klik på punktet kalder kommandoen.
Giver en uigennemsigtig handlerId-tekststreng tilbage. Behold den, hvis du senere får
brug for at unsubscribe punktet (sjældent i fase 1).
Det yderste venstre led ("Plugins" ovenfor) skal passe til title i en af dine
menus[]-poster i plugin.json, så placeringen på menulinjen kommer med.
ctx.menus.add_separator(path)¶
Indsætter en skillelinje i en eksisterende undermenu.
ctx.menus.set_item_checked(handler_id, checked)¶
Gør det tidligere tilføjede punkt til et afkrydseligt menupunkt og sætter dets tilstand — det sædvanlige idiom for en vedvarende til/fra-kontakt, der viser et synligt flueben.
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 kald gør punktet afkrydseligt; de følgende kald vender bare fluebenet. At
give et handler_id, værten ikke kender, gør i stilhed ingenting (trygt at kalde,
efter at dit symbol er droppet, f.eks. fra et forsinket tilbagekald, der udløses under
nedlukningen).
ctx.menus.set_item_enabled(handler_id, enabled)¶
Slår et tidligere tilføjet punkt til eller nedtoner det. Brug den, når kommandoen kræver en forudsætning — noget at lukke, noget at gendanne — så menuen viser, at den ikke er tilgængelig, i stedet for at tilbyde en post, der i stilhed ikke gør noget.
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)
Et frakoblet punkt bliver ved med at være synligt, men kan ikke udløses, hverken med et
klik eller med sin genvejstast. Kaldet kan gentages, så du aldrig behøver at huske den
forrige tilstand, og et ukendt handler_id gør i stilhed ingenting som ovenfor.
Punkter begynder tilkoblede: ét kald lige efter add_item sætter et punkt op, der ikke
er tilgængeligt ved opstart.
events¶
Abonnér på editorhændelser. To ligeværdige API'er — de lette dekoratorer anbefales;
den rå subscribe() er der, hvis du vil beregne emnet under kørslen.
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 indpakkede funktion tager ét argument: en typet dataklasse, der svarer til emnet. Se Hændelsesdokumentationen for hele tabellen over emne ↔ dataklasse.
Den rå API¶
handler_id = ctx.events.subscribe("document.saved", _saved)
# later:
ctx.events.unsubscribe(handler_id)
Tilgængelige lette egenskaber (alle sammen dekoratorer):
| Egenskab | Udløses ved |
|---|---|
on_document_opened |
Et dokument blev åbnet i et faneblad |
on_document_closed |
Et dokument blev lukket |
on_document_saved |
Et dokument blev skrevet til disken |
on_selection_changed |
Markøren eller markeringen flyttede sig i det aktive dokument |
on_active_document_changed |
Det forreste faneblad skiftede |
on_document_modified_changed |
Flaget for ren eller ændret vendte (modified: bool) |
on_text_changed |
Hver ændring (position, added_bytes, removed_bytes) — hold den ganske enkel |
on_settings_changed |
Indstillingerne blev anvendt (scope: "" hele editoren, "plugins/<id>") |
on_theme_changed |
Temaet blev skiftet eller redigeret (variant) — læs farverne fra ctx.theme igen |
on_workspace_root_changed |
En arbejdsområdemappe blev åbnet eller lukket (root) |
on_workspace_files_changed |
Arbejdsområdets sæt af filer ændrede sig (files) |
on_host_window_shown |
Én gang pr. kørsel, efter det første billede — læg langsomt opstartsarbejde i kø her |
on_app_about_to_quit |
Editoren lukker — sidste chance for at køre |
on_command_shortcut_changed |
En kommandos faktiske genvejstast ændrede sig (brugerens omtildeling, en importeret tastaturopsætning eller en løst konflikt); indhold: command_id, sequence ("" = uden tildeling) |
Ukendte emnenavne kaster ValueError ved abonneringen. Abonnenter kan køre efter
den tilsvarende indbyggede håndtering; behandl leveringen af hændelser som oplysende og
ikke som afgørende.
At udgive¶
ctx.events.publish(topic, payload) udsender til både indbyggede og
Python-abonnenter — der tages kun imod de to emner om arbejdsområdet
(workspace.rootChanged, workspace.filesChanged); alt andet kaster ValueError. Se
Hændelsesdokumentationen.
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 niveau svarer til værtens ILogger. Linjer får præfikset
[python:<plugin.id>], så dit output kan findes i editorens diagnostiklog:
Brug aldrig print() fra et udvidelsesmodul — arbejderens stdout er RPC-kanalen, og at
skrive til den ødelægger protokollen. ctx.log.* er den eneste godkendte måde at
udsende diagnostisk tekst på.
status¶
Send en forbigående meddelelse til statuslinjen.
message(str): det, der skal vises. Kun korte tekststrenge — statuslinjen har en fast bredde.timeout_ms(int, 0 som standard): hvor længe den skal blive stående på skærmen;0lader værten vælge en fornuftig standard (nogle få sekunder).level(str,"info"som standard):"info"/"warning"/"error". Højere niveauer kan holde tiden på skærmen lidt længere, så en fejl ikke øjeblikkeligt viskes ud af en rutinemæssig info-besked.
ctx.status.show sender og glemmer. Har værten ingen synlig statuslinje (en hovedløs
eller minimal bygning), kasseres kaldet i stilhed. ctx.status.clear() fjerner den
forbigående meddelelse, der står på skærmen.
Vedvarende afsnit¶
Til levende tilstand (et ordtal, en serverstatus) skal du bruge et afsnit, du selv ejer og opdaterer — det ødelægger aldrig en meddelelse, 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 modulernes afsnit fra venstre mod højre (lavere = længere til
venstre; uafgjorte beholder registreringsrækkefølgen). Når et udvidelsesmodul lukkes
ned, fjernes alt, det stadig holder.
editor¶
Fuld synkron adgang til det aktive dokument eller de aktive dokumenter. Hver metode
spærrer den kaldende tråd, indtil værten svarer (typisk mikrosekunder, når arbejderen
og editoren deler en maskine). Lovligt fra enhver kommando- eller hændelseshåndtering;
aldrig fra et async def-tilbagekald (se bemærkningen om tråde øverst på denne
side).
At opregne 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
Adgang 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 undgår at trække hele bufferen over RPC'en, når du kun har brug for et
stykke — foretræk den til sortering og omdannelse i store filer.
Markering¶
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 kald til »tag brugeren derhen« (en byggefejl, en
stakramme, et søgeresultat): det åbner filen eller aktiverer dens faneblad,
placerer markøren uden markering, folder en foldning ud, der skjuler linjen,
ruller linjen ind i visningen — centreret, når den var uden for skærmen — og
giver editoren fokus. Linje og kolonne tælles fra 0 (kolonnen i UTF-8-byte)
og afgrænses, afvises aldrig; det returnerer dokument-id'et, eller 0, når
filen ikke kunne åbnes, og så har intet flyttet sig. reveal_line viser kun
en linje: det flytter ikke markøren, skifter ikke faneblad og tager ikke
fokus.
Bogmærker, markeringer og URL-fremhævning¶
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øgning¶
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 af felter.
Trinvis søgning (udvid mønsteret, mens brugeren skriver, fra et fastholdt anker):
ctx.editor.set_incremental_search_anchor(doc)
hit = ctx.editor.incremental_search(doc, "TOD", opts) # MatchRange
Indrykning 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
Opdelt visning og fanebladsgrupper¶
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, der vises i to ruder, er ét dokument med ét id, så group_of() kan kun
navngive den ene af dets pladser. groups_of() melder dem alle sammen, og
show_document_in_group() opretter endnu en delt visning — det samme, som
Vis > Opdel dokumentet til højre gør, så der rejses ingen
document_opened-hændelse.
ctx.editor afspejler nu den indbyggede IEditorService én til én.
languages¶
Syntaksfarvning er en kernefunktion — værten afgør et dokuments sprog og farver det
uden noget udvidelsesmodul. ctx.languages lader dig være med: opregn, hvad værten
kender, læs eller tilsidesæt et dokuments sprog, kør bestemmelsen igen og bidrag med
hele sprogdefinitioner.
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 tager den samme form som en medleveret colorizers/*.json-fil (eller en hel
definition=-ordbog): lexer navngiver en eksisterende backend-lexer (værten får ingen
nye lexere under kørslen), styles knytter den lexers egne stilnavne til semantiske
kategorier, og keywords adresserer dens ordlister efter lexerens egen
pladsbeskrivelse — værten slår begge dele op præcis som for en medleveret fil, så du
aldrig staver motorens id'er. At registrere et id, der allerede findes, erstatter det,
så længe du holder på håndterings-id'et; når udvidelsesmodulet lukkes ned, trækkes alt,
det stadig holder, tilbage.
document_settings¶
Skrivebeskyttede indstillinger, der er afgrænset til dokumentet, og som lægger et
projekts .editorconfig oven på dine egne ctx.settings. For en nøgle k og et
dokument doc finder et opslag mte.<plugin.id>.<k> i den .editorconfig, der gælder
for det dokument, falder derefter tilbage på ctx.settings og derefter på din
standardværdi:
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 gennem ctx.settings — aldrig tilbage i .editorconfig.
diagnostics¶
Skub bølgelinjer og margentegn ud for et dokument — fra en statisk analysator, en
sprogserver eller en byggelog. Værten tegner dem; du rører aldrig visningen. At udgive
erstatter alt, du tidligere har udgivet for det par af (dokument, kilde), så send hele
sættet 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åkrævet — det er dét, der holder dit sæt adskilt fra andre producenters
(LSP-udvidelsesmodulet, stavekontrollen) på det samme dokument. Alvorsgrader:
SEVERITY_ERROR / SEVERITY_WARNING / SEVERITY_INFORMATION / SEVERITY_HINT.
Positioner er halvåbne [start, end)-byteområder.
theme¶
Registrér de farver, din egen brugerflade tegner, som navngivne kategorier, der kan indgå i temaer; Temaeditoren opregner dem af sig selv, og brugerens tilsidesættelser gemmes og læses igen 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)
Læs resolve_color igen ved ctx.events.on_theme_changed.
compare¶
Åbn (eller fokusér) editorens sammenligningsvisning side om side over to kilder. Hver
side er en fil på disken (path=), bogstavelig tekst (content=) eller begge dele
(indholdet vises, og stien giver sessionsbevaringen en identitet, der kan gendannes):
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
Giver False tilbage, når en side ikke kan læses.
settings¶
Et vedvarende typet nøgle/værdi-lager, afgrænset til plugins/<your.id>/ hos værten.
Alle metoder er synkrone; get og set udledes af standardværdiens 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 for default |
Type på ledningen | Den type, get() giver tilbage |
|---|---|---|
bool |
bool |
bool |
int (ikke bool) |
int |
int |
float |
double |
float |
str (eller None) |
string |
str |
Desuden:
ctx.settings.contains("wrap") # bool
ctx.settings.remove("stale_key")
ctx.settings.sync() # optional; host also syncs on shutdown
Reagér på ændringer, der er lavet i indstillingsvinduet, ved at abonnere på
settings.changed (ctx.events.on_settings_changed; se
Hændelsesdokumentationen).
app_settings¶
En skrivebeskyttet visning af editorens opsætning for hele programmet. De velkendte
nøglenavne eksporteres som konstanter i mte.keys (som afspejler C++-headerfilen
PluginApi/AppSettingsKeys.h, der bliver ved med at være den afgørende liste):
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"
Sættere, remove() og sync() på ctx.app_settings kaster RuntimeError — visningen
er med vilje skrivebeskyttet.
completions¶
Registrér en fuldførelsesleverandør, der er med i editorens 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 indpakkede funktion kaldes ved hvert tastetryk (eller ved Ctrl+Mellemrum), hvis
dokument passer til sprogfilteret. Felter på req:
| Felt | Type | Betydning |
|---|---|---|
document |
int |
Det dokument, der redigeres |
prefix |
str |
Det ordstykke, der står umiddelbart før markøren |
position |
int |
Markørens byteposition |
language_id |
str |
Farvelæggerens id ("python", "cpp" …) |
manual |
bool |
True, når brugeren trykkede Ctrl+Mellemrum; False ved automatisk udløsning |
Giv en liste af mte.CompletionItem tilbage (eller almindelige tekststrenge eller
ordbøger med {text, detail, kind}). Typer: mte.KIND_KEYWORD / KIND_WORD /
KIND_SYMBOL / KIND_SNIPPET / KIND_UNKNOWN.
Frist
Værten sender din leverandør en forespørgsel pr. tastetryk med en frist på cirka 30 ms. Overskrider dit tilbagekald den, vises listen uden dine kandidater for det tastetryk. Byg ethvert dyrt indeks i baggrunden, og svar fra et mellemlager — lav aldrig ind- og uddata i tilbagekaldet. Netværksfuldførelse i LSP-stil hører hjemme i en fremtidig asynkron flade og ikke her.
languages=[] (eller ingenting) betyder »hvert dokument«. Flere leverandører pr.
udvidelsesmodul er tilladt; hver dekorator registrerer sin egen.
data_dir¶
Giver den skrivbare mappe pr. udvidelsesmodul tilbage, som værten allerede har oprettet
til dig. Brug den til mellemlagre, indekser og alle data, du ejer.
ctx.diagnostics_dir() giver tilsvarende den fælles mappe til nedbrud og logfiler
tilbage (skrivebeskyttet for dig — det er nedbrudsrapporteringen, der skriver der).
docks¶
Deklarative dokpaneler — en sidepanelbrugerflade bygget af en formularbeskrivelse og
ikke af 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 dokpanel. Giver panelets id tilbage (tildelt af sig selv, når id er
None).
id(str, valgfri) — en stabil identifikator, somctx.ui.get/ctx.ui.setbruger til at adressere kontroller inde i dette panel. Giver du ikke en, tildeler værten etpy-dock/N-id og giver det tilbage.title(str) — vises på panelets overskrift.area(str) —"left"/"right"/"top"/"bottom". Ukendte værdier falder tilbage på"right".form(dict) — en beskrivelse bygget medmte.ui-byggerne.initially_visible(bool) — om panelet vises, når udvidelsesmodulet indlæses.Truesom standard. GivFalsetil et panel, der ikke skal springe frem ved opstart, og vis det senere medset_panel_visible.proportional_size(float) — panelets standardstørrelse som en andel af hovedvinduet: af bredden i områderne"left"/"right", af højden i"top"/"bottom".0.0(standardvalget) bevarer den pixelopførsel, et værktøjspanel vil have — panelet holder sin størrelse, og det at ændre vinduets størrelse lader det være. En brøk som0.4er, hvad en forhåndsvisning vil: det at maksimere vinduet gør panelet bredere med det. Kun standarden er din; så snart brugeren trækker panelets deler, tager værten deres andel i brug og husker den. Værdier uden for intervallet klemmes, og værten bevarer en mindste udstrækning for både panelet og editoren. De fulde regler står underproportionalSize.tab_group(str) — paneler med det samme ikke-tomme gruppe-id i det sammeareadeler én dok som faneblade i stedet for at ligge side om side. Giv det et navnerum som et panel-id ("renamer/panels"). Kun standardopstillingen: et layout, som brugeren har gemt, går forud. SetabGroup.
ctx.docks.is_panel_visible(handler_id) -> bool¶
Om et panel, der er tilføjet med add_panel, er åbent — et panel, der
ligger som faneblad bag et andet, tæller som åbent; et, der blev registreret
med initially_visible=False og aldrig vist, et lukket panel og et ukendt id
gør ikke. Brug det sammen med set_panel_visible til at vise dine paneler
under en opgave og bagefter sætte det tilbage, som brugeren havde:
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, der er tilføjet med add_panel. At vise det løfter også
panelet op over de paneler, det deler område med, så en kommando, der »åbner« sit panel,
virkelig sætter det foran brugeren. Kan gentages — gentag den samme værdi frit, der er
ingen tilstand at holde styr på; ses der i stilhed bort fra ved et ukendt 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 et håndterings-id til at knytte en kontrols on_change-felt til en
Python-funktion. Tilbagekaldet modtager den nye værdi som en tekststreng; boolske
kontroller leverer "true" / "false", og talkontroller 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)])
Håndterings-id'er til on_change har præfikset py-dock-cb/N og støder aldrig sammen
med håndterings-id'er til kommandoer, hændelser eller fuldførelser.
Tilbagekaldet kaldes på arbejderens hændelsesløkke og IKKE på trådpuljen — hold det
hurtigt. Brug ctx.log, ændr en lille tilstand i hukommelsen, eller udløs en
efterfølgende kommando; lav ikke tungt arbejde her.
line_markers¶
Margensymboler og farvning af hele linjer, fæstnet til dokumentlinjer, der følger brugerens redigeringer — stoppunkter, en pil for den aktuelle sætning, ændringsstriber — og kravet på klikket i bogmærkekolonnen. Den indbyggede tjeneste og alle dens regler er beskrevet under Linjemærker og margenklik.
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 afmte.GLYPH_NONE(kun farvning),GLYPH_CIRCLE,GLYPH_CIRCLE_HOLLOW,GLYPH_CIRCLE_BAR,GLYPH_ARROW,GLYPH_STRIP; farverne er id'er på kategorier, du har registreret medctx.theme. Editoren har kun få mærkepladser til alle udvidelsesmoduler tilsammen, så dette kan mislykkes — så kastesRpcError. Registrér dine typer én gang, iregister().add_marker(kind, doc, line)— linje talt fra 0, ikke afgrænset: en linje uden for dokumentet returnerer 0 og placerer intet.- Mærker flytter sig med deres linjer, overlever en genindlæsning på samme
linjenummer og forsvinder med deres dokument — tilføj dine igen i
ctx.events.on_document_opened.
Margenklikket¶
@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 venstreklik i bogmærkekolonnen udgives som margin.clicked
(document, line, margin = "symbol", modifiers — bits
mte.MODIFIER_SHIFT / MODIFIER_CONTROL / MODIFIER_ALT /
MODIFIER_META). Som standard slår editoren også et bogmærke til eller fra
ved klikket; så længe et modul holder claim_margin_click(), gør den det
ikke og overlader klikket til modulerne. ctx.line_markers.release(claim)
giver klikket tilbage.
settings_page¶
Tilføjer en side under editorens indstillingsvindue. Samme ordforråd til
formularbeskrivelser som dokpaneler; 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åkrævet) — en sti med skråstreger i indstillingstræet, f.eks."Plugins/My Plugin". Indlejrede kategorier kommer frem som knuder i træet.title(str, påkrævet) — den overskrift, der vises over siden.form(dict, påkrævet) — en beskrivelse bygget medmte.ui-byggerne.scope(str, valgfri) — det hændelsesomfang, der udsendes vedSettingsChanged, efter at brugeren har trykket OK eller Anvend.
Giver håndterings-id'et tilbage.
Annullér ruller IKKE ændringer tilbage
Kontroller med binds="settings:<key>" gemmer med det samme, mens brugeren
redigerer, så et tryk på Annullér i indstillingsvinduet fortryder dem ikke. Det
er en kendt begrænsning i fase 3; en senere forfining vil lægge de underliggende
indstillinger bag et mellemled med buffer.
ui¶
Læser og skriver kontrollers værdier inde i paneler, du allerede har registreret. Værdier er altid tekststrenge 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]¶
Læser en kontrols nuværende værdi. Giver None tilbage, når panelet eller kontrollen
er ukendt (ikke en fejl — behandl både None og "" som »tom«).
- Label / Button / LineEdit / ComboBox — giver teksten tilbage.
- Checkbox — giver
"true"eller"false"tilbage. - NumberSpin — giver heltallet tilbage som en decimaltekststreng.
- List — giver teksten på den markerede post tilbage (tom, når intet er markeret).
ctx.ui.set(panel_id, control_id, value) -> bool¶
Skriver en værdi ind i en kontrol programmatisk. Giver True tilbage, når skrivningen
lykkedes, og False, når panelet eller kontrollen er ukendt, eller værdien ikke kan
omformes (f.eks. et tal, der ikke er et heltal, sendt til en NumberSpin).
Pythons True / False omsættes til "true" / "false", inden de sendes; alt andet
går gennem str().
Et set fra værten udløser IKKE kontrollens on_change-tilbagekald igen, så du kan
opdatere dine egne kontroller fra en kommandohåndtering uden uendelige løkker.
Sammendrag af bindinger under kørslen (fase 3)¶
| Felt i formularbeskrivelsen | Adfærd under kørslen |
|---|---|
id="…" |
Adressér kontrollen fra ctx.ui.get / ctx.ui.set. |
binds="settings:<key>" |
Læser udgangsværdien fra ctx.settings; skriver tilbage ved hver ændring fra brugeren. |
on_click="<cmd>" |
Knapper kalder det registrerede kommando-id ved et klik. |
on_change=håndtering |
Udløser det tilbagekald, der er registreret via ctx.docks.on_change(...), ved en ændring fra brugeren. |
De samme regler gælder for dokpaneler og indstillingssider.