2 Action system
Vectornaut edited this page 2026-01-15 00:59:53 +00:00

We plan for all user actions to be mediated through action objects that can be described by commands; saved in an undo history; and triggered by buttons, menu items, and keyboard shortcuts. A rough draft of an action system can be found on the Vectornaut:action-tinkering branch. Here are some design considerations.

Organizing execution code

Action trait

In the current draft, an action is described by an implementation of the Action trait. This trait defines a single method, execute, which takes an application state reference as input. This organization helps streamline the construction of actions, since the execution code doesn't need to be written in the place where the action is constructed.

Stored closures

Alternatively, an action could be represented by a structure that stores the execution code as a pointer to a closure, like a Box or an Rc. This would help us to define actions more flexibly, without having to create a special structure for each one.

Taking input parameters

For buttons, menu items, and keyboard shortcuts, it's useful to have a kind of action that applies a fixed procedure to a reactive input parameter. This factoring makes it easier to reuse the same procedure for command language interpretation, where the input parameter is more tightly bound to the procedure and is known at the time when the action is constructed.

In the current draft, this kind of action is represented by the ParametricAction<T> structure, where:

  • The input parameter is a ReadSignal with a value of type Result<T, String>.
  • The procedure is a boxed closure that maps T values to boxed Action trait objects.

The type parameter T lets us enforce type consistency between the input parameter and the procedure at compile time. Since the input parameter has type Result<T, String>, we still have room to produce the input parameter through runtime type conversion, setting the input parameter to Err if conversion fails.