Skip to content
DocsEvents

PluginsEarly

Events

What a plugin can listen for with on(...), what each one carries and what its handler may return.

From the plugin interface of gr 0.2.16 (API 0.1, 0.2, 0.3). gr plugin api events prints it on your machine.

A plugin listens with on(kind, handler). The handler gets the payload and, for events marked "with context", the app's context. Its time is held to the budget named.

load

The script was loaded for a root.

Payload
none
Returns
void
Sent by
daemon
Budget
load

unload

The instance is going away.

Payload
{ reason: "idle" | "disabled" | "removed" | "reload" }
Returns
void
Sent by
daemon
Budget
unload

command

One of the plugin's commands was run from a key, the palette, the command line or a menu. From a menu a right click opened (since 0.2), menu is its place (one of [[menus]]' places, or row for a row's own menu) and args is [target], a MenuTarget, or a row menu entry's args.

Payload
{ command: string; args: Json[]; menu?: string }
Returns
Cmd[] | void
Sent by
app, with context
Budget
handler

view

A panel or float wants its tree.

Payload
{ view: string }
Returns
Element
Sent by
app, daemon, with context
Budget
view

rows

A windowed list, or (0.2) table, wants items [start, end); list is its key; rows for another rev are dropped.

Payload
{ view: string; rev: number; list: string; start: number; end: number }
Returns
{ rev: number; items: Element[] }
Sent by
app
Budget
rows

act

The person acted on an element of a view; value is an input's text, a select's chosen value, or a toggle's true or false (0.2); column is the column a table's sort asks for (0.2)

Payload
{ view: string; element: string; act: "activate" | "select" | "press" | "submit" | "change" | "open" | "close" | "sort"; item?: string; value?: string | boolean; column?: string }
Returns
Cmd[] | void
Sent by
app, with context
Budget
handler

picker

A picker wants its entries.

Payload
{ picker: string; query: string }
Returns
Entry[]
Sent by
app, with context
Budget
rows

pick

The person chose an entry.

Payload
{ picker: string; entry: string; how: "open" | "split" | "vsplit" | "tab" }
Returns
Cmd[] | void
Sent by
app, with context
Budget
handler

focus

Focus moved; at most 10 a second.

Payload
none
Returns
void
Sent by
app, with context
Budget
background

file.opened

A file was opened.

Payload
{ path: string }
Returns
void
Sent by
app, with context
Budget
background

file.saved

A file was saved.

Payload
{ path: string }
Returns
void
Sent by
app, with context
Budget
background

file.closed

A file was closed.

Payload
{ path: string }
Returns
void
Sent by
app
Budget
background

mode

The mode changed.

Payload
{ mode: Context["mode"] }
Returns
void
Sent by
app, with context
Budget
background

theme

The theme changed.

Payload
{ name: string; dark: boolean }
Returns
void
Sent by
app
Budget
background

agent.started

An agent started.

Payload
{ agent: string }
Returns
void
Sent by
daemon
Budget
background

agent.stopped

An agent is no longer running (stopped, asleep or archived); not that its turn ended, which is agent.attention with attention idle.

Payload
{ agent: string }
Returns
void
Sent by
daemon
Budget
background

agent.attention

An agent asks for the person: attention (0.2) says what for; 0.1 named it kind, which the event's own kind hides.

Payload
{ agent: string; attention: "permission" | "question" | "plan" | "idle" }
Returns
void
Sent by
daemon
Budget
background

graph.changed

Nodes changed (at most 1,000), or all; coalesced to one a 250 ms.

Payload
{ nodes?: string[]; all?: true }
Returns
void
Sent by
daemon
Budget
background

settings

The plugin's settings changed.

Payload
{ settings: Record<string, Json> }
Returns
void
Sent by
daemon
Budget
background

files.changed

Files of the root changed on disk (at most 1,000 paths, slash-separated and within the root, .git's own files left out), or all; coalesced to one a 250 ms.

Payload
{ paths?: string[]; all?: true }
Returns
void
Sent by
daemon
Budget
background
Since
API 0.2

agent.state

An agent's state changed (Agent.state's words), with what it waits for when it waits.

Payload
{ agent: string; state: string; attention?: string }
Returns
void
Sent by
daemon
Budget
background
Since
API 0.2

shown

One of the plugin's views began to show in some window.

Payload
{ view: string }
Returns
void
Sent by
daemon
Budget
background
Since
API 0.2

hidden

One of the plugin's views shows in no window any more.

Payload
{ view: string }
Returns
void
Sent by
daemon
Budget
background
Since
API 0.2

document.opened

A document of a language the plugin's [documents] names (every language when the table names none) was opened in an editor of the root.

Payload
{ path: string; version: number; language: string; dirty: boolean }
Returns
void
Sent by
daemon
Budget
background
Since
API 0.2

document.changed

A document's text changed; one a document every 50 ms at most; changes, in order, only with fs:read:workspace and under 64 KiB (absent: read it again)

Payload
{ path: string; version: number; changes?: TextEdit[] }
Returns
void
Sent by
daemon
Budget
background
Since
API 0.2

document.saved

A document was saved at version.

