Hyppää sisältöön

ctx — liitännäisen konteksti

register(ctx) vastaanottaa yhden argumentin: PluginContext-olion. Se paljastaa alla olevat palvelut (koko IPluginContext-pinnan, joka sopii prosessin ulkopuoliseen malliin). Kukin on pieni Python-luokka, jonka työntekijä rakentaa RPC-kanavan päälle; lähdekoodi on 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

Kahdella natiivin sopimuksen osalla ei vielä ole Python-vastinetta: hover-toimittajilla (joten hoverin prioriteettikaistat eivät koske Python-liitännäisiä) ja editorin kontekstivalikon toimittajilla (joten ei myöskään kontekstivalikon alue teksti / marginaali). Molempiin vastataan käyttäjän odottaessa, mikä vaatii saman määräaikakäsittelyn kuin täydennystoimittajilla on, ennen kuin edestakainen matka työntekijälle on turvallinen.

Älä säilytä ctx-oliota globaalissa muuttujassa odottaen käyttäväsi sitä myöhemmin — vaikka attribuutit ovat vakaat liitännäisen elinajan, käsittele ctx-oliota rekisteröintikohtaisena. Säilytä viittaukset niihin yksittäisiin palveluihin, joita tarvitset (esimerkiksi log = ctx.log).


commands

ctx.commands.command(*, id, title, shortcut="", category="", scope="")

Koriste, joka rekisteröi komennon ja sitoo käärityn funktion sen käsittelijäksi.

  • id (str, pakollinen): käänteisen DNS:n tyylinen yksilöllinen tunniste (esimerkiksi "wordcount.count"). Samat säännöt kuin tiedostossa plugin.json — täytyy olla globaalisti yksilöllinen.
  • title (str, pakollinen): ihmisluettava nimiö, joka näkyy kaikkialla, missä komento tulee esiin (valikot, komentopaletti).
  • shortcut (str, valinnainen): siirrettävä oletuspikanäppäinmerkkijono, esimerkiksi "Ctrl+Alt+W". Ctrl kuvautuu automaattisesti alustan ensisijaiseen muuntonäppäimeen (Cmd macOS:ssä). Jätä tyhjäksi, jos pikanäppäintä ei ole. Käyttäjä voi määrittää sen uudelleen tai poistaa sen määrityksen kohdassa Asetukset ▸ Pikanäppäimet; valikkoon sidottujen komentojen osalta isäntä ottaa uudelleenmäärityksen käyttöön puolestasi.
  • category (str, valinnainen): vapaamuotoinen ryhmittelynimiö — näytetään komennon luokkana pikanäppäinten määrityksessä.
  • scope (str, valinnainen): ""/"application" (oletus — isäntä sitoo pikanäppäimen komennon valikkotoimintoon) tai "pluginWindow" niille yhdistelmille, jotka sijaitsevat liitännäisen omistamassa käyttöliittymässä: isäntä vain luettelee komennon määrityksessä; lue ctx.commands.effective_shortcut(id) rakentaessasi ohjausobjektejasi ja ota se uudelleen käyttöön tapahtumassa "command.shortcutChanged".
ctx.commands.effective_shortcut(command_id) -> str

Se pikanäppäin, joka on tällä hetkellä voimassa käyttäjän uudelleenmäärityksen ja ristiriitojen ratkaisun jälkeen ("" = ilman määritystä tai tuntematon). Turvallinen kutsua käsittelijöistä.

Kääritty funktio ei ota argumentteja eikä palauta mitään. Sen sisäiset poikkeukset nappaa työntekijä ja kirjaa ne stderriin; ne eivät kaada editoria.

@ctx.commands.command(id="wordcount.count",
                      title="Count Words",
                      shortcut="Ctrl+Alt+W",
                      category="Text")
def _count():
    ctx.status.show("counted")

