[[contributes.commands]] entry becomes an IDE action with the stable id
plugin.<plugin-id>.<command-id>. Like a built-in action it shows in
Find Action (⌘⇧A / Ctrl+Shift+A) and Search Everywhere, can be bound in
Settings › Keymap, and can be placed in menus, toolbars and the status bar.
Declared commands are live as soon as the plugin is enabled, before any plugin code
loads. The code is instantiated the first time one of them runs (every command implies
on-command:<id> activation), so a plugin with many commands costs nothing at start-up.
See Lifecycle for activation and idle reclaim.
Declare a command
when clauses
when uses the same expressions as built-in actions: key, key == value,
key != value, !, &&, || and parentheses. Useful keys:
editorFocus: a text editor has focus.editorLangId == sql: the focused editor’s language id.workspaceContains:pom.xml: the open project contains that exact path (relative to the project root, no globs). In a workspace it is true when any project contains it, and it updates as files change. An IDE that doesn’t know the key treats it as false.plugin.<plugin-id>.<key>: a key the plugin set itself withhost::set_context(below).
Run the command
ImplementPlugin::run_command
(WIT export commands.run). ctx is the invoking window: ctx.project(),
ctx.editor() and ctx.selected_paths().
editor.read and editor.write under [capabilities]
(Capabilities). The
String Tools
plugin is a complete example with 26 commands.
What the result means:
Ok(Some(text))is shown to the user;Ok(None)shows nothing.- An error shows “
<title>failed: …” and the plugin keeps running."msg".into()isError::Failed. Error::Cancelled(the user gave up) andError::Denied(a capability is missing) are not counted as the plugin failing.
Arguments and selected files
argis an optional string. It isNonewhen the command runs from Find Action or a shortcut, and set when another feature runsplugin.<plugin-id>.<command-id>with an argument, or when a notification button, code lens or gutter action passes one.ctx.selected_paths()lists the files and folders a Project view or editor tab menu ran the command on (the argument is then the first of them); it is empty otherwise.- From
problems.contextandsearchResults.contextmenus,selected_paths()holds the problem’s or match’s file andargis JSON{"path": "…", "line": 0, "column": 0}(0-based line, UTF-16 column).
Limits
A command call has a 5-second wall-clock budget and a CPU fuel budget. For longer work, open a task withhost::begin_task(title, cancellable): while it is open the call may run
for 60 seconds, and each report or is_cancelled renews that budget. Dialogs
(host::pick, input, confirm, …) don’t count against the budget while they wait.
Keyboard shortcuts
- Modifiers:
Meta,Ctrl,Alt,Shift. Keys:A–Z,0–9,F1–F24,Enter,Escape,Tab,Space,Backspace,Delete,Insert,Home,End,PageUp,PageDown,Up,Down,Left,Right,Minus,Equal,Comma,Period,Slash,Semicolon,Quote. - A chord is two strokes separated by a space:
Meta+K Meta+C. - Every stroke except a function key needs
Ctrl,AltorMeta: plain keys are for typing. - Without
mac, macOS getskeyunchanged, soCtrlstaysCtrl. GivemacwithMetawhen you want⌘. - A plugin shortcut is a default below the IDE’s: it is dropped when the keymap preset or the user already uses that keystroke, or when the action already has a binding. The user can rebind it in Settings › Keymap.
Menus
Using a menu newer than 1.0 means declaring at least that API in
engines.openidea.
Every entry names a command the plugin declares. The menu’s when applies alongside the
command’s own when.
Toolbar icons. editor.title, mainToolbar and commit.message entries show an
icon: the command’s icon, else the plugin’s manifest icon.
Submenus (API 1.3). In a context menu (*.context), entries that name the same
submenu are grouped under it in declaration order. A submenu with one visible entry
shows it as a plain entry. The label is translated through the plugin’s catalog.
viewItem.context needs view, the id of one of the
plugin’s own views that its code renders as a tree, list or table (not a web view).
Each command receives the item’s key as its argument. Only the menu’s when can test
viewItem (the key) and viewItemKind (the key up to its first :, so pod for
pod:default/nginx). For table rows the key is the decimal row index. See
Views and decorations.
Status bar items
host::set_status_item(id, &StatusItem { text, tooltip, command })shows or updates an item in every window (at most 8 per plugin; kept while the plugin is idle);remove_status_item(id)removes it.host::set_window_status_item(id, item)(API 1.4) overrides it in the invoking window only;remove_window_status_item(id)falls back to the global item. Only valid from a command or event of a window.
Context keys from code
host::set_context(key, value) sets plugin.<plugin-id>.<key> for when clauses
(true, a number or text up to 1024 bytes). Keys are 1–64 characters of
A-Za-z0-9_-, at most 100 per plugin. A key set from a command or event applies to that
window; one set outside any applies to every window, and a window’s value wins. Keys
survive a window reload and idle reclaim and are dropped when the plugin stops.
Notifications with buttons
host::notify(level, title, body) shows a balloon in the window the command or event
came from (every window when there is none). host::notify_with_actions adds up to three
buttons, each running one of the plugin’s declared commands:
Project::notify(level, title, body, actions): a balloon only in a window of
that project (the most recently focused one), also from scheduled or background work. If
the project has closed it fails with Error::NotFound. Labels are at most 256 bytes and
arguments 64 KiB; an undeclared command rejects the whole notification.
Running other commands
host::execute_command(id, arg) (API 1.4, WIT command-runner.execute) runs a stable
IDE action id or plugin.<plugin-id>.<command-id> in the invoking window. A plugin’s own
commands need no capability; IDE actions and other plugins’ commands need the high-risk
ide.commands capability. IDE actions return None; plugin commands return their result.
Calls nest at most 8 deep and only from a command or event of a window.
Events
Commands are one entry point; workbench events are the other. Subscribe withhost::subscribe(EventKind::FileSaved) in activate, or declare
activation = ["on-event:file-saved"] to be woken by the first one, then handle batches
in Plugin::handle_events(events, ctx) (WIT events.wit, export event-handler).
Events arrive in batches, oldest first, per window. An idle plugin collects them for 2
seconds before it is woken.
host::subscribe_paths(kind, &["config/*.yaml"]) (API 1.3)
filters file-opened, file-saved and files-changed by project-relative globs. Kinds
newer than the SDK arrive as Event::Other { kind, data }; match the
#[non_exhaustive] enum with a _ arm. Key Promoter
(action-performed) and Git Toolbox
(on-schedule, vcs-changed) are working examples.
Commits
A plugin can act on the commit the user is preparing (API 1.3,commit.wit):
- A button above the message: a
commit.messagemenu entry. - Read the draft:
host::pending_commit()(vcs.read) returns what Commit would commit now: per file its repository, path, status and agit diffof only the included changes (1 MiB in all, thentruncated), plus the message, Amend and arevision. Unsaved editors of those files are saved first; nothing is staged. - Write the message:
host::set_commit_message(revision, text)(vcs.write) replaces it only while the draft is still atrevision; otherwise it fails withError::Staleand the user’s text is kept.
[[contributes.commitChecks]] (id, title) is listed in
Commit Options, on by default. When the user commits, after the IDE’s own checks, the
IDE calls the commit-checker export. Register it with
register_plugin!(MyPlugin, commit_checks) and implement
openidea_plugin::commit::CommitChecks:
vcs.read is reported as a problem too.
Related
- Manifest for the full
plugin.tomlreference. - Views and decorations for tool windows whose buttons run code.
- API reference for every host function.