Skip to Content
APIansiq-runtime

ansiq-runtime

ansiq-runtime 是 Ansiq 的运行时入口。它主要负责:

  • App 生命周期
  • RuntimeHandle 提供的消息、任务、history 和 focus 控制接口
  • 主循环、dirty scope 收集、局部 rerender
  • focus 与 input routing

如果你还没先理解这些类型的职责,先读:

App trait

pub trait App { type Message: Send + 'static; fn mount(&mut self, _handle: &RuntimeHandle<Self::Message>) {} fn render(&mut self, cx: &mut ViewCtx<'_, Self::Message>) -> Element<Self::Message>; fn update(&mut self, message: Self::Message, handle: &RuntimeHandle<Self::Message>); fn on_unhandled_key(&mut self, _key: Key, _handle: &RuntimeHandle<Self::Message>) -> bool { false } }

mount(...)

调用时机:

  • terminal session 建立之后
  • 第一次 render(...) 之前

典型用途:

  • 启动后台任务
  • 发送初始消息
  • 建立需要长期存在的连接或采样器

不适合的事情:

  • 直接修改渲染树
  • 在这里手动做布局或 patch

render(...)

render(...) 负责:

  • 描述当前 UI 树
  • 建立本轮响应式读取
  • 暴露组件边界和 continuity key

它不负责:

  • 直接写 terminal
  • 决定 relayout / damage model

update(...)

update(...) 负责:

  • 消费 Message
  • 修改 app state
  • 决定是否继续启动异步工作

最常见的边界是:

async task -> handle.emit(Message) -> update(...) -> state

on_unhandled_key(...)

如果某个按键:

  • 没有被当前 widget 消费
  • 也没有被 runtime 的焦点导航消费

那么它会回到 app 的 on_unhandled_key(...)

适合这里处理的事情:

  • 全局快捷键
  • Escape 取消
  • 模式切换
  • 命令入口
fn on_unhandled_key( &mut self, key: Key, handle: &RuntimeHandle<Self::Message>, ) -> bool { if key == Key::Esc { let _ = handle.emit(Message::Cancel); return true; } false }

RuntimeHandle

RuntimeHandle 是 app 和 runtime 之间最重要的控制面。

消息与任务

handle.emit(Message::Refresh)?; let task_handle = handle.clone(); handle.spawn(async move { let _ = task_handle.emit(Message::Loaded(data)); });

最常用的方法:

  • emit(message):把消息送回 app
  • spawn(future):启动后台任务
  • quit():请求退出主循环

注意:

  • 不要在 spawn(...) 的任务里直接改 UI signal
  • 正确模式始终是 emit -> update -> state

history / scrollback

handle.commit_history("completed turn".to_string())?; handle.commit_history_block(block)?;

这组方法适合:

  • 把已完成 turn 提交到 scrollback
  • 把 live viewport 留给当前活动内容

focus scope

handle.trap_focus_in("composer-panel")?; handle.clear_focus_scope()?;

这组方法适合:

  • modal
  • 弹出层
  • 需要把 Tab 限制在某个子树里的面板

它们依赖的是 continuity key,而不是临时 node id。

最小运行入口

use ansiq_runtime::run_app; #[tokio::main] async fn main() -> std::io::Result<()> { run_app(MyApp::default()).await }

如果你还需要控制 viewport 策略,用 run_app_with_policy(...),见下一页:

Last updated on