Welcome to the mound! Termit implements TUI - yet another terminal UI.
Tl;DR:
//! This is an almost minimal hello world termit example.
//!
//! There is no input processing, no async, no looping. Just print some nice screen.
use io;
use *;
For a little more sophisticated example with input event loop and custom widgets, cargo run --example color
. A simplistic Delta.Chat client inspired by the dreamer project is in examples/dech. There are more examples.
Here's a replay of the editor example:
Why?
Back to basics, less line drawing, more content and elegance.
Usage
In your Cargo.toml
:
[]
= "*"
Please note that the API is still evolving. Feedback is most welcome. Ergonomic static UI initialization and dynamic UI updates are somewhat at odds with each other.
Concepts
Termit relies heavily on crossterm. It actually re-exports it as crosterm structs are part of the Termit model.
Widgets maintain their own state
Unlike in some other TUI libs, widgets are not ephemeral unless you want to. You can implement a stateful Widget
easily:
use *;
This is usefult if your widget tracks multiple internal state values which are irrelevant to the application as a whole. For instance, a text box editor doesn't need to polute application state with cursor position.
You may also recreate the whole or part of the UI tree in each update cycle if you want to. Then your widgets must keep their state in the model.
Widgets update the app model directly
Widgets can manipulate the application state model directly.
However, these changes should be near instant. More intensive work (io, network) should be sent to the application as a command and processed independently and ideally asynchronously. This is done in the dech example.
use *;
;
The widget generally accesses the whole app state mutably. It should be possible, though, to create a widget adapter that will focus on a subset of the model or another model alltogether.
Simple widgets, composition and decoration
Avoid creating complex widgets. Instead, add features by wrapping other widgets in decorators or by composing a complex subtree from other widgets.
Look at the [crate::widget::WidgetBinder
] for instance which allows us to load and save any widget, any property of the widget or even replcace it altogether on update. It is a decorator implemented for all impl Widget
's with .bind_with()
:
# use *;
#
The same with [crate::widget::WidgetPropertyBinder
]:
# use *;
#
Company
These are probably some more advanced options.