Konepellin alla: Python-puoli varaa tunnisteen handlerId paikallisesti, rekisteröi takaisinkutsun RPC-yhteyteen ja lähettää kutsun commands.registerCommand isännälle. Kun käyttäjä aktivoi komennon (valikkonapsautus, pikanäppäin, paletti), isäntä lähettää callback-RPC:n ja funktiosi ajetaan.

Komentotunnisteet ovat prosessinlaajuisia eivätkä liitännäiskohtaisia. Lisää käänteinen DNS-nimiavaruutesi tunnisteidesi eteen (wordcount.…) välttääksesi törmäykset.


Valikkopolut käyttävät merkkiä / erottimena. Vasemmanpuoleisin osa on ylimmän tason valikko (Plugins, Tools …); väliosat luovat alivalikot tarvittaessa; viimeinen osa on kohdan nimiö.

ctx.menus.add_item(path, command_id)

ctx.menus.add_item("Plugins/Word Count/Count", "wordcount.count")
  • path (str): "Ylin/Ali/…/Nimiö". Välialivalikot luodaan tarvittaessa.
  • command_id (str): aiemmin rekisteröidyn komennon tunniste. Kohdan napsauttaminen kutsuu komentoa.

Palauttaa läpinäkymättömän handlerId-merkkijonon. Säilytä se, jos joudut myöhemmin kutsumaan kohteelle funktiota unsubscribe (harvinaista vaiheessa 1).

Vasemmanpuoleisimman osan ("Plugins" yllä) täytyy vastata jonkin menus[]-kohtasi kenttää title tiedostossa plugin.json, jotta valikkopalkkisijainti poimitaan.

ctx.menus.add_separator(path)

ctx.menus.add_separator("Plugins/Word Count")

Lisää erottimen olemassa olevaan alivalikkoon.

ctx.menus.set_item_checked(handler_id, checked)

Muuttaa aiemmin lisätyn kohdan valittavaksi valikkokohdaksi ja asettaa sen valintatilan — vakioidiomi pysyvälle päälle/pois-kytkimelle, joka näyttää näkyvän valintamerkin.

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)

Ensimmäinen kutsu tekee kohdasta valittavan; seuraavat kutsut vain kääntävät merkin. Sellaisen tunnisteen handler_id välittäminen, jota isäntä ei tunne, ei tee hiljaisesti mitään (turvallista kutsua sen jälkeen, kun polettisi on pudotettu, esimerkiksi viivästyneestä takaisinkutsusta sammutuksen aikana).

ctx.menus.set_item_enabled(handler_id, enabled)

Ottaa aiemmin lisätyn kohdan käyttöön tai harmaannuttaa sen. Käytä sitä, kun komento tarvitsee edellytyksen — jotain suljettavaa, jotain palautettavaa — jotta valikko näyttää, ettei se ole käytettävissä, sen sijaan että tarjoaisi kohtaa, joka ei hiljaisesti tee mitään.

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)

Käytöstä poistettu kohta pysyy näkyvissä muttei ole käynnistettävissä, ei napsautuksella eikä pikanäppäimellään. Kutsu on idempotentti, joten sinun ei tarvitse koskaan muistaa edellistä tilaa, ja tuntematon handler_id ei tee hiljaisesti mitään, kuten yllä. Kohdat alkavat käytössä olevina: yksi kutsu heti funktion add_item jälkeen valmistelee kohdan, joka ei ole käytettävissä käynnistyksessä.


events

Tilaa editoritapahtumia. Kaksi vastaavaa API:ta — kevyitä koristeita suositellaan; raaka subscribe() on saatavilla, jos haluat laskea aiheen ajon aikana.

Kevyet koristeet

@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}")

Kääritty funktio ottaa yhden argumentin: aihetta vastaavan tyypitetyn dataluokan. Katso koko aihe ↔ dataluokka -taulukko kohdasta Tapahtumadokumentaatio.

Raaka API

handler_id = ctx.events.subscribe("document.saved", _saved)
# later:
ctx.events.unsubscribe(handler_id)