Payload
{ path: string; version: number }
Returns
void
Sent by
daemon
Budget
background
Since
API 0.2

document.closed

A document was closed, or its window went away.

Payload
{ path: string }
Returns
void
Sent by
daemon
Budget
background
Since
API 0.2

document.viewport

The lines of a document on screen changed (top to bottom, from 0)

Payload
{ path: string; version: number; top: number; bottom: number }
Returns
void
Sent by
daemon
Budget
background
Since
API 0.2

document.edited

The answer to the plugin's own edit at version: applied, or refused and why; now is the version after it, or the document's current one.

Payload
{ path: string; version: number; applied: boolean; reason?: "moved" | "closed" | "readonly" | "shape"; now?: number }
Returns
void
Sent by
app
Budget
background
Since
API 0.2

tool

An agent called one of the plugin's [[tools]], through Graphide's MCP server, where it is plugin_<plugin>_<verb>: tool is its name (<plugin>.<verb>), input what the agent gave, already checked against its [tools.input]. A tool is declared in plugin.toml with [allow] agents = ["tools"]: [[tools]] name, description (at most 1,000 characters: what the agent reads), read_only (it changes nothing), and [tools.input] required = [...] with [tools.input.properties.<name>] type (string, number, integer, boolean or array), description, enum (strings) and items (an array's, not an array). The handler computes within a command's budget and may wait on $ calls; the agent waits at most 30 s in all for the answer (tool.timeout). Example: on("tool", { tool: "todos.list" }, async (e) => ({ text: await todosOf(e.input.path) }))

Payload
{ tool: string; input: Record<string, Json> }
Returns
ToolAnswer
Sent by
daemon
Budget
handler
Since
API 0.2

mention

The person is typing an @ in an agent's composer: source is one of the plugin's [[mentions]] by its id, query what follows the @ (or the @<prefix>:, which asks this source alone). Asked once typing rests (80 ms), on the editor's threads, never holding a key: an answer that comes after the next question is dropped, and one that never comes shows nothing. At most 50 entries (mention_entries), the first kept. A source is declared in plugin.toml as [[mentions]] id = "<plugin>.<name>" (in the plugin's one set of ids), title (the heading its entries show under, at most 40 characters) and prefix (1 to 16 lowercase letters, digits and hyphens, beginning with a letter: @<prefix>: narrows the list to it). Example: on("mention", { source: "issues.open" }, async (e) => (await open(e.query)).map((i) => ({ key: i.id, label: i.title, attach: { text: i.body } })))

Payload
{ source: string; query: string }
Returns
MentionEntry[]
Sent by
app
Budget
rows
Since
API 0.2

mention.pick

The person chose an entry of a mention source (entry is its key); the editor has attached what the entry said already, and tells the plugin after.

Payload
{ source: string; entry: string }
Returns
Cmd[] | void
Sent by
app
Budget
handler
Since
API 0.2

layer.left

One of the plugin's own key layers was left: a key it does not bind (which then went on where it was going), Escape, its timeout, a change of the keys' mode, or the plugin's own layer.exit; told to that plugin alone.

Payload
{ layer: string; why: "key" | "escape" | "timeout" | "mode" | "exit" }
Returns
void
Sent by
app
Budget
background
Since
API 0.2

complete

The person is typing a word in a file of a language one of the plugin's [[completions]] lists (or any file, for one that lists none): path is the file within the root, version its version in the editor, at the caret (a Pos), prefix the word before the caret, trigger the character just typed where it is one the file's language server completes after. Asked 30 ms after a word's first keys rest, after a trigger character and when the person asks for completions (Ctrl+Space), at most once a pause, on the editor's threads and never holding a key: the menu shows at once and the items join it when they come; an answer after the next question, or later than 250 ms after the question, is dropped. The editor narrows the answer itself as the word goes on, without asking again. Items list after the language server's, in the order given, the first 100 kept: label is what the menu shows and what is typed over the prefix unless insert says other text (plain text), detail a few words after it, kind one of LSP's kinds in lower case (function, method, variable, field, class, struct, interface, module, keyword, snippet, constant, ...) marking it with that kind's colour. Needs fs:read:workspace: the prefix is the file's text, and a plugin not granted it is asked nothing (gr plugin check warns of [[completions]] without it). Example: on("complete", async (e) => ({ items: (await words(e.path)).filter((w) => w.startsWith(e.prefix)).map((w) => ({ label: w, kind: "text" })) }))

Payload
{ path: string; version: number; at: Pos; trigger?: string; prefix: string }
Returns
{ items: { label: string; detail?: string; insert?: string; kind?: string }[] }
Sent by
app
Budget
rows
Since
API 0.2

lsp.diagnostics

What the language servers say of these files of the root changed (at most 1,000 paths, slash-separated and within the root): ask lsp.diagnostics for the ones shown. No path means more changed than an event names: ask for them all. Coalesced to one a 250 ms.

Payload
{ paths: string[] }
Returns
void
Sent by
daemon
Budget
background
Since
API 0.2

These docs describe Graphide 0.2.16, the latest release. Something wrong or missing? Tell us onDiscord or at hello@graphide.com.