Gutter markers and gutter buttons are editor providers: see
Language features. File icons are on
Icon themes.
Declare a tool window
A view without
web needs code (wasm). Showing a view activates the plugin
(on-view:<id>).
Grouped and conditional views
secondary, even when that view is hidden; the window disappears when all its tabs are
hidden. Tabs load on first selection and stay mounted while they apply, so web views keep
their state when you switch tabs. when is evaluated again on context changes, file
creation and removal, and project changes. These fields only control visibility; they
grant no access.
Render a view
Registerregister_plugin!(MyPlugin, views) and implement openidea_plugin::views::Views
(WIT export view-provider). A view is data: a toolbar, a body and a status line. The IDE
draws it with its own components (theme, keyboard, speed search) and sends back what the
user does.
From the TODO Finder
example:
host::refresh_view(view) and the IDE calls render again.
host::reveal_view(view) brings one of the plugin’s views to the front in the invoking
window. For a tool window, ctx.editor() is the window’s active text editor, so toolbar
buttons can act on what the user is editing.
Bodies
Toolbar buttons:
View::new(body).button(Button::new("refresh", "Refresh").icon("refresh"))
and .status("12 items").
Events
ViewEvent carries Button(id), Activate(key) (double click or Enter), Select(key),
Expand(key), Collapse(key), Field(key, value) (true/false for checkboxes),
Cell { row, column, value }, InsertRow(before), DeleteRows(rows) and Message(text)
from an HTML body. Table row clicks and Space decode with event.table_select();
double click and Enter with event.table_activate() (API 1.3, absolute 0-based rows).
Bodies, fields and events added by later APIs travel as Other { kind, data }: an IDE that
doesn’t know a body says it needs updating, and leaves out a field type it doesn’t know.
Item right-click menus use viewItem.context (see
Commands and actions).
Custom editors
A custom editor opens files matching its patterns and edits the file’s text document:priority = "default"opens matching files in the plugin’s editor;optionmakes it available through Open With. Open as Text opens the text editor.layout = "split"or"preview"opens the file in the text editor with the plugin’s editor beside it and the Editor Only / Editor and Preview / Preview Only switch in the tab strip, as for Markdown; the value is the layout files start in."tab"(default) is a tab of its own.- In
renderandhandle,ctx.editor()is the editor’s document. Read it withdocument()and change it withapply_edits(version, edits). The text editor of the same file follows, Undo/Redo is one history with it, and Save, the dirty mark and the close prompts are the document’s.
editor.read and editor.write.
HTML bodies
Body::Html runs in a sandboxed frame: an opaque origin under a CSP that allows only its
inline scripts and styles and data: images, with no network and no IDE API. It talks to
the plugin only through openidea.postMessage(text) and openidea.onMessage(fn), which
arrive as ViewEvent::Message and are answered with host::post_view_message(view, text).
Regex Tester
works this way. Rendering again reloads the frame, so let the page keep its own state.
The frame follows the IDE theme without reloading. Its root carries
data-theme="light|dark" and these CSS variables with concrete colour values:
Scripts also get
openidea.theme ({ dark, vars }) and openidea.onThemeChange(fn).
Variables are only ever added.
Web views
A view or custom editor can be a web page shipped in the package, for UIs the declarative bodies can’t express (a canvas, a diagram editor). It needs no code:- The page’s directory (never the package root) is part of the declaration: every file under it is checked (at most 4096 files and 256 MiB, no links), installed and signed with the package.
- The page loads into an
<iframe sandbox="allow-scripts">from the IDE’s own URL scheme: opaque origin, no network, no cookies or storage, only the page’s own files. Build it with relative paths (Vite:base: "./"). - The same
openideaobject as in HTML bodies is available before the page’s scripts run, plus:
IDE shortcuts the page doesn’t handle (Save, Close, Find Action…) still work while it has
focus; editing keys stay with the page. With the
clipboard capability the page may use
navigator.clipboard.
Custom header (API 1.3). An ungrouped tool-window web view can declare
header = "none": once the page is ready, the IDE replaces the tool-window header with
corner actions (Options, Hide) and sets --openidea-corner-inset-width (64px) and
--openidea-corner-inset-height (34px) so the page can pad its own top bar:
web-src/, built into web/ by
plugins/build.sh official/graphviz, whose code publishes the errors Graphviz reports as
problems.
Page protocols (API 1.3)
Withengines.openidea = "^1.3", a page can send JSON messages through
openidea.postMessage to ask the IDE for more. All of them run only programs granted with
process:<program>, in the window’s trusted project root, never through a shell:
The message fields and limits are in the
plugin guide;
the built fixtures
web-pty, web-log and web-content under
crates/ide-plugin/tests/fixtures/ exercise them.
Services views and detail panes
location = "services" (API 1.3) puts a view’s tree in the Services tool window next
to Docker and the run configurations, instead of a tool window of its own:
render, handle, the toolbar (acting on the
selected node) and viewItem.context menus work as in a tool window. The pane beside the
tree comes from the detail-provider export: register_plugin!(MyPlugin, views, details)
and implement openidea_plugin::details::Details:
host::refresh_view(view). A tab is a Pane::Message, a read-only Pane::Text
(at most 1 MiB) or a ProcessLog: the IDE runs that program (it needs the
process:<program> grant) in the project root and follows its output (ANSI stripped, the
last 5000 lines, Soft-wrap, Clear, the exit code at the end). A toggle appends its
args and restarts the program. It stops when the pane closes or Services is hidden.
List and detail views (API 1.3). A tree or list view in any location can declare
detail = true to show the same Details tabs beside the selected item, with a resizable
divider. The host asks after the item’s select event and again after refresh_view.
Tabs and terminals opened by code
These are called from a command or event of a window:Decorations
Decorations (API 1.4, WITdecorations.wit) annotate editors and the Project tree. They
need project.read; paths must be inside an open project.
- Styles map to theme tokens:
highlight,search,added,modified,removed,warning,error,info,underline,strikethrough,muted. Unknown styles are ignored. - A set (
set_id) belongs to the plugin and project and is shared by all windows of that project. Setting replaces the set’s items for that file;clear_decorations(set_id)andclear_file_decorations(set_id)remove a set everywhere. - Limits: 50 editor sets and 50 tree sets per plugin, 10,000 editor items per file, 4 MiB of metadata. Disabling, unloading or a crash withdraws them; idle reclaim keeps them.
Project::vcs_blame into end-of-line decorations.