Skip to Content
内部原理终端 session 与 viewport

终端 session 与 viewport

Ansiq 的 surface 层不负责业务状态,也不负责 widget 语义。
它负责的是另一件非常底层、但又极其关键的事:

把一个普通终端会话变成一个可管理的 runtime viewport。

如果没有这一层,Ansiq 的 runtime 很快就会陷入两个问题:

  • 不知道自己到底能控制终端的哪一块区域
  • 不知道历史输出、live viewport、退出光标位置应该怎么协调

surface 这一层具体负责什么

当前 surface 层负责:

  • 进入和退出 raw mode
  • viewport reservation
  • reanchor 与 resize plan
  • 安全的 exit row 处理

这看起来像 terminal plumbing,但实际上它是一层非常明确的系统边界。

为什么 viewport 不是“顺手分一块 rect”

在 GUI 里,一个 app 往往天然拥有一个窗口。
但在终端里,情况不是这样:

  • 你可能是在 shell 中 inline 启动应用
  • 你可能希望保留上方历史输出
  • 你可能希望应用结束后 shell prompt 回到一个可预测位置

这意味着 runtime 不能假设自己天然拥有整块屏幕。

所以 Ansiq 需要显式建立 viewport 语义:

  • 当前 live 区域从哪里开始
  • 占多少行
  • resize 时怎么调
  • history commit 后怎么重锚
surface 如何建立受管理的 viewport
1进入 terminal session
2根据 ViewportPolicy 解析初始 viewport
3runtime 在 viewport 内绘制 live shell
4resize / history commit 触发 reanchor 或 resize plan
5exit 时恢复终端状态与光标位置

为什么 session 语义必须留在 surface

一个很自然的诱惑是:
“既然 app 更了解自己的布局,那 viewport 和 history 的事是不是也该由 app 管?”

但这样做的问题很明显:

  • 每个 app 都会重新发明自己的终端会话管理
  • runtime 很难给出统一的 patch / exit 语义
  • 历史提交和 live viewport 边界会越来越混乱

因此 Ansiq 的选择是:

  • app 决定自己的 shell 长什么样
  • surface 决定这块 shell 如何和真实 terminal 会话对接

当前有哪些 viewport policy

目前最常见的是:

  • PreserveVisible
  • ReservePreferred
  • ReserveFitContent

它们并不是纯视觉选项,而是在回答不同问题:

PreserveVisible

重点是:

  • 尽量不要扰动当前已有 terminal 内容

适合:

  • 小工具
  • 临时 UI
  • 不需要长期驻留的场景

ReservePreferred

重点是:

  • 给 live viewport 一个偏好的工作高度
  • 但在 history commit / reanchor 后重新收回到这个偏好高度

这非常适合:

  • 会话型应用
  • 有 composer/footer 的终端工作区

ReserveFitContent

重点是:

  • 让 viewport 高度随内容范围变化,但仍然受 clamp 控制

适合:

  • 示例
  • 比较轻的嵌入式 UI

resize 和 reanchor 为什么必须是 plan,而不是直接写 terminal

现在 surface 里已经把这两件事尽量做成了 plan function:

  • resize_viewport_plan
  • reanchor_viewport_plan

这件事的重要性在于:

  • 它们更容易测试
  • 不依赖真实终端行为就能验证
  • 可以先把 terminal 语义算清楚,再去执行 ANSI 操作

这是 Ansiq 在 runtime 成熟化过程里一个很重要的方向:

把“可以纯计算的 terminal 行为”从“真正写 terminal”里拆出来。

为什么历史提交后不应该继续盲目保留扩大的 viewport

这是最近一轮 surface 硬化里非常重要的一个语义:

  • live viewport 可能会因为当前内容而临时增高
  • 但 history commit / reanchor 后,不应把这个临时高度当成新的稳态

否则会出现典型问题:

  • 第一轮对话还正常
  • 第二轮、第三轮之后 viewport 越来越高
  • 最后像整个终端都被应用占满了一样

这也是为什么 ReservePreferred 现在在 commit/reanchor 后会回到 preferred height。

退出时的终端状态为什么也属于 surface

用户真正感受到“这个框架稳不稳”,往往不是看树更新多先进,而是看这些瞬间:

  • 启动时会不会顶掉 shell
  • resize 时会不会乱跳
  • 退出后 prompt 会不会落在奇怪位置

所以 exit_row、safe clamp、raw mode 恢复这些事情都必须在 surface 层被认真对待。
它们不是工程细枝末节,而是产品体验。

这页的结论

terminal session 和 viewport 不是 runtime 的附属品,也不是 app shell 的细节。

它们是 Ansiq 里一层明确的系统边界:

  • runtime 负责更新和 patch
  • app 负责场景结构
  • surface 负责让这些结构在真实终端里安全、稳定、可预测地成立

这一层必须保持 terminal-native,不应该吞掉应用层 shell 语义;但它也不能退化成“只会调用几条 ANSI 命令”的薄封装。

推荐一起阅读

Last updated on