Cline CLI 的 OpenTUI 文本显示组件:text、ascii-font 与 RGBA 颜色体系实战指南
Cline 的 CLI(TUI)界面基于 OpenTUI 构建,其中承载所有可见信息的正是文本显示组件体系:text、内联修饰标签(span/strong/em 等)以及 ascii-font 大标题横幅。本文基于仓库内技能参考文档 text-display.md 完整展开,并结合 apps/cli 中真实组件代码,讲清这三种 API 范式(Core 命令式、React、Solid)下如何正确编写样式文本、使用 t 模板与 RGBA 颜色对象,以及如何避开“样式不生效”等典型陷阱。读完你能够独立为终端界面编写带颜色、富文本与动态内容的显示层。
一、背景:Cline CLI 中的 OpenTUI 版本与文本组件定位
Cline CLI 通过以下依赖引入 OpenTUI(见 根 package.json 与 apps/cli/package.json):
@opentui/core0.4.3 —— 命令式核心渲染 API;@opentui/react0.4.3 —— React 调和器(reconciler),Cline CLI 的 TUI 主体即采用此范式;@opentui-ui/dialog0.1.2(仓库在 patches/ 中对其打了本地补丁)。
在该技能体系里,OpenTUI 提供了三种编写 TUI 的路径(参见 SKILL.md 的决策树):Core 适合需要完全控制与极致性能的场景,React 适合熟悉组件化开发的人,Solid 适合需要细粒度响应式的场景。文本显示文档正是“我需要展示内容”这一分支下的第一站:纯文本或带样式文本走 text,ASCII 艺术横幅走 ascii-font。
二、Text 组件基础用法
text 是显示文本的主力组件,三种范式各有一套写法。
React/Solid(声明式):
// React/Solid
<text>Hello, World!</text>
// 用 content prop 传内容
<text content="Hello, World!" />
Core(命令式):
const text = new TextRenderable(renderer, {
id: "greeting",
content: "Hello, World!",
})
在 Cline CLI 源码中可以找到与上述完全一致的用法,例如 chat-entry.tsx 中的 <text fg="red">x</text> 与 <text fg={planAccent} content="* " />——属性与子节点两种传内容方式在真实业务组件里混用。
三、React/Solid 样式化:嵌套修饰标签(最重要的规则)
这是文档中最容易被违反的一条规则:React/Solid 中不要给 <text> 直接传 bold、italic、underline、dim、strikethrough 属性——它们不生效。必须使用嵌套的修饰标签:
<text fg="#FFFFFF" bg="#000000">
<strong>Bold</strong>, <em>italic</em>, and <u>underlined</u>
</text>
可用的内联修饰元素完整清单如下,它们只能出现在 <text> 内部:
| 元素 | 作用 | 示例 |
|---|---|---|
<span fg="..." /> |
内联着色片段 | Normal text with <span fg="red">red text</span> inline |
<strong> / <b> |
加粗 | <strong>Bold text</strong> |
<em> / <i> |
斜体 | <em>Italic text</em> |
<u> |
下划线 | <u>Underlined text</u> |
<br /> |
换行 | Line one<br />Line two |
<a href="..." /> |
链接 | Visit <a href="https://example.com">our website</a> |
修饰符可以任意组合嵌套,例如:
<text>
<span fg="#00FF00">
<strong>Bold green</strong>
</span>
and
<span fg="#FF0000">
<em><u>italic underlined red</u></em>
</span>
</text>
仓库佐证:chat-entry.tsx 展示了真实的组合用法——用 <span fg={accent}><strong>{toolName}</strong></span> 把工具名以主题强调色加粗渲染,用 <em>Thinking...</em> 表现推理流式状态;autocomplete-dropdown.tsx 则展示了条件颜色的典型写法:
<span fg={isSelected ? theme.textOnSelection : "gray"}>{prefix}</span>
即颜色属性既接受字符串("red"、"#FF0000"),也接受运行时计算出的变量或 RGBA 对象。
四、Core 范式的文本属性:TextAttributes
不走声明式标签时,Core API 通过位掩码常量设置文本属性:
import { TextRenderable, TextAttributes } from "@opentui/core"
const text = new TextRenderable(renderer, {
content: "Styled",
attributes: TextAttributes.BOLD | TextAttributes.UNDERLINE,
})
可用属性共 8 个,可用位运算叠加:
TextAttributes.BOLD、TextAttributes.DIM、TextAttributes.ITALIC、TextAttributes.UNDERLINETextAttributes.BLINK、TextAttributes.INVERSE、TextAttributes.HIDDEN、TextAttributes.STRIKETHROUGH
五、文本选中与复制
selectable 属性控制用户能否框选文本(配合终端 OSC 52 剪贴板能力):
<text selectable>
This text can be selected by the user
</text>
<text selectable={false}>
This text cannot be selected
</text>
完整的选区与 copy-on-selection API 在键盘参考文档 keyboard/REFERENCE.md 中(selection 一节)。Cline CLI 在展示助手回答、ClinePass 权益列表等需要用户复制的场景中,大量使用了 <text fg={...} selectable> 形式,例如 chat-entry.tsx 中链接文本的 <text fg={linkColor} selectable>。
六、Core 的样式化模板:t 模板字符串
对复杂排版,Core 提供 t 模板字面量与一组样式函数,返回的字符串可直接赋给 content:
import { t, bold, italic, underline, fg, bg, dim } from "@opentui/core"
const styled = t`
${bold("Bold")} and ${italic("italic")} text.
${fg("#FF0000")("Red text")} with ${bg("#0000FF")("blue background")}.
${dim("Dimmed")} and ${underline("underlined")}.
`
const text = new TextRenderable(renderer, {
content: styled,
})
样式函数一览:
| 函数 | 说明 |
|---|---|
bold(text) |
加粗 |
italic(text) |
斜体 |
underline(text) |
下划线 |
dim(text) |
变暗 |
strikethrough(text) |
删除线 |
fg(color)(text) |
设置前景色(柯里化,先传色再传文本) |
bg(color)(text) |
设置背景色 |
七、ascii-font 组件:ASCII 大标题横幅
用于在终端展示大型 ASCII 艺术字,适合做启动横幅、页面标题:
// React
<ascii-font text="TITLE" font="tiny" />
// Solid(注意 kebab-case 组件名差异)
<ascii_font text="TITLE" font="tiny" />
// Core
const title = new ASCIIFontRenderable(renderer, {
id: "title",
text: "TITLE",
font: "tiny",
})
支持 4 种字体:
| 字体 | 风格 |
|---|---|
tiny |
紧凑 ASCII 字体 |
block |
块状字母 |
slick |
现代流线风格 |
shade |
带阴影的 3D 效果 |
着色方式与 text 相同——React 直接传颜色字符串,Core 传 RGBA 对象:
// React
<ascii-font
text="HELLO"
font="block"
color="#00FF00"
/>
// Core
import { RGBA } from "@opentui/core"
const title = new ASCIIFontRenderable(renderer, {
text: "HELLO",
font: "block",
color: RGBA.fromHex("#00FF00"),
})
文档给出的渲染效果示意(tiny 与 block 两种字体渲染 "HELLO"):
Font: tiny
╭─╮╭─╮╭─╮╭╮╭╮╭─╮╶╮╶ ╶╮
│ ││─┘├┤ │╰╯││ │ │
╰─╯╵ ╰─╯╵ ╵╰─╯╶╯╶╰─╯
Font: block
█▀▀█ █▀▀█ █▀▀ █▀▀▄
█ █ █▀▀▀ █▀▀ █ █
▀▀▀▀ ▀ ▀▀▀ ▀ ▀
八、颜色体系:字符串格式与 RGBA 类
颜色字符串格式(用于 JSX 属性):
// 十六进制
<text fg="#FF0000">Red</text>
<text fg="#F00">Short hex</text>
// 命名色
<text fg="red">Red</text>
<text fg="blue">Blue</text>
// 透明背景
<text bg="transparent">No background</text>
注意十六进制必须带 #,fg="FF0000" 是错误写法。
RGBA 类:@opentui/core 导出的 RGBA 可以在所有框架(Core、React、Solid)中用于程序化颜色运算,三种构造方式对应不同数据来源:
import { RGBA } from "@opentui/core"
// 从十六进制字符串(最常用)
const red = RGBA.fromHex("#FF0000")
const shortHex = RGBA.fromHex("#F00") // 支持短形式
// 从 0-255 整数(r, g, b, a)
const green = RGBA.fromInts(0, 255, 0, 255)
const semiGreen = RGBA.fromInts(0, 255, 0, 128) // 50% 透明
// 从 0.0-1.0 归一化浮点
const blue = RGBA.fromValues(0.0, 0.0, 1.0, 1.0)
const overlay = RGBA.fromValues(0.1, 0.1, 0.1, 0.7) // 半透明深色
选择依据:对接设计规范/CSS 色值用 fromHex();持有 8 位通道值用 fromInts();做颜色插值与运算用 fromValues()。在 React/Solid 中,几乎所有接受颜色字符串的属性都直接接受 RGBA 对象:
import { RGBA } from "@opentui/core"
const primaryColor = RGBA.fromHex("#7aa2f7")
function MyComponent() {
return (
<box backgroundColor={primaryColor} borderColor={primaryColor}>
<text fg={RGBA.fromHex("#c0caf5")}>Styled with RGBA</text>
</box>
)
}
仓库佐证:Cline CLI 的主题系统正是这条链路的生产级实践。themes.ts 定义了多套主题(各自的 accents 强调色与 syntax 语法调色板),而 syntax-style.ts 将主题中的十六进制色值统一经 RGBA.fromHex 转换为 RGBA 对象,再包装成 { fg, bold }、{ fg, italic } 等 StyleDefinition,最终通过 SyntaxStyle.fromStyles(...) 构建代码高亮样式——从文档的 RGBA.fromHex("#...") 到仓库中 color(hex) { return RGBA.fromHex(hex) } 的映射一目了然。
九、文本换行与动态内容
换行由父容器决定:文本在触达父级容器宽度时自动折行:
<box width={40}>
<text>
This long text will wrap when it reaches the edge of the
40-character wide parent container.
</text>
</box>
动态内容按范式区分更新方式:
// React:状态驱动
function Counter() {
const [count, setCount] = useState(0)
return <text>Count: {count}</text>
}
// Solid:信号驱动
function Counter() {
const [count, setCount] = createSignal(0)
return <text>Count: {count()}</text>
}
// Core:命令式更新
const text = new TextRenderable(renderer, {
id: "counter",
content: "Count: 0",
})
// 之后任意时刻更新
text.setContent("Count: 1")
十、常见陷阱(Gotchas)
文档专门列出三类高频错误,逐一给出对照写法:
1. 修饰标签放到 <text> 之外不生效——<strong>、<em> 等只能在 <text> 内部解析:
// WRONG - modifiers only work inside <text>
<box>
<strong>Won't work</strong>
</box>
// CORRECT
<box>
<text>
<strong>This works</strong>
</text>
</box>
2. 空文本可能引发布局问题——用空格占位或条件渲染兜底:
// May cause layout issues
<text></text>
// Better - use space or conditional
<text>{content || " "}</text>
3. 十六进制颜色漏写 #:
// WRONG
<text fg="FF0000">Missing #</text>
// CORRECT
<text fg="#FF0000">With #</text>
另外,SKILL.md 的 Troubleshooting Index 也把“文本样式不生效(Text styling not applying)”直接指向本文档,可见它是 TUI 排障的第一参考。
十一、延伸阅读与相关路径
围绕本文主题,仓库内可直接深入的路径:
- 本文源文档:text-display.md
- 组件总索引:components/REFERENCE.md
- 选区/剪贴板(selectable 的完整 API):keyboard/REFERENCE.md
- 容器组件(box/scrollbox,文本的宿主):components/containers.md
- 代码高亮与 Diff(与本文 RGBA→SyntaxStyle 链路呼应):components/code-diff.md
- Cline CLI 真实实践:themes.ts、syntax-style.ts、chat-entry.tsx、autocomplete-dropdown.tsx
综上,OpenTUI 的文本显示层规则可以浓缩为三句话:React/Solid 用嵌套标签做样式、Core 用 TextAttributes 与 t 模板做样式、颜色统一经字符串或 RGBA 对象传递;Cline CLI 的主题系统与消息渲染组件是这套规则在真实项目中的完整落地样本。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00