Käytettävissä olevat kevyet ominaisuudet (kaikki koristeita):

Ominaisuus Laukeaa
on_document_opened Asiakirja avattiin välilehdessä
on_document_closed Asiakirja suljettiin
on_document_saved Asiakirja kirjoitettiin levylle
on_selection_changed Kohdistin tai valinta liikkui aktiivisessa asiakirjassa
on_active_document_changed Etualan välilehti vaihtui
on_document_modified_changed Puhdas/likainen-lippu kääntyi (modified: bool)
on_text_changed Jokainen muokkaus (position, added_bytes, removed_bytes) — pidä se hyvin yksinkertaisena
on_settings_changed Asetukset otettiin käyttöön (scope: "" koko editori, "plugins/<id>")
on_theme_changed Teema vaihdettiin tai sitä muokattiin (variant) — lue kohteen ctx.theme värit uudelleen
on_workspace_root_changed Työtilakansio avattiin tai suljettiin (root)
on_workspace_files_changed Työtilan tiedostojoukko muuttui (files)
on_host_window_shown Kerran ajoa kohti, ensimmäisen ruudun jälkeen — aikatauluta hidas käynnistystyö tähän
on_app_about_to_quit Editori sulkeutuu — viimeinen tilaisuus ajaa
on_command_shortcut_changed Komennon todellinen pikanäppäin muuttui (käyttäjän uudelleenmääritys, näppäinkartan tuonti tai ristiriidan ratkaisu); hyötykuorma: command_id, sequence ("" = ilman määritystä)

Tuntemattomat aihenimet heittävät poikkeuksen ValueError tilaushetkellä. Tilaajat voivat ajautua vastaavan natiivin käsittelijän jälkeen; käsittele tapahtumien toimitusta tiedottavana eikä ratkaisevana.

Julkaiseminen

ctx.events.publish(topic, payload) lähettää sekä natiiveille että Python-tilaajille — hyväksytään vain kahdelle työtila-aiheelle (workspace.rootChanged, workspace.filesChanged); mikä tahansa muu heittää poikkeuksen ValueError. Katso Tapahtumadokumentaatio.


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")

Kukin taso vastaa isännän rajapintaa ILogger. Rivit saavat etuliitteen [python:<plugin.id>], jotta tulosteesi löytyy editorin diagnostiikkalokista:

[python:org.example.wordcount] counted 42 words

Älä koskaan käytä funktiota print() liitännäisestä — työntekijän stdout on RPC-kanava, ja siihen kirjoittaminen turmelee protokollan. ctx.log.* on ainoa hyväksytty tapa lähettää diagnostiikkatekstiä.


status

ctx.status.show(message, timeout_ms=0, level="info")

Lähetä ohimenevä ilmoitus tilariville.

  • message (str): mitä näyttää. Vain lyhyitä merkkijonoja — tilarivillä on kiinteä leveys.
  • timeout_ms (int, oletus 0): kuinka kauan se pidetään näytöllä; 0 antaa isännän valita järkevän oletuksen (muutama sekunti).
  • level (str, oletus "info"): "info" / "warning" / "error". Korkeammat tasot voivat pitää näytöllä olon vähimmäisajan hieman pidempänä, jottei virhettä pyyhitä heti pois rutiininomaisella info-viestillä.
ctx.status.show("saved", timeout_ms=1500)
ctx.status.show("no results", level="warning")

ctx.status.show on lähetä-ja-unohda. Jos isännällä ei ole näkyvää tilariviä (pääteetön tai minimaalinen käännös), kutsu hylätään hiljaisesti. ctx.status.clear() pyyhkii näytöllä olevan ohimenevän ilmoituksen.

Pysyvät osiot

Elävää tilaa varten (sanamäärä, palvelimen tila) käytä omistamaasi osiota ja päivitä sitä — se ei koskaan tuhoa ilmoitusta eikä päinvastoin:

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 järjestää liitännäisosiot vasemmalta oikealle (pienempi = kauempana vasemmalla; tasapelit säilyttävät rekisteröintijärjestyksen). Liitännäisen sammutus poistaa kaiken vielä hallussa olevan.


