历史与 scrollback
一旦你的终端应用不只是“当前屏幕长什么样”,而开始有:
- 多轮会话
- 已完成内容
- 当前 live viewport
- sticky footer 或 composer
你就不能再把“历史”当成普通文本输出看待了。
在 Ansiq 里,history 和 scrollback 是一个显式 surface 语义,不是 incidental implementation detail。
当前模型是什么
Ansiq 现在会在 commit 时把历史提交到 terminal scrollback。
这意味着:
- 已完成内容会离开 live viewport
- live viewport 保留当前活跃区域
- scrollback 变成用户查看历史的主要方式
这条模型很适合:
- 长时间运行的会话型应用
- agent shell
- transcript / log 风格界面
1当前 turn 在 live viewport 里增长
2应用决定这个 turn 已完成
3history entry 归一化成 block
4surface 把 block 提交到 scrollback
5live viewport 继续保留当前活跃区域
当前行为
- history 按提交时宽度 wrap
- 之后 resize 不会让已提交历史 reflow
Text和Block现在走同一条 commit-time wrap 路径
这些行为不是临时巧合,而是当前的明确设计选择。
为什么“提交时 wrap”是一个 tradeoff
从纯理论上讲,最理想的行为似乎是:
- 历史提交后也能随着终端宽度变化重新换行
但在真实终端里,这件事并不免费。
一旦内容已经被提交到 scrollback,它就已经离开了 live viewport 管辖的区域。
要让它在 resize 后重新排版,你需要:
- 重新控制滚回去的所有历史内容
- 重新生成文本
- 重新覆盖终端已有 scrollback
这在大多数 terminal 模式下并不现实,也会带来非常复杂的副作用。
所以 Ansiq 目前明确选择了更朴素、也更 terminal-native 的策略:
- commit 时按当前宽度 wrap
- 一旦进入 scrollback,就不再重新流式布局
为什么这件事必须写进文档
因为如果不把它写清楚,用户会把它误解成 bug:
- “为什么 live viewport resize 后会重新排版,但历史不会?”
答案是:
- live viewport 仍属于 runtime 管辖
- scrollback 已经是 terminal 自己的历史输出
两者不是同一层。
Text 和 Block 为什么必须统一
之前 HistoryEntry::Text 和 HistoryBlock 走的是两条略有差异的路径,这会导致:
- 同样是历史内容
- 一部分在 commit 时按一种规则换行
- 另一部分按另一种规则换行
这会让“历史”在视觉上失去一致性。
现在文档里可以明确写成:
- 历史提交会先归一化成统一 block 模型
- 再走同一条 scrollback 渲染路径
这样至少保证了:
同一类历史语义,在同一终端宽度下会有一致行为。
什么时候该 commit,什么时候不该 commit
这其实是产品语义问题,不是渲染细节。
你应该先回答:
- 什么叫“已完成”
- 哪部分内容属于 live 区
- 哪部分内容应该进入 scrollback
例如:
- 对话应用里,已完成 turn 可以 commit
- 活动监视器这类固定壳层应用,主内容通常不该 commit
- 结构化浏览器里,左中右 pane 也不该被当作 history
也就是说,history 模型并不是每个应用都需要。
这一页真正想说明什么
在 Ansiq 里,history / scrollback 不是“把字符串打印出去”这么简单。
它是一个明确的架构边界:
- live viewport 由 runtime 管理
- committed history 由 terminal scrollback 接管
- commit-time wrap 是一个显式 tradeoff
只有把这条边界说清楚,用户才能正确理解 resize、history 和 viewport 的行为差异。
推荐一起阅读
Last updated on