Skip to main content

Action

Trait Action 

Source
pub trait Action: Any + Send {
    // Required methods
    fn boxed_clone(&self) -> Box<dyn Action>;
    fn partial_eq(&self, action: &dyn Action) -> bool;
    fn name(&self) -> &'static str;
    fn name_for_type() -> &'static str
       where Self: Sized;
    fn build(value: Value) -> Result<Box<dyn Action>>
       where Self: Sized;

    // Provided methods
    fn action_json_schema(_: &mut SchemaGenerator) -> Option<Schema>
       where Self: Sized { ... }
    fn deprecated_aliases() -> &'static [&'static str]
       where Self: Sized { ... }
    fn deprecation_message() -> Option<&'static str>
       where Self: Sized { ... }
    fn documentation() -> Option<&'static str>
       where Self: Sized { ... }
}
Expand description

An action is a named command that the app can run, such as saving or moving the cursor up.

Declaring an action separates what the app can do from the keys that trigger it. A KeyBinding maps keystrokes to an action, a menu or button can run the same action, and InteractiveElement::on_action handlers receive it. See keyboard input for the dispatch order.

Declare unit actions with actions!, and actions with data with #[derive(Action)]. The derive macro implements every method of this trait and registers the action by name, so you rarely write an impl yourself.

§Examples

This action has a field, so the keymap entry carries a value. The handler runs when ctrl-r is typed while the Counter element has focus:

use gpui::{Action, Context, FocusHandle, KeyBinding, TestApp, Window, div, prelude::*};

#[derive(Clone, PartialEq, serde::Deserialize, schemars::JsonSchema, Action)]
#[action(namespace = action_trait_docs)]
pub struct Repeat {
    pub times: usize,
}

struct Counter {
    focus_handle: FocusHandle,
    total: usize,
}

impl Render for Counter {
    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
        div()
            .key_context("Counter")
            .track_focus(&self.focus_handle)
            .on_action(cx.listener(|counter, action: &Repeat, _window, _cx| {
                counter.total += action.times;
            }))
    }
}

let mut app = TestApp::new();
app.update(|cx| cx.bind_keys([KeyBinding::new("ctrl-r", Repeat { times: 2 }, Some("Counter"))]));

let mut window = app.open_window(|window, cx| {
    let focus_handle = cx.focus_handle();
    window.focus(&focus_handle, cx);
    Counter { focus_handle, total: 0 }
});

window.simulate_keystrokes("ctrl-r");
assert_eq!(window.read(|counter, _| counter.total), 2);

§Derive attributes

#[derive(Action)] requires Clone and PartialEq. A struct with fields also requires serde::Deserialize and schemars::JsonSchema, which build the action from JSON and describe its shape. A unit struct, or a type with no_json, needs neither.

Options go in #[action(...)], separated by commas:

  • namespace = ident prefixes the name, so namespace = editor on Save gives editor::Save. The value is an identifier, not a string.
  • name = "Text" sets the name without a namespace. The name must not contain ::.
  • no_json makes Action::build always return an error and makes Action::action_json_schema return None. The type then doesn’t need Deserialize or JsonSchema.
  • no_register skips registration. The action can’t be invoked by name or built from JSON.
  • deprecated_aliases = ["editor::OldName"] keeps old names working. Each old name must not be the name of a registered action.
  • deprecated = "Message" attaches a deprecation message, which Action::deprecation_message returns.

§Manual implementation

To control every method yourself, implement the trait and call register_action!. It registers the action without the rest of the derive.

use gpui::{SharedString, register_action};
#[derive(Clone, PartialEq, Eq, serde::Deserialize, schemars::JsonSchema)]
pub struct Paste {
    pub content: SharedString,
}

impl gpui::Action for Paste {
}

register_action!(Paste);

Required Methods§

Source

fn boxed_clone(&self) -> Box<dyn Action>

Returns a boxed copy of this action.

Keymaps clone their bindings with this, so each binding owns its own action value.

Source

fn partial_eq(&self, action: &dyn Action) -> bool

Returns whether action is the same action type as self and has equal fields.

Returns false for an action of a different type.

Source

fn name(&self) -> &'static str

Returns the action’s full name, such as editor::MoveUp.

Keymap files refer to actions by this name, and the name is what App::build_action accepts.

Source

fn name_for_type() -> &'static str
where Self: Sized,

Returns the same name as name, for the type rather than a value.

Source

fn build(value: Value) -> Result<Box<dyn Action>>
where Self: Sized,

Builds this action from JSON, as a keymap entry supplies it.

value is {} for an action that takes no input. The derive macro reads value with serde, so the JSON must match the type’s fields. Returns an error if it doesn’t match, and always returns an error for an action declared with no_json. To build an action by name, use App::build_action.

Provided Methods§

Source

fn action_json_schema(_: &mut SchemaGenerator) -> Option<Schema>
where Self: Sized,

Returns the JSON schema of the input this action accepts, or None if it takes no input.

The derive macro fills this in from schemars::JsonSchema. Schema generation for keymap files uses it.

Source

fn deprecated_aliases() -> &'static [&'static str]
where Self: Sized,

Returns the old names that still invoke this action. They are set with the deprecated_aliases option of #[action(...)].

Source

fn deprecation_message() -> Option<&'static str>
where Self: Sized,

Returns the deprecation message, or None if the action isn’t deprecated. It is set with the deprecated option of #[action(...)].

Source

fn documentation() -> Option<&'static str>
where Self: Sized,

Returns the action’s documentation, or None if it has none.

The derive macro and actions! set this from the doc comments on the type.

Implementations§

Source§

impl dyn Action

Source

pub fn as_any(&self) -> &dyn Any

Returns this action as &dyn Any, so that you can downcast it to its concrete type with downcast_ref.

Trait Implementations§

Source§

impl Debug for dyn Action

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§