editor

Täysi synkroninen pääsy aktiiviseen asiakirjaan tai asiakirjoihin. Kukin metodi estää kutsuvan säikeen, kunnes isäntä vastaa (tyypillisesti mikrosekunteja, kun työntekijä ja editori jakavat koneen). Sallittu mistä tahansa komento- tai tapahtumakäsittelijästä; ei koskaan async def-takaisinkutsusta (katso säiehuomautus tämän sivun ylälaidassa).

Asiakirjojen luettelointi

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

Puskurin käyttö

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 välttää koko puskurin vetämisen RPC:n yli, kun tarvitset vain viipaleen — suosi sitä lajitteluun ja muunnokseen suurissa tiedostoissa.

Valinta

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?

Kohdistin

pos = ctx.editor.caret(doc)                         # mte.EditorPosition(line, column)
ctx.editor.set_caret(doc, mte.EditorPosition(line=7, column=3))

Tiedostotoiminnot

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 on se yksi kutsu, jolla »viedään käyttäjä sinne« (käännösvirhe, pinokehys, hakutulos): se avaa tiedoston tai aktivoi sen välilehden, sijoittaa kohdistimen ilman valintaa, avaa rivin piilottavan laskostuksen, vierittää rivin näkyviin — keskitettynä, jos se oli näytön ulkopuolella — ja kohdistaa editoriin. Rivi ja sarake alkavat nollasta (sarake UTF-8-tavuina) ja ne rajataan, niitä ei koskaan hylätä; se palauttaa asiakirjan tunnisteen, tai 0, jos tiedostoa ei voitu avata, ja silloin mikään ei liikkunut. reveal_line vain näyttää rivin: se ei siirrä kohdistinta, ei vaihda välilehteä eikä ota kohdistusta.

Kirjanmerkit, merkinnät ja URL-korostus

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

Haku

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". Katso koko kenttäluettelo kohteesta mte.SearchOptions.

Tarkentuva haku (kasvata hahmoa käyttäjän kirjoittaessa, kiinnitetystä ankkurista):

ctx.editor.set_incremental_search_anchor(doc)
hit = ctx.editor.incremental_search(doc, "TOD", opts)   # MatchRange

Sisennys ja syntaksi

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

Jaettu näkymä ja välilehtiryhmät

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

Kahdessa ruudussa näkyvä asiakirja on yksi asiakirja, jolla on yksi tunniste, joten group_of() voi nimetä vain toisen sen paikoista. groups_of() ilmoittaa ne kaikki, ja show_document_in_group() luo toisen jaetun näkymän — saman, minkä Näytä > Jaa asiakirja oikealle tekee, joten document_opened-tapahtumaa ei nosteta.

ctx.editor heijastaa nyt natiivia rajapintaa IEditorService yksi yhteen.


languages

