1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//! 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`](app/struct.App.html) 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`](trait.Component.html) methods and how they fit together.
//!
//! A slightly more complex version which includes styling can be found at
//! `examples/counter.rs`.
//!
//! ![zi-counter-example](https://user-images.githubusercontent.com/797170/137802270-0a4a50af-1fd5-473f-a52c-9d3a107809d0.gif)
//!
//! 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`.
//!
//! ```ignore
//! 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.

pub mod app;
pub mod components;
pub mod terminal;

pub use component::{
    bindings::{AnyCharacter, BindingQuery, Bindings, EndsWith, Keymap, NamedBindingQuery},
    layout::{self, ComponentExt, ComponentKey, Container, FlexBasis, FlexDirection, Item},
    Callback, Component, ComponentLink, Layout, ShouldRender,
};
pub use terminal::{Background, Canvas, Colour, Foreground, Key, Position, Rect, Size, Style};

pub mod prelude {
    //! The Zi prelude.
    pub use super::{
        AnyCharacter, Bindings, Component, ComponentExt, ComponentLink, Container, FlexBasis,
        FlexDirection, Item, Layout, ShouldRender,
    };
    pub use super::{Background, Canvas, Colour, Foreground, Key, Position, Rect, Size, Style};
}

// Re-export 3rd party libraries to do with unicode segmentation.
//
// It is helpful to ensure downstream use the same version as zi to ensure any code relying on
// unicode segmentation matches what zi does internally.
pub use unicode_segmentation;
pub use unicode_width;

// Crate only modules
pub(crate) mod component;
pub(crate) mod text;