//! Views and custom editors (`[[contributes.views]]`, //! `[[contributes.customEditors]]`): implement [`Views`] and register with //! `register_plugin!(MyPlugin, views)`. //! //! A view is data — a toolbar, a body (tree, list, form, table, message or //! sandboxed HTML) and a status line. The IDE renders it and calls //! [`Views::handle`] with what the user did; call [`crate::host::refresh_view`] //! when the content changes. For a custom editor, `ctx.editor()` is its //! document: read it with `document()` and change it with `apply_edits`, so //! the text editor of the same file follows and undo is shared. use crate::{Error, Invocation}; #[derive(Clone, Debug, PartialEq, Eq)] pub struct Button { pub id: String, pub label: String, /// An IDE icon (`refresh`, `add`, `remove`, `run`, `stop`, `settings`…). pub icon: Option, pub enabled: bool, } impl Button { pub fn new(id: &str, label: &str) -> Self { Self { id: id.into(), label: label.into(), icon: None, enabled: true } } pub fn icon(mut self, icon: &str) -> Self { self.icon = Some(icon.into()); self } pub fn enabled(mut self, enabled: bool) -> Self { self.enabled = enabled; self } } /// A tree node; `parent` is the key of an item listed before it. #[derive(Clone, Debug, PartialEq, Eq)] pub struct TreeItem { pub key: String, pub parent: Option, pub label: String, pub icon: Option, pub detail: Option, /// Shows an expander before the children are known ([`ViewEvent::Expand`]). pub expandable: bool, pub expanded: bool, } impl TreeItem { pub fn new(key: &str, label: &str) -> Self { Self { key: key.into(), parent: None, label: label.into(), icon: None, detail: None, expandable: false, expanded: false, } } pub fn parent(mut self, parent: &str) -> Self { self.parent = Some(parent.into()); self } pub fn icon(mut self, icon: &str) -> Self { self.icon = Some(icon.into()); self } pub fn detail(mut self, detail: &str) -> Self { self.detail = Some(detail.into()); self } /// Has (or may have) children; `expanded` shows them. pub fn expandable(mut self, expanded: bool) -> Self { self.expandable = true; self.expanded = expanded; self } } #[derive(Clone, Debug, PartialEq, Eq)] pub struct ListItem { pub key: String, pub label: String, pub icon: Option, pub detail: Option, } impl ListItem { pub fn new(key: &str, label: &str) -> Self { Self { key: key.into(), label: label.into(), icon: None, detail: None } } pub fn icon(mut self, icon: &str) -> Self { self.icon = Some(icon.into()); self } pub fn detail(mut self, detail: &str) -> Self { self.detail = Some(detail.into()); self } } #[derive(Clone, Debug, PartialEq, Eq)] #[non_exhaustive] pub enum FieldValue { Text(String), Multiline(String), Checkbox(bool), /// Options and the chosen one. Choice(Vec, String), /// A field type of a newer plugin API: its kind and JSON data (IDEs that /// don't know it leave the field out). Other { kind: String, data: String, }, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct Field { pub key: String, pub label: String, pub value: FieldValue, } impl Field { pub fn new(key: &str, label: &str, value: FieldValue) -> Self { Self { key: key.into(), label: label.into(), value } } } /// Rows `first_row..first_row + rows.len()` of `total_rows`. #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct Table { pub columns: Vec, pub total_rows: u32, pub first_row: u32, pub rows: Vec>, pub editable: bool, } #[derive(Clone, Debug, PartialEq, Eq)] #[non_exhaustive] pub enum Body { Message(String), Tree(Vec), List(Vec), Form(Vec), Table(Table), /// Shown in a sandboxed frame; its script talks to the plugin with /// `openidea.postMessage(text)` and `openidea.onMessage(fn)`. Html(String), /// A body of a newer plugin API: its kind and JSON data (IDEs that don't /// know it say they need updating). Other { kind: String, data: String, }, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct View { pub toolbar: Vec