Syntaksivärjäys on ytimen ominaisuus — isäntä tunnistaa asiakirjan kielen ja värittää sen ilman liitännäistä. ctx.languages antaa sinun osallistua: luettele, mitä isäntä tuntee, lue tai ohita asiakirjan kieli, aja tunnistus uudelleen ja tarjoa kokonaisia kielimäärityksiä.

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 ottaa saman muodon kuin mukana tuleva colorizers/*.json-tiedosto (tai kokonaisen definition=-sanakirjan): lexer nimeää olemassa olevan taustajärjestelmän leksikaalisen jäsentimen (isäntä ei saa uusia jäsentimiä ajon aikana), styles kuvaa tuon jäsentimen omat tyylinimet semanttisiksi luokiksi, ja keywords osoittaa sen sanaluetteloihin jäsentimen oman paikkakuvauksen mukaan — isäntä ratkaisee molemmat täsmälleen kuten mukana tulevalle tiedostolle, joten sinun ei tarvitse koskaan kirjoittaa moottorin tunnisteita. Jo olemassa olevan tunnisteen rekisteröinti korvaa sen niin kauan kuin pidät käsittelijätunnistetta; liitännäisen sammutus peruu kaiken vielä hallussa olevan.


document_settings

Vain luettavia, asiakirjaan rajattuja asetuksia, jotka kerrostavat projektin .editorconfig-tiedoston omien ctx.settings-asetustesi päälle. Avaimelle k ja asiakirjalle doc luku ratkaisee avaimen mte.<plugin.id>.<k> siitä .editorconfig-tiedostosta, joka koskee tuota asiakirjaa, turvautuu sitten kohteeseen ctx.settings ja sitten oletusarvoosi:

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?

Kirjoitukset kulkevat kohteen ctx.settings kautta — ei koskaan takaisin .editorconfig-tiedostoon.


diagnostics

Työnnä aaltoviivoja ja marginaalimerkkejä asiakirjalle — staattiselta analysaattorilta, kielipalvelimelta tai käännöslokista. Isäntä piirtää ne; sinä et koskaan kosketa näkymään. Julkaiseminen korvaa kaiken, minkä olet aiemmin julkaissut tuolle parille (asiakirja, lähde), joten lähetä koko joukko joka kerta:

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 on pakollinen — juuri se pitää joukkosi erillään muiden tuottajien (LSP-liitännäisen, oikoluvun) joukoista samassa asiakirjassa. Vakavuusasteet: SEVERITY_ERROR / SEVERITY_WARNING / SEVERITY_INFORMATION / SEVERITY_HINT. Siirtymät ovat puoliavoimia [start, end)-tavuvälejä.


theme

Rekisteröi ne värit, joita oma käyttöliittymäsi piirtää, nimettyinä, teemoitettavina luokkina; Teemaeditori luettelee ne automaattisesti ja käyttäjän ohitukset kulkevat edestakaisin teematiedostossa:

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)

Lue resolve_color uudelleen tapahtumassa ctx.events.on_theme_changed.


compare

Avaa (tai kohdista) editorin vierekkäinen vertailunäkymä kahdelle lähteelle. Kukin puoli on levyllä oleva tiedosto (path=), kirjaimellinen teksti (content=) tai molemmat (sisältö näytetään, polku antaa istunnon säilytykselle palautettavan identiteetin):

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

Palauttaa arvon False, kun puolta ei voi lukea.


settings

Pysyvä tyypitetty avain–arvo-varasto, rajattuna polkuun plugins/<your.id>/ isännässä. Kaikki metodit ovat synkronisia; get ja set päätellään oletusarvon Python-tyypistä.

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

Tyypit:

Kentän default Python-tyyppi Siirtotyyppi Funktion get() palauttama tyyppi
bool bool bool
int (ei bool) int int
float double float
str (tai None) string str

Lisäksi:

ctx.settings.contains("wrap")           # bool
ctx.settings.remove("stale_key")
ctx.settings.sync()                     # optional; host also syncs on shutdown

Reagoi asetusikkunassa tehtyihin muutoksiin tilaamalla aihe settings.changed (ctx.events.on_settings_changed; katso Tapahtumadokumentaatio).

app_settings

Vain luettava näkymä editorin sovelluksenlaajuiseen kokoonpanoon. Tunnetut avainnimet viedään vakioina moduulissa mte.keys (peilaten C++-otsikkotiedostoa PluginApi/AppSettingsKeys.h, joka pysyy ratkaisevana luettelona):

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"

Asettajat, remove() ja sync() kohteessa ctx.app_settings heittävät poikkeuksen RuntimeError — näkymä on tarkoituksella vain luettava.


completions

Rekisteröi täydennystoimittaja, joka osallistuu editorin ponnahdusluetteloon:

@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)]

Kääritty funktio kutsutaan jokaisella näppäinpainalluksella (tai Ctrl+välilyönnillä), jonka asiakirja vastaa kielisuodatinta. Olion req kentät:

Kenttä Tyyppi Merkitys
document int Muokattava asiakirja
prefix str Sanan osa välittömästi ennen kohdistinta
position int Kohdistimen tavusiirtymä
language_id str Värjääjän tunniste ("python", "cpp" …)
manual bool True, kun käyttäjä painoi Ctrl+välilyöntiä; False automaattisella laukaisulla

Palauta luettelo mte.CompletionItem-olioita (tai tavallisia merkkijonoja tai sanakirjoja muotoa {text, detail, kind}). Lajit: mte.KIND_KEYWORD / KIND_WORD / KIND_SYMBOL / KIND_SNIPPET / KIND_UNKNOWN.

Määräaika

Isäntä lähettää toimittajallesi näppäinpainalluspyynnön noin 30 ms:n määräajalla. Jos takaisinkutsusi ylittää sen, ponnahdusluettelo näytetään ilman ehdokkaitasi tuon näppäinpainalluksen osalta. Rakenna mikä tahansa kallis hakemisto taustalla ja vastaa välimuistista — älä koskaan tee I/O:ta takaisinkutsussa. LSP-tyylinen verkkotäydennys kuuluu tulevaan asynkroniseen pintaan eikä tänne.

languages=[] (tai puuttuva) tarkoittaa »jokainen asiakirja«. Useita toimittajia liitännäistä kohti on sallittu; kukin koriste rekisteröi omansa.


data_dir

path = ctx.data_dir()                    # pathlib.Path

Palauttaa liitännäiskohtaisen kirjoitettavan hakemiston, jonka isäntä on jo luonut puolestasi. Käytä välimuisteihin, hakemistoihin ja kaikkeen omistamaasi dataan. ctx.diagnostics_dir() palauttaa vastaavasti jaetun kaatumis- ja lokihakemiston (sinulle vain luettava — kaatumisraportoija kirjoittaa sinne).


docks

Kuvailevat telakkapaneelit — sivupaneelikäyttöliittymä, joka on rakennettu lomakemäärittelystä eikä Qt-ohjausobjekteista. Katso rakentajien sanasto kohdasta 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

Rekisteröi telakkapaneelin. Palauttaa paneelin tunnisteen (automaattisesti varattuna, kun id on None).

  • id (str, valinnainen) — vakaa tunniste, jota ctx.ui.get / ctx.ui.set käyttää osoittaakseen tämän paneelin sisällä oleviin ohjausobjekteihin. Jos et anna sitä, isäntä varaa tunnisteen muotoa py-dock/N ja palauttaa sen.
  • title (str) — näkyy telakan otsikossa.
  • area (str) — "left" / "right" / "top" / "bottom". Tuntemattomat arvot turvautuvat arvoon "right".
  • form (dict) — mte.ui-rakentajilla rakennettu määrittely.
  • initially_visible (bool) — näytetäänkö telakka, kun liitännäinen latautuu. Oletus True. Anna False paneelille, jonka ei pitäisi ponnahtaa esiin käynnistyksessä, ja tuo se esiin myöhemmin funktiolla set_panel_visible.
  • proportional_size (float) — paneelin oletuskoko osuutena pääikkunasta: sen leveydestä alueilla "left" / "right", sen korkeudesta alueilla "top" / "bottom". 0.0 (oletus) säilyttää pikselikäyttäytymisen, jota työkalupaneeli haluaa — paneeli pitää kokonsa, eikä ikkunan koon muuttaminen kosketa sitä. Murtoluku kuten 0.4 on sitä, mitä esikatselu haluaa: ikkunan suurentaminen leventää paneelia sen mukana. Vain oletus on sinun; heti kun käyttäjä vetää paneelin erotinta, isäntä ottaa käyttöön ja muistaa hänen osuutensa. Rajojen ulkopuoliset arvot rajataan, ja isäntä säilyttää vähimmäislaajuuden sekä paneelille että editorille. Täydet säännöt ovat kohdassa proportionalSize.
  • tab_group (str) — paneelit, joilla on sama ei-tyhjä ryhmätunniste samalla area-alueella, jakavat yhden telakan välilehtinä sen sijaan, että olisivat vierekkäin. Anna sille nimiavaruus kuten paneelin tunnisteelle ("renamer/panels"). Vain oletusjärjestely: käyttäjän tallentama asettelu voittaa. Katso tabGroup.

ctx.docks.is_panel_visible(handler_id) -> bool

Onko add_panel-kutsulla lisätty paneeli auki — toisen taakse välilehdeksi jäänyt paneeli lasketaan avoimeksi; arvolla initially_visible=False rekisteröity eikä koskaan näytetty paneeli, suljettu paneeli ja tuntematon tunniste eivät. Yhdistä se set_panel_visible-kutsuun, kun haluat näyttää paneelisi tehtävän ajaksi ja palauttaa sen jälkeen sen, mitä käyttäjällä oli:

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)

Tuo esiin tai piilottaa paneelin, joka on lisätty funktiolla add_panel. Näyttäminen myös nostaa paneelin niiden telakoiden yläpuolelle, joiden kanssa se jakaa alueen, joten komento, joka »avaa« paneelinsa, todella laittaa sen käyttäjän eteen. Idempotentti — toista sama arvo vapaasti, mitään ei tarvitse seurata; ohitetaan hiljaisesti tuntemattomalle tunnisteelle.

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

Varaa käsittelijätunnisteen ohjausobjektin on_change-kentän kytkemiseksi Python-funktioon. Takaisinkutsu saa uuden arvon merkkijonona; totuusarvo-ohjausobjektit toimittavat arvon "true" / "false", ja numeeriset ohjausobjektit toimittavat kokonaisluvun merkkijonona.

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)])

on_change-käsittelijätunnisteilla on etuliite py-dock-cb/N eivätkä ne koskaan törmää komento-, tapahtuma- tai täydennyskäsittelijöiden tunnisteisiin.

Takaisinkutsu ajetaan työntekijän tapahtumasilmukassa EIKÄ säiepoolissa — pidä se nopeana. Käytä kohdetta ctx.log, muuta pientä muistissa olevaa tilaa tai laukaise jatkokomento; älä tee raskasta työtä täällä.


line_markers

Marginaalisymbolit ja kokonaisten rivien sävytykset, jotka on kiinnitetty asiakirjan riveihin ja jotka seuraavat käyttäjän muokkauksia — keskeytyskohdat, nykyisen lauseen nuoli, muutospalkit — sekä kirjanmerkkisarakkeen napsautuksen varaus. Natiivi palvelu ja kaikki sen säännöt kuvataan kohdassa Rivimerkit ja marginaalin napsautus.

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=) — glyph on jokin arvoista mte.GLYPH_NONE (pelkkä sävytys), GLYPH_CIRCLE, GLYPH_CIRCLE_HOLLOW, GLYPH_CIRCLE_BAR, GLYPH_ARROW, GLYPH_STRIP; värit ovat niiden luokkien tunnisteita, jotka olet rekisteröinyt ctx.theme-palvelulla. Editorissa on kaikille liitännäisille yhteensä vain muutama merkkipaikka, joten tämä voi epäonnistua — silloin heitetään RpcError. Rekisteröi lajisi kerran, funktiossa register().
  • add_marker(kind, doc, line) — nollasta alkava rivi, jota ei rajata: asiakirjan ulkopuolinen rivi palauttaa 0 eikä sijoita mitään.
  • Merkit liikkuvat rivien mukana, säilyvät uudelleenlatauksessa samalla rivinumerolla ja katoavat asiakirjansa mukana — lisää omasi uudelleen käsittelijässä ctx.events.on_document_opened.

Marginaalin napsautus

@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()

Jokainen vasemman painikkeen napsautus kirjanmerkkisarakkeessa julkaistaan aiheena margin.clicked (document, line, margin = "symbol", modifiers — bitit mte.MODIFIER_SHIFT / MODIFIER_CONTROL / MODIFIER_ALT / MODIFIER_META). Oletuksena editori myös lisää tai poistaa kirjanmerkin napsautuksesta; niin kauan kuin jokin liitännäinen pitää claim_margin_click()-varausta, se ei tee niin vaan jättää napsautuksen liitännäisille. ctx.line_markers.release(claim) palauttaa napsautuksen.


settings_page

Lisää sivun editorin asetusikkunaan. Sama lomakemäärittelyn sanasto kuin telakkapaneeleilla; sama binds="settings:<key>"-tallennus.

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, pakollinen) — kauttaviivoin erotettu polku asetuspuussa, esimerkiksi "Plugins/My Plugin". Sisäkkäiset luokat saapuvat puusolmuina.
  • title (str, pakollinen) — otsikko, joka näytetään sivun yläpuolella.
  • form (dict, pakollinen) — mte.ui-rakentajilla rakennettu määrittely.
  • scope (str, valinnainen) — tapahtuman laajuus, joka lähetetään tapahtumassa SettingsChanged, kun käyttäjä painaa OK tai Ota käyttöön.

Palauttaa käsittelijätunnisteen.

Peruuta EI peru muutoksia

Ohjausobjektit, joilla on binds="settings:<key>", tallentuvat innokkaasti käyttäjän muokatessa, joten Peruuta-painikkeen painaminen asetusikkunassa ei kumoa niitä. Tämä on tunnettu vaiheen 3 rajoitus; tuleva hienosäätö kääri taustalla olevat asetukset puskuroivaan välikerrokseen.


ui

Lukee ja kirjoittaa ohjausobjektien arvoja jo rekisteröimissäsi paneeleissa. Arvot ovat siirtotiellä aina merkkijonoja.

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]

Lukee ohjausobjektin nykyisen arvon. Palauttaa arvon None, kun paneeli tai ohjausobjekti on tuntematon (ei virhe — käsittele sekä None että "" merkityksessä »tyhjä«).

  • Label / Button / LineEdit / ComboBox — palauttaa tekstin.
  • Checkbox — palauttaa arvon "true" tai "false".
  • NumberSpin — palauttaa kokonaisluvun desimaalimerkkijonona.
  • List — palauttaa valitun kohdan tekstin (tyhjä, kun mitään ei ole valittuna).

ctx.ui.set(panel_id, control_id, value) -> bool

Kirjoittaa arvon ohjausobjektiin ohjelmallisesti. Palauttaa arvon True, kun kirjoitus onnistui, ja False, kun paneeli tai ohjausobjekti on tuntematon tai arvoa ei voi muuntaa (esimerkiksi ei-kokonaisluku lähetettynä NumberSpin-kenttään).

Pythonin True / False muunnetaan arvoiksi "true" / "false" ennen lähetystä; kaikki muu kulkee funktion str() kautta.

Isännän ohjaama set EI laukaise ohjausobjektin on_change-takaisinkutsua uudelleen, joten voit päivittää omia ohjausobjektejasi komentokäsittelijästä ilman äärettömiä silmukoita.


Ajonaikaisten sidontojen yhteenveto (vaihe 3)

Lomakemäärittelyn kenttä Ajonaikainen käyttäytyminen
id="…" Osoita ohjausobjektiin funktioilla ctx.ui.get / ctx.ui.set.
binds="settings:<key>" Lukee alkuarvon kohteesta ctx.settings; kirjoittaa takaisin jokaisella käyttäjän muokkauksella.
on_click="<cmd>" Painikkeet kutsuvat rekisteröityä komentotunnistetta napsautettaessa.
on_change=käsittelijä Laukaisee takaisinkutsun, joka on rekisteröity funktiolla ctx.docks.on_change(...), käyttäjän muokatessa.

Samat säännöt pätevät telakkapaneeleihin ja asetussivuihin.