Crate zi

Source
Expand description

Zi is a library for building modern terminal user interfaces.

A user interface in Zi is built as a tree of stateful components. Components let you split the UI into independent, reusable pieces, and think about each piece in isolation.

The App runtime keeps track of components as they are mounted, updated and eventually removed and only calls view() on those UI components that have changed and have to be re-rendered. Lower level and independent of the components, the terminal backend will incrementally redraw only those parts of the screen that have changed.

§A Basic Example

The following is a complete example of a Zi application which implements a counter. It should provide a good sample of the different Component methods and how they fit together.

A slightly more complex version which includes styling can be found at examples/counter.rs.

zi-counter-example

Anyone familiar with Yew, Elm or React + Redux should be familiar with all the high-level concepts. Moreover, the names of some types and functions are the same as in Yew.

use zi::{
    components::{
        border::{Border, BorderProperties},
        text::{Text, TextAlign, TextProperties},
    },
    prelude::*,
};
use zi_term::Result;


// Message type handled by the `Counter` component.
enum Message {
    Increment,
    Decrement,
}

// The `Counter` component.
struct Counter {
    // The state of the component -- the current value of the counter.
    count: usize,

    // A `ComponentLink` allows us to send messages to the component in reaction
    // to user input as well as to gracefully exit.
    link: ComponentLink<Self>,
}

// Components implement the `Component` trait and are the building blocks of the
// UI in Zi. The trait describes stateful components and their lifecycle.
impl Component for Counter {
    // Messages are used to make components dynamic and interactive. For simple
    // or pure components, this will be `()`. Complex, stateful components will
    // typically use an enum to declare multiple Message types. In this case, we
    // will emit two kinds of message (`Increment` or `Decrement`) in reaction
    // to user input.
    type Message = Message;

    // Properties are the inputs to a Component passed in by their parent.
    type Properties = ();

    // Creates ("mounts") a new `Counter` component.
    fn create(
        _properties: Self::Properties,
        _frame: Rect,
        link: ComponentLink<Self>,
    ) -> Self {
        Self { count: 0, link }
    }

    // Returns the current visual layout of the component.
    //  - The `Border` component wraps a component and draws a border around it.
    //  - The `Text` component displays some text.
    fn view(&self) -> Layout {
        Border::with(BorderProperties::new(Text::with(
            TextProperties::new()
                .align(TextAlign::Centre)
                .content(format!("Counter: {}", self.count)),
        )))
    }

    // Components handle messages in their `update` method and commonly use this
    // method to update their state and (optionally) re-render themselves.
    fn update(&mut self, message: Self::Message) -> ShouldRender {
        self.count = match message {
            Message::Increment => self.count.saturating_add(1),
            Message::Decrement => self.count.saturating_sub(1),
        };
        ShouldRender::Yes
    }

   // Updates the key bindings of the component.
   //
   // This method will be called after the component lifecycle methods. It is
   // used to specify how to react in response to keyboard events, typically
   // by sending a message.
   fn bindings(&self, bindings: &mut Bindings<Self>) {
       // If we already initialised the bindings, nothing to do -- they never
       // change in this example
       if !bindings.is_empty() {
           return;
       }
       // Set focus to `true` in order to react to key presses
       bindings.set_focus(true);

       // Increment
       bindings
           .command("increment", || Message::Increment)
           .with([Key::Char('+')])
           .with([Key::Char('=')]);

       // Decrement
       bindings.add("decrement", [Key::Char('-')], || Message::Decrement);

       // Exit
       bindings.add("exit", [Key::Ctrl('c')], |this: &Self| this.link.exit());
       bindings.add("exit", [Key::Esc], |this: &Self| this.link.exit());
   }
}

fn main() -> zi_term::Result<()> {
  zi_term::incremental()?.run_event_loop(Counter::with(()))
}

More examples can be found in the examples directory of the git repository.

Re-exports§

pub use terminal::Background;
pub use terminal::Canvas;
pub use terminal::Colour;
pub use terminal::Foreground;
pub use terminal::Key;
pub use terminal::Position;
pub use terminal::Rect;
pub use terminal::Size;
pub use terminal::Style;
pub use unicode_segmentation;
pub use unicode_width;

Modules§

app
The application runtime. This is low-level module useful when you are implementing a backend, but otherwise not meant to be used directly by an end application.
components
A collection of reusable components useful as building blocks.
layout
The Layout type and flexbox-like utilities for laying out components.
prelude
The Zi prelude.
terminal
An abstract specification of a lightweight terminal.

Structs§

AnyCharacter
Bindings
Callback
Callback wrapper. Useful for passing callbacks in child components Properties. An Rc wrapper is used to make it cloneable.
ComponentKey
Wrapper type for user defined component identity.
ComponentLink
A context for sending messages to a component or the runtime.
Container
A flex container with a specified direction and items.
EndsWith
Item
Represents a flex item, a layout tree nested inside a container.
Keymap
Layout
Represents a layout tree which is the main building block of a UI in Zi.

Enums§

BindingQuery
FlexBasis
Enum to control the size of an item inside a container.
FlexDirection
Enum to control how items are placed in a container. It defines the main axis and the direction (normal or reversed).
NamedBindingQuery
ShouldRender
Type to indicate whether a component should be rendered again.

Traits§

Component
Components are the building blocks of the UI in Zi.
ComponentExt