Appearance
Demo:最小 TUI
工程化复现第五部分的组件模型 + 布局 + 差分渲染。源码在 pi-principles/src/tui/,入口在 pi-principles/play/tui.ts。
工程化结构
text
pi-principles/src/tui/
├── component.ts # Component 类型(render(width) → string[])
├── layout.ts # 布局:把组件放进屏幕矩形,渲染成字符网格
└── renderer.ts # 差分渲染:只重写变化行关键实现
组件(component.ts)
ts
export type Component = { render(width: number): string[] };
export function streamingComponent(text: () => string): Component; // 流式打字组件
export function textComponent(line: string): Component; // 静态文本组件布局(layout.ts)
ts
export function layout(components, width, height): Box[]; // 计算每个组件的矩形
export function renderFrame(boxes, width, height): string[]; // 渲染成字符网格差分渲染(renderer.ts)
ts
export function createScreen(): Screen {
return {
prev: [],
emit(next, width) {
for (let i = 0; i < next.length; i++) {
if (this.prev[i] !== next[i]) {
process.stdout.write(`\x1b[${i + 1};1H\x1b[2K${next[i]}`); // 只重写变化行
}
}
this.prev = next;
},
};
}入口与运行
play/tui.ts 组装三个组件,模拟模型逐字输出,看差分渲染只重写最后一行:
bash
cd pi-principles
bun play/tui.ts # 或 npm run tui在真实终端里运行,你会看到前三行只画一次,只有最后一行在逐字追加、被反复重写。
对应到真实源码
| 工程化 Demo | 真实 pi 源码 |
|---|---|
tui/component.ts | packages/tui/src/tui.ts |
tui/layout.ts | packages/tui/src/layout.ts |
tui/renderer.ts | packages/tui/src/tui-main-screen.ts |
理解要点
- 组件是纯函数:
render(width)只受宽度影响,才能被缓存、被差分。 - 布局负责"放哪",组件负责"画什么"。
- 差分只重写变化的行:终端高效的关键。
下一步:6.1 架构总览。