83次发布

0.9.15 2023年12月23日
0.9.14 2023年10月29日
0.9.8 2023年9月10日
0.9.7 2023年4月21日
0.6.9 2022年3月22日

#26 in 文本编辑器

Download history 12/week @ 2024-03-09 5/week @ 2024-03-16 2/week @ 2024-03-23 63/week @ 2024-03-30 8/week @ 2024-04-06 33/week @ 2024-04-13 50/week @ 2024-04-20 266/week @ 2024-04-27 32/week @ 2024-05-04 29/week @ 2024-05-11 44/week @ 2024-05-18 29/week @ 2024-05-25 23/week @ 2024-06-01 18/week @ 2024-06-08 12/week @ 2024-06-15 10/week @ 2024-06-22

69 每月下载量

Apache-2.0

52KB
503

上下文

R3BL TUI & 针对 面向 开发 应用 的开源 工具 套件

我们正在构建基于Rust的命令行应用程序,这些应用程序具有丰富的文本用户界面(TUI)。我们希望利用终端作为提高生产力的场所,并为其构建各种出色的应用程序。

  1. 🔮 我们不仅构建了一个应用程序,我们还构建了一个库,以实现任何类型的丰富TUI开发,并有所创新:将适用于前端移动和Web开发世界的有效概念重新想象为TUI和Rust。
  • 从React、JSX、CSS、Redux、Elm、iced-rs、JetPack Compose等中汲取灵感,但使事物更快、更Rust风格和更简单。例如,我们不是使用Redux进行复杂的状态管理和处理异步中间件函数,而是简单地使用 tokio::mpsc 通道,允许任务向主线程发送信号以重新渲染或将这些信号转发到适当的应用程序逻辑。
  • 运行主事件循环的线程也不阻塞,因为它也是异步的。
  • 使用进程宏创建DSL以实现CSS和JSX。
  1. 🌎 我们正在构建应用程序以增强开发者的生产力和工作流程。
  • 这里的想法不是用Rust重新构建tmux(将多个进程复用到单个终端窗口)。而是构建一套集成“应用程序”(或“任务”),这些任务在同一个进程中运行,渲染到单个终端窗口。
  • 在这个终端窗口内部,我们可以实现诸如“应用程序”切换、路由、分割布局、堆叠布局等功能,以便我们可以管理许多在同一进程中、同一窗口中运行的紧密集成的TUI应用程序。因此,您可以想象所有这些“应用程序”具有共享的应用程序状态(即Redux存储)。每个“应用程序”也可能有自己的Redux存储。
  • 以下是我们计划构建的“应用程序”类型的一些示例(为此基础设施作为开源引擎)
    1. 具有语法高亮的多人文本编辑器。
    2. 与GitHub问题的集成。
    3. 与日历、电子邮件、联系人API的集成。

所有位于 r3bl-open-core 仓库中的crate都提供了许多有用的功能,帮助您构建TUI(文本用户界面)应用程序,同时还有所有Rustaceans 🦀 都能享受的一般优雅和人体工程学。

r3bl_rs_utils crate

tree_memory_arena(非二叉树数据结构)

ArenaMTArena 类型是实现受 非二叉树 启发的数据结构,该结构受 内存区域 的启发。

以下是如何使用 Arena 类型的简单示例

use r3bl_rs_utils::{
  tree_memory_arena::{Arena, HasId, MTArena, ResultUidList},
  utils::{style_primary, style_prompt},
};

let mut arena = Arena::<usize>::new();
let node_1_value = 42 as usize;
let node_1_id = arena.add_new_node(node_1_value, None);
println!("{} {:#?}", style_primary("node_1_id"), node_1_id);
assert_eq!(node_1_id, 0);

以下是如何从区域(树)中获取弱和强引用,以及树遍历

use r3bl_rs_utils::{
  tree_memory_arena::{Arena, HasId, MTArena, ResultUidList},
  utils::{style_primary, style_prompt},
};

let mut arena = Arena::<usize>::new();
let node_1_value = 42 as usize;
let node_1_id = arena.add_new_node(node_1_value, None);

// Access node.
{
  assert!(arena.get_node_arc(&node_1_id).is_some());
  let node_1_ref = dbg!(arena.get_node_arc(&node_1_id).unwrap());
  let node_1_ref_weak = arena.get_node_arc_weak(&node_1_id).unwrap();
  assert_eq!(node_1_ref.read().unwrap().payload, node_1_value);
  assert_eq!(
    node_1_ref_weak.upgrade().unwrap().read().unwrap().payload,
    42
  );
}

// Node does not exist.
{
  let node_id_dne = 200 as usize;
  assert!(arena.get_node_arc(&node_id_dne).is_none());
}

// Walk tree.
{
  let node_1_id = 0 as usize;
  let node_list = dbg!(arena.tree_walk_dfs(&node_1_id).unwrap());
  assert_eq!(node_list.len(), 1);
  assert_eq!(node_list, vec![0]);
}

// Mutate node.
{
  let node_1_id = 0_usize;
  {
    let node_1_ref = dbg!(arena.get_node_arc(node_1_id).unwrap());
    node_1_ref.write().unwrap().payload = 100;
  }
  assert_eq2!(
    arena.get_node_arc(node_1_id).unwrap().read().unwrap().payload,
    100
  );
}

以下是如何使用 MTArena 类型的示例

use std::{
  sync::Arc,
  thread::{self, JoinHandle},
};

use r3bl_rs_utils::{
  tree_memory_arena::{Arena, HasId, MTArena, ResultUidList},
  utils::{style_primary, style_prompt},
};

type ThreadResult = Vec<usize>;
type Handles = Vec<JoinHandle<ThreadResult>>;

let mut handles: Handles = Vec::new();
let arena = MTArena::<String>::new();

// Thread 1 - add root. Spawn and wait (since the 2 threads below need the root).
{
  let arena_arc = arena.get_arena_arc();
  let thread = thread::spawn(move || {
    let mut arena_write = arena_arc.write().unwrap();
    let root = arena_write.add_new_node("foo".to_string(), None);
    vec![root]
  });
  thread.join().unwrap();
}

// Perform tree walking in parallel. Note the lambda does capture many enclosing variable context.
{
  let arena_arc = arena.get_arena_arc();
  let fn_arc = Arc::new(move |uid, payload| {
    println!(
      "{} {} {} Arena weak_count:{} strong_count:{}",
      style_primary("walker_fn - closure"),
      uid,
      payload,
      Arc::weak_count(&arena_arc),
      Arc::weak_count(&arena_arc)
    );
  });

  // Walk tree w/ a new thread using arc to lambda.
  {
    let thread_handle: JoinHandle<ResultUidList> =
      arena.tree_walk_parallel(&0, fn_arc.clone());

    let result_node_list = thread_handle.join().unwrap();
    println!("{:#?}", result_node_list);
  }

  // Walk tree w/ a new thread using arc to lambda.
  {
    let thread_handle: JoinHandle<ResultUidList> =
      arena.tree_walk_parallel(&1, fn_arc.clone());

    let result_node_list = thread_handle.join().unwrap();
    println!("{:#?}", result_node_list);
  }
}

📜还有更多复杂的 ArenaMTArena 的使用方法。请查看这些广泛的集成测试,这些测试将它们置于考验之下 这里

依赖关系

~10–20MB
~156K SLoC