Ink 终端 UI 框架
概述
Codev 的 Ink 是基于 vadimdemedes/ink v6 的深度定制分叉(fork)。Ink 使用 React 组件模型渲染终端用户界面。它将 React 的虚拟 DOM 映射到终端字符网格,支持 Yoga Flexbox 布局、样式继承、事件处理、文本选择、搜索高亮等丰富的交互能力。
与上游相比,Codev 的 Ink 新增/修改了以下核心能力:自定义 DOM 节点树、压缩屏幕缓冲区(Int32Array)、基于 Yoga WASM 的布局引擎、Kitty 键盘协议支持、SGR 鼠标跟踪、文本选择模式、搜索高亮、双向文本处理、scrollable 容器、声明式光标位置等。
核心架构
Ink 的渲染管线分为以下几个层次:
React 组件树
│
▼
React Reconciler (自定义 Fiber 协调器)
│
▼
DOM 节点树 (ink-root, ink-box, ink-text, ...)
│
▼
Yoga 布局引擎 (WASM Flexbox)
│
▼
Renderer → Output (screen buffer)
│
▼
LogUpdate (差异比较)
│
▼
Patch[] → ANSI 序列 → stdout
Ink 主类
文件:src/ink/ink.tsx
Ink 类(约 1723 行)管理整个渲染生命周期:
- 构造函数:设置
LogUpdate、节流渲染调度器(scheduleRender,使用FRAME_INTERVAL_MS=16ms)、FocusManager、YogaonComputeLayout回调、React reconciler 容器 - **
onRender()**:核心帧循环,每个渲染周期执行以下步骤:- 调用
createRenderer执行 DOM → Yoga 布局 → 屏幕缓冲区的渲染 - 处理选择滚动追踪
- 应用选择/搜索覆盖层
- 全损坏回退(full-damage backstop)
- 计算差异(diff)
- 缓冲池交换
- 补丁优化与序列化
- 光标定位(原生光标或声明式光标)
- 写入 stdout
- 调用
- 选择管理:
startSelection,extendSelection,wordSelect,lineSelect,dragScrollCapture,shiftSelection - stdin 挂起/恢复:用于外部编辑器集成
- 控制台/stderr 补丁:拦截 console.log 等输出重定向
- drainStdin:清理时清空 stdin 缓冲区
React Reconciler(协调器)
文件:src/ink/reconciler.ts
使用 react-reconciler 包创建自定义 Fiber 协调器,将 React 组件映射到 Ink 的 DOM 节点。
关键宿主配置:
| 钩子 | 说明 |
|---|---|
createInstance |
创建 DOMElement(ink-box, ink-text 等),在 <Text> 内部嵌套时将 ink-text 转换为 ink-virtual-text |
createTextInstance |
创建 TextNode,要求必须在 <Text> 内使用 |
commitUpdate |
React 19 使用新旧 props 直接比较,调用 setStyle, setAttribute, setTextStyles, setEventHandler |
commitTextUpdate |
更新文本节点 |
appendChild / insertBefore / removeChild |
DOM 树操作,同步更新 Yoga 节点树 |
resetAfterCommit |
提交后触发 onComputeLayout(Yoga 布局)和 onRender(渲染帧) |
hideInstance / unhideInstance |
设置/取消 Yoga display: none |
调试工具:
getOwnerChain():从 React Fiber_debugOwner提取组件名链,用于识别重绘来源CLAUDE_CODE_DEBUG_REPAINTS环境变量:启用后记录组件树归属CLAUDE_CODE_COMMIT_LOG:记录提交/渲染性能日志
DOM 节点树
文件:src/ink/dom.ts
自定义 DOM 树,与浏览器 DOM 不同,专为终端渲染优化。
节点类型:
| 节点名 | 说明 |
|---|---|
ink-root |
根节点,持有 FocusManager |
ink-box |
容器(类似 <div>),有 Yoga 节点 |
ink-text |
文本容器,有测量函数 |
ink-virtual-text |
<Text> 内嵌套的文本,无 Yoga 节点 |
ink-link |
超链接,无 Yoga 节点 |
ink-progress |
进度条,无 Yoga 节点 |
ink-raw-ansi |
预渲染 ANSI 字符串,固定尺寸测量 |
#text |
文本叶子节点 |
DOM 操作:
createNode()/createTextNode()—— 创建节点appendChildNode()/insertBeforeNode()/removeChildNode()—— DOM 树操作,同步更新 Yoga 节点setStyle()/setAttribute()/setTextStyles()—— 属性更新,含脏检测(shallow equal 跳过未变更的渲染)markDirty()—— 标记节点及其所有祖先为脏scheduleRenderFrom()—— 从指定节点触发渲染(用于非 React 触发的 DOM 变更)
脏标记(Dirty Flag):每个 DOMElement 有 dirty 属性(boolean),markDirty() 从当前节点向上遍历直到根节点。渲染完成后清除。这允许增量重绘 —— 只有脏子树被重新布局和渲染。
Screen(屏幕缓冲区)
文件:src/ink/screen.ts
Screen 是终端渲染的核心数据结构,使用压缩的 Int32Array 存储每个单元格,避免为每个单元格分配对象(200x120 屏幕可避免分配 24000 个对象)。
单元格存储布局: 每个单元格占用 2 个 Int32(共 8 字节):
word0:字符 ID(索引到CharPool,32 位)word1:styleId[31:17] | hyperlinkId[16:2] | width[1:0]
池化系统:
| 池 | 说明 |
|---|---|
CharPool |
字符字符串池,共享跨所有屏幕。ASCII 字符使用 Int32Array 快速查找;非 ASCII 使用 Map。索引 0 固定为空格,索引 1 为 spacer 空字符串。 |
StylePool |
ANSI 样式池,位 0 标识样式是否在空格上可见(背景色、反色、下划线等)。提供 transition(fromId, toId) 方法生成缓存的 ANSI 过渡字符串。withInverse()、withCurrentMatch()、withSelectionBg() 用于选择/搜索覆盖层。 |
HyperlinkPool |
OSC 8 超链接池,索引 0 表示无链接。 |
单元格宽度枚举(CellWidth):
| 值 | 名称 | 说明 |
|---|---|---|
| 0 | Narrow | 单宽字符 |
| 1 | Wide | 宽字符(CJK、emoji),占用两列 |
| 2 | SpacerTail | 宽字符的第二列占位符 |
| 3 | SpacerHead | 软换行时在行尾标记宽字符延续 |
关键函数:
createScreen()—— 创建屏幕,8 字节/单元格的 ArrayBufferresetScreen()—— 重用屏幕,使用BigInt64Array.fill()快速清空setCellAt()—— 写入单元格,自动创建宽字符的 SpacerTailsetCellStyleId()—— 仅更新样式 ID,用于选择/搜索覆盖层cellAt()/cellAtIndex()—— 读取单元格diff()/diffEach()—— 比较两个屏幕,使用findNextDiff()快速跳过相同区域blitRegion()—— 批量复制矩形区域(TypedArray.set())clearRegion()—— 快速清空矩形区域shiftRows()—— 行位移(copyWithin),用于 DECSTBM 滚动优化markNoSelectRegion()—— 标记选择排除区域migrateScreenPools()—— 跨代池重置时重新 intern
Output(输出缓冲)
文件:src/ink/output.ts
收集渲染操作(Operations),在 get() 中统一应用到 Screen 缓冲区。
操作类型:
| 类型 | 说明 |
|---|---|
write |
写入 ANSI 文本到指定位置 |
blit |
复制源屏幕的矩形区域 |
clear |
清空矩形区域 |
clip / unclip |
裁剪区域(嵌套 overflow:hidden) |
shift |
行位移 |
noSelect |
标记选择排除区域(最后应用) |
字符缓存(charCache):
每行文本经过 tokenize(ANSI 解析)、grapheme 聚类、双向文本重排、样式 ID + 超链接预计算后缓存。大多数行在帧间不变,缓存命中后只需读取属性并调用 setCellAt()。
**writeLineToScreen()**:
核心写入函数,处理:
- C0 控制字符(tab → 空格展开,ESC → CSI/single-char 序列跳过)
- 零宽字符(组合标记等)静默跳过
- 宽字符在行尾时放置 SpacerHead
- 写时损坏区域追踪(
screen.damage)
LogUpdate(差异比较与补丁生成)
文件:src/ink/log-update.ts
比较前一帧和当前帧的 Screen 缓冲区,生成最小补丁序列(Diff = Patch[])。
补丁类型:
| 类型 | 说明 |
|---|---|
stdout |
原始 ANSI 字符串输出 |
clear |
清空 N 行 |
clearTerminal |
完全清屏(全损坏,引发闪烁) |
cursorHide / cursorShow |
光标显隐 |
cursorMove |
光标相对移动 |
cursorTo |
光标绝对定位到列 |
carriageReturn |
CR |
hyperlink |
OSC 8 超链接 |
styleStr |
预序列化的 ANSI 样式过渡字符串 |
DECSTBM 滚动优化:
当 ScrollBox 的 scrollTop 变化时,使用硬件滚动(CSI top;bottom r + CSI n S/T)替代重写整个滚动区域,大幅减少输出字节。
全损坏重置(fullResetSequence_CAUSES_FLICKER):
在以下情况触发终端完全清屏:
- 终端尺寸变化(resize)
- 内容高度超出视口后又缩小到视口内
- 需要更新的行在滚动缓冲区中(不可达)
- 这些重置会引发可见的闪烁
VirtualScreen:
内部辅助类,追踪虚拟光标位置和差异补丁列表,支持事务性操作(txn())批量提交补丁。
Frame(帧结构)
文件:src/ink/frame.ts
type Frame = {
screen: Screen // 屏幕缓冲区
viewport: Size // 视口尺寸
cursor: Cursor // 光标状态
scrollHint?: ScrollHint // DECSTBM 滚动提示
scrollDrainPending?: boolean // 是否需要继续帧
}
辅助函数:
shouldClearScreen()—— 判断是否需要清屏(resize 或 offscreen)emptyFrame()—— 创建空帧
布局引擎(Yoga)
文件:src/ink/layout/ 目录
使用 Yoga 的 WASM 实现进行 Flexbox 布局计算。
在渲染管线中的位置:
- React commit 后,
resetAfterCommit调用rootNode.onComputeLayout() ink.tsx中的onComputeLayout调用root.yogaNode.calculateLayout()- Yoga 执行完整的 Flexbox 布局计算(含
measureFunc回调用于文本测量) - Renderer 读取
getComputedWidth/Height/Top/Left获取布局结果
布局节点:文件 src/ink/layout/node.ts,定义 LayoutNode 接口和所有布局常量(LayoutEdge, LayoutDisplay, LayoutFlexDirection, LayoutJustify, LayoutAlign, LayoutOverflow, LayoutPositionType, LayoutWrap, LayoutGutter)。
布局引擎:文件 src/ink/layout/engine.ts,创建和管理 Yoga WASM 实例。提供 createLayoutNode() 和 getYogaCounters() 等函数。
测量函数:
ink-text:measureTextNode()—— 处理文本换行、tab 展开、bi-di 重排ink-raw-ansi:measureRawAnsiNode()—— 使用预设的 rawWidth/rawHeight
样式系统
文件:src/ink/styles.ts
样式类型定义(Styles)涵盖所有 CSS Flexbox 属性:
布局:display, position, overflow, flexDirection, flexWrap, flexGrow, flexShrink, flexBasis, alignItems, alignSelf, justifyContent
尺寸:width, height, minWidth, maxWidth, minHeight, maxHeight(支持数值和百分比字符串)
间距:margin, padding, gap(含 X/Y 方向缩写)
边框:borderStyle(圆角/单线/双线等), borderColor, borderTop/Right/Bottom/Left(控制各边显隐)
文本:textWrap(8 种模式:wrap, wrap-trim, end, middle, truncate-end, truncate, truncate-middle, truncate-start)
其他:backgroundColor, opaque, noSelect(选择排除), borderText(边框内文本)
applyStyles() 函数将 Styles 对象映射到 Yoga 节点属性。每个样式类别有独立的函数(applyPositionStyles, applyOverflowStyles, applyFlexStyles 等)。
TextStyles
文件:src/ink/styles.ts
type TextStyles = {
color?, backgroundColor? // 颜色
dim?, bold?, italic? // 字体样式
underline?, strikethrough? // 装饰
inverse? // 反色
}
TextStyles 在 <Text> 组件中声明,通过 ink-text 节点的 textStyles 属性传递。渲染时由 render-node-to-output.ts 的 buildTextStyles() 转换为 ANSI SGR 序列。
事件系统
键盘事件
Kitty 键盘协议:在 raw mode 中启用 CSI u 扩展键编码(ENABLE_KITTY_KEYBOARD + ENABLE_MODIFY_OTHER_KEYS),使 Ctrl+Shift+字母 与 Ctrl+字母 可区分。终端识别通过在 XTVERSION 查询后设置。
输入解析:文件 src/ink/parse-keypress.ts,状态机解析 stdin 的原始字节流。支持:
- 普通字符(UTF-8)
- CSI 序列(方向键、功能键等)
- Kitty CSI u 序列(带修饰键编码)
- SGR 鼠标编码(
<row;col;button M/m) - DEC 私有模式响应(DCS 序列)
- OSC 序列(操作系统命令)
- 粘贴模式(
IN_PASTE状态)
App 组件中的处理(文件 src/ink/components/App.tsx):
handleReadable()—— stdinreadable事件回调processInput()—— 调用parseMultipleKeypresses()解析多按键processKeysInBatch()—— 在reconciler.discreteUpdates中批量处理按键,避免"最大更新深度超出"错误- 处理
Ctrl+C(退出)、Ctrl+Z(挂起)、终端焦点事件(DECSET 1004)
鼠标事件
通过 DECSET 1003(SGR 鼠标跟踪)启用/禁用。
processKeysInBatch 中的鼠标处理(handleMouseEvent()):
- press:开始选择、多击检测(双击选中单词、三击选中行)
- drag:扩展选择(字符/单词/行模式)
- release:结束选择
- no-button motion(模式 1003):悬停事件分发(
onMouseEnter/onMouseLeave) - 超链接:单点击时延迟打开,双击取消
handleMouseEvent() 中的选择逻辑:
startSelection()/finishSelection()/hasSelection()- 多击跟踪:
clickCount在 500ms 内递增,支持双击单词选择和三击行选择 lastPressHadAlt:记录 Alt 修饰键,用于终端判定
焦点管理
文件:src/ink/focus.ts
FocusManager 存储在每个根节点,类似于浏览器 document.activeElement。
功能:
focus(node)/blur()—— 获取/失去焦点handleNodeRemoved()—— 节点移除时自动恢复焦点到栈中上一个handleAutoFocus()—— 自动聚焦(autoFocusprop)handleClickFocus()—— 点击聚焦(tabIndexprop)focusNext()/focusPrevious()—— Tab / Shift+Tab 导航
焦点栈:最多 32 层,用于节点移除后的焦点恢复。
事件分发:事件系统使用 Dispatcher 类(src/ink/events/dispatcher.ts)处理捕获(Capture)和冒泡(Bubble)阶段。EVENT_HANDLER_PROPS 集合定义哪些 props 是事件处理器(onClick, onKeyDown 等)。
组件库
文件:src/ink/components/
| 组件 | 文件 | 说明 |
|---|---|---|
App |
App.tsx |
根组件,管理 stdin/stdout、raw mode、光标、挂起/恢复、事件分发、多击选择 |
Box |
Box.tsx |
布局容器(类似 <div>),支持完整 Flexbox 样式和事件处理器(onClick, onKeyDown, onMouseEnter, onMouseLeave, onFocus, onBlur) |
Text |
Text.tsx |
文本组件,支持颜色(color, backgroundColor)、加粗(bold)、斜体(italic)、下划线(underline)、删除线(strikethrough)、反色(inverse)、换行模式(wrap) |
Button |
Button.tsx |
按钮组件(继承 Box 的点击能力) |
Link |
Link.tsx |
超链接(使用 OSC 8 协议),终端不支持时回退到纯文本 |
Spacer |
Spacer.tsx |
弹性空间填充(flexGrow: 1) |
Newline |
Newline.tsx |
插入空白行 |
ScrollBox |
ScrollBox.tsx |
滚动容器(overflow: scroll),支持 scrollTo(), scrollToElement() 和粘性滚动 |
AlternateScreen |
AlternateScreen.tsx |
替代屏幕(alt-screen)管理 |
RawAnsi |
RawAnsi.tsx |
原始 ANSI 字符串渲染(预计算的宽度和高度) |
NoSelect |
NoSelect.tsx |
选择排除区域(如行号、diff 标记) |
Ansi |
(在 ink.ts 中 re-export) | ANSI 文本渲染 |
ErrorOverview |
ErrorOverview.tsx |
错误概览组件 |
Context 提供者:
| Context | 文件 | 提供内容 |
|---|---|---|
AppContext |
AppContext.ts |
exit() 退出函数 |
StdinContext |
StdinContext.ts |
stdin, setRawMode, internal_eventEmitter, internal_querier |
TerminalSizeContext |
TerminalSizeContext.tsx |
columns, rows 终端尺寸 |
TerminalFocusContext |
TerminalFocusContext.tsx |
isTerminalFocused 终端焦点状态 |
ClockContext |
ClockContext.tsx |
时钟/定时器(根据焦点状态调整间隔) |
CursorDeclarationContext |
CursorDeclarationContext.ts |
声明式光标位置 |
Hooks
文件:src/ink/hooks/
| Hook | 文件 | 说明 |
|---|---|---|
useInput |
use-input.ts |
处理用户键盘输入(useLayoutEffect 同步启用 raw mode),注册 input 事件监听器 |
useStdin |
use-stdin.ts |
访问 stdin/setRawMode/EventEmitter |
useApp |
use-app.ts |
访问 exit() 函数 |
useAnimationFrame |
use-animation-frame.ts |
动画帧钩子(使用 FRAME_INTERVAL_MS=16ms 节流渲染) |
useInterval |
use-interval.ts |
定时器(终端失焦时可选减速) |
useSelection |
use-selection.ts |
文本选择状态管理(anchor, focus, word/line 模式) |
useSearchHighlight |
use-search-highlight.ts |
搜索高亮状态(匹配位置、当前匹配导航) |
useDeclaredCursor |
use-declared-cursor.ts |
声明式光标位置(用于 IME 输入和屏幕阅读器) |
useTabStatus |
use-tab-status.ts |
Tab 状态管理 |
useTerminalFocus |
use-terminal-focus.ts |
终端焦点变化监听 |
useTerminalTitle |
use-terminal-title.ts |
终端标题设置 |
useTerminalViewport |
use-terminal-viewport.ts |
终端视口信息 |
文本选择
文件:src/ink/selection.ts
SelectionState 管理全屏模式下的文本选择:
- anchor:选择起点(鼠标按下处)
- focus:选择终点(鼠标拖动处)
- anchorSpan:多击(双击/三击)时初始单词/行的范围
- scrolledOffAbove/Below:选择过程中滚动出视口的文本
- softWrap 标记:跟踪软换行位置
选择操作:
startSelection()/updateSelection()/finishSelection()extendSelection()—— 字符/单词/行模式扩展getSelectedText()—— 获取选中文本(拼接跨行的选择,含滚动出视口的文本)applySelectionOverlay()—— 在屏幕覆盖层中高亮选中区域
搜索高亮
文件:src/ink/render-to-screen.ts 和 src/ink/components/App.tsx
搜索高亮系统分为两个层次:
renderToScreen()—— 在独立屏幕缓冲区中渲染单个消息,扫描查询字符串的位置applySearchHighlight()/applyPositionedHighlight()—— 将搜索匹配覆盖层应用到实际屏幕
匹配视觉风格:
- 普通匹配:反色(SGR 7,白色底,从主题继承)
- 当前匹配(用户导航到的位置):黄色背景(通过黄色前景 + 反色实现)+ 加粗 + 下划线
渲染管线完整流程
从 React 组件到终端输出的完整流程:
1. React 更新 (setState / 新 props)
│
2. Reconciler commit (resetAfterCommit)
├── onComputeLayout: Yoga calculateLayout()
└── onRender: scheduleRender (节流, 16ms)
│
3. createRenderer → renderNodeToOutput
├── 递归遍历 DOM 树
├── 应用 scrollTop 偏移
├── 写操作 -> Output buffer
└── blit 操作 -> Output buffer
│
4. Output.get()
├── 应用所有操作到 Screen
├── 处理裁剪区域
├── 处理 absolute 清除
└── 更新 softWrap 标记
│
5. LogUpdate.render()
├── 检查是否要全损坏重置
├── DECSTBM 滚动优化
├── diffEach 比较前后帧
├── 处理增长/收缩
└── 生成 Patch[]
│
6. optimize() — 补丁合并与去重
│
7. writeDiffToTerminal() — 补丁序列化为 ANSI → stdout
│
8. 屏幕选择/搜索覆盖层更新
│
9. 光标定位
└── 下一帧
特殊功能
双缓冲(Double Buffering)
使用前后帧(frontFrame / backFrame)实现双缓冲:
backFrame.screen是当前渲染目标frontFrame.screen是前一帧的屏幕,用于差异比较和 blit- 渲染帧切换后进行缓冲池交换(
swapFrames())
屏幕伤害追踪(Damage Tracking)
每个 Screen 有一个 damage 矩形区域,记录自上次重置以来发生写操作的区域。diffEach() 只扫描损伤区域,避免遍历整个屏幕。
双向文本(BiDi)
文件:src/ink/bidi.ts
使用 Unicode Bidirectional Algorithm 对文本行进行重排。在 writeLineToScreen() 中,每行文本在 tokenize 和 grapheme 聚类后执行 reorderBidi()。
ANSI 解析与 Grapheme 聚类
使用 @alcalzone/ansi-tokenize 解析 ANSI 序列,然后通过 Intl.Segmenter 进行 grapheme 聚类(支持家族 emoji 等多码点字符)。结果缓存到 charCache,帧间重用。
终端查询(Terminal Querier)
文件:src/ink/terminal-querier.ts
TerminalQuerier 通过 DEC 请求序列(如 DA1、XTVERSION、DECRPM)与终端通信。它维护一个待处理请求的 Promise 队列,在收到终端响应时解析相应的 Promise。
DEC 私有模式
文件:src/ink/termio/dec.ts
管理 DEC 私有模式:
- 鼠标跟踪:
ENABLE_MOUSE_TRACKING(SGR, 1003)/DISABLE_MOUSE_TRACKING - 光标显隐:
HIDE_CURSOR/SHOW_CURSOR - 焦点报告:
EFE/DFE(DECSET 1004) - 滚轮支持:通过
DECRPM查询终端能力
Kitty 键盘协议
文件:src/ink/termio/ansi.ts 和 src/ink/termio/csi.ts
通过 CSI >1u(Kitty 协议)和 CSI >4;2m(xterm modifyOtherKeys)启用扩展键盘报告,使修饰键组合(Ctrl+Shift+A 等)可区分。
替代屏幕(Alt Screen)
<AlternateScreen> 组件管理终端的替代屏幕缓冲区。启用时:
- 内容始终恰好占满终端行数
- 光标隐藏
- 启用 DECSET 1000/1002/1003 鼠标跟踪
- 支持 DECSTBM 滚动优化
- 退出时恢复主屏幕内容
声明式光标(Declared Cursor)
useDeclaredCursor 钩子和 CursorDeclarationContext 允许组件声明当前光标位置(如输入框),使 Ink 在每一帧后将终端光标放置在该位置,支持 IME 输入和屏幕阅读器。
滚动容器(ScrollBox)
<ScrollBox> 组件(overflow: scroll)实现:
scrollTop:可编程滚动位置pendingScrollDelta:累积的滚动增量(限制 SCROLL_MAX_PER_FRAME 行/帧,防止大幅跳动)stickyScroll:粘性滚动(内容增长时自动保持在底部)scrollTo(y)/scrollToElement(el, offset):可编程滚动scrollHeight/scrollViewportHeight:滚动信息查询scrollClampMin/scrollClampMax:虚拟滚动边界保护- 渲染时通过
output.shift()实现 DECSTBM 硬件滚动
选择排除(NoSelect)
<NoSelect> 组件标记区域为选择排除:
noSelect模式:仅排除该盒子的精确区域from-left-edge模式:从第 0 列到盒子右边缘的整行区域screen.noSelect位图每帧重置,blitRegion复制时连带复制
调试与性能分析
CLAUDE_CODE_DEBUG_REPAINTS:追踪重绘来源组件CLAUDE_CODE_COMMIT_LOG:记录提交/渲染时间日志- YOGA 计数器:
getYogaCounters()报告每个框架的节点访问、测量、缓存命中 FRAME_INTERVAL_MS = 16:60fps 帧率- Blit/Write 比率日志:高频写入(而非 blit)时发出警告
文件索引
按功能类别整理的核心文件:
| 类别 | 文件 |
|---|---|
| 主入口 | src/ink.ts, src/ink/ink.tsx |
| DOM | src/ink/dom.ts |
| Reconciler | src/ink/reconciler.ts |
| Renderer | src/ink/renderer.ts, src/ink/render-node-to-output.ts |
| Screen | src/ink/screen.ts |
| Output | src/ink/output.ts |
| LogUpdate | src/ink/log-update.ts |
| Frame | src/ink/frame.ts |
| Styles | src/ink/styles.ts |
| Focus | src/ink/focus.ts |
| Selection | src/ink/selection.ts |
| Layout | src/ink/layout/engine.ts, node.ts |
| Event Dispatcher | src/ink/events/dispatcher.ts |
| Event Handlers | src/ink/events/event-handlers.ts |
| Components | src/ink/components/ (App, Box, Text, Button, Link, Spacer, Newline, ScrollBox, AlternateScreen, RawAnsi, NoSelect, ErrorOverview) |
| Hooks | src/ink/hooks/ (use-input, use-stdin, use-app, use-animation-frame, use-interval, use-selection, use-search-highlight, use-declared-cursor, use-tab-status, use-terminal-focus, use-terminal-title, use-terminal-viewport) |
| Termio | src/ink/termio/ansi.ts, csi.ts, dec.ts, osc.ts |
| Bidi | src/ink/bidi.ts |
| Constants | src/ink/constants.ts |
| Contexts | src/ink/components/AppContext.ts, StdinContext.ts, TerminalSizeContext.tsx, TerminalFocusContext.tsx, ClockContext.tsx, CursorDeclarationContext.ts |