11 个版本

0.3.2 2022 年 4 月 22 日
0.3.1 2022 年 4 月 10 日
0.2.0 2021 年 10 月 24 日
0.1.6 2021 年 5 月 1 日
0.1.3 2020 年 7 月 26 日

#299命令行界面

Download history 25/week @ 2024-03-11 13/week @ 2024-03-18 17/week @ 2024-03-25 47/week @ 2024-04-01 15/week @ 2024-04-08 11/week @ 2024-04-15 20/week @ 2024-04-22 10/week @ 2024-04-29 6/week @ 2024-05-06 11/week @ 2024-05-13 16/week @ 2024-05-20 8/week @ 2024-05-27 7/week @ 2024-06-03 24/week @ 2024-06-10 8/week @ 2024-06-17 16/week @ 2024-06-24

56 每月下载量
2 crates 中使用

MIT/Apache

150KB
3.5K SLoC

Zi 是一个用于构建现代终端用户界面的库。

Zi 中的用户界面是以有状态的组件树的形式构建的。组件可以让您将 UI 划分为独立的、可重用的部分,并独立考虑每个部分。

App 运行时会跟踪组件的挂载、更新以及最终删除,并且只对需要重新渲染的已更改的 UI 组件调用 view()。位于组件之下的终端后端将只增量重新绘制屏幕上已更改的部分。

基本示例

以下是一个 Zi 应用程序的完整示例,它实现了一个计数器。它应该提供了一个很好的示例,说明了不同的 Component 方法以及它们是如何结合在一起的。

一个包含样式的稍微复杂版本的示例可以在 examples/counter.rs 中找到。

zi-counter-example

熟悉 Yew、Elm 或 React + Redux 的人应该熟悉所有高级概念。此外,某些类型和函数的名称与 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.add("increment", [Key::Char('+')], || Message::Increment);
        bindings.add("increment", [Key::Char('=')], || Message::Increment);

        // 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(()))
}

更多示例可以在 Git 仓库的 examples 目录中找到。

许可协议

该项目受以下任一协议的许可:

任选其一。

贡献

除非您明确说明,否则根据Apache-2.0许可证定义的,您有意提交的任何贡献,应双授权如上所述,不附加任何其他条款或条件。

依赖项

~2.5MB
~39K SLoC