Code
使用 Tree-sitter 展示语法高亮的代码。支持多种语言,提供准确、快速的高亮显示。
基本用法
Renderable API
import { CodeRenderable, createCliRenderer, SyntaxStyle, RGBA } from "@opentui/core"
const renderer = await createCliRenderer()
const syntaxStyle = SyntaxStyle.fromStyles({
keyword: { fg: RGBA.fromHex("#FF7B72"), bold: true },
string: { fg: RGBA.fromHex("#A5D6FF") },
comment: { fg: RGBA.fromHex("#8B949E"), italic: true },
number: { fg: RGBA.fromHex("#79C0FF") },
function: { fg: RGBA.fromHex("#D2A8FF") },
default: { fg: RGBA.fromHex("#E6EDF3") },
})
const code = new CodeRenderable(renderer, {
id: "code",
content: `function hello() {
// This is a comment
const message = "Hello, world!"
return message
}`,
filetype: "javascript",
syntaxStyle,
width: 50,
height: 10,
})
renderer.root.add(code)
Construct API
import { Code, Box, createCliRenderer, SyntaxStyle, RGBA } from "@opentui/core"
const renderer = await createCliRenderer()
const syntaxStyle = SyntaxStyle.fromStyles({
keyword: { fg: RGBA.fromHex("#FF7B72"), bold: true },
string: { fg: RGBA.fromHex("#A5D6FF") },
default: { fg: RGBA.fromHex("#E6EDF3") },
})
renderer.root.add(
Box(
{ border: true, width: 50, height: 10 },
Code({
content: 'const x = "hello"',
filetype: "javascript",
syntaxStyle,
}),
),
)
创建语法样式
使用 SyntaxStyle.fromStyles() 为语法标记定义颜色和属性:
import { SyntaxStyle, RGBA, parseColor } from "@opentui/core"
const syntaxStyle = SyntaxStyle.fromStyles({
// Basic tokens
keyword: { fg: RGBA.fromHex("#FF7B72"), bold: true },
"keyword.import": { fg: RGBA.fromHex("#FF7B72"), bold: true },
"keyword.operator": { fg: RGBA.fromHex("#FF7B72") },
string: { fg: RGBA.fromHex("#A5D6FF") },
comment: { fg: RGBA.fromHex("#8B949E"), italic: true },
number: { fg: RGBA.fromHex("#79C0FF") },
boolean: { fg: RGBA.fromHex("#79C0FF") },
constant: { fg: RGBA.fromHex("#79C0FF") },
// Functions and types
function: { fg: RGBA.fromHex("#D2A8FF") },
"function.call": { fg: RGBA.fromHex("#D2A8FF") },
"function.method.call": { fg: RGBA.fromHex("#D2A8FF") },
type: { fg: RGBA.fromHex("#FFA657") },
constructor: { fg: RGBA.fromHex("#FFA657") },
// Variables and properties
variable: { fg: RGBA.fromHex("#E6EDF3") },
"variable.member": { fg: RGBA.fromHex("#79C0FF") },
property: { fg: RGBA.fromHex("#79C0FF") },
// Operators and punctuation
operator: { fg: RGBA.fromHex("#FF7B72") },
punctuation: { fg: RGBA.fromHex("#F0F6FC") },
"punctuation.bracket": { fg: RGBA.fromHex("#F0F6FC") },
"punctuation.delimiter": { fg: RGBA.fromHex("#C9D1D9") },
// Default fallback
default: { fg: RGBA.fromHex("#E6EDF3") },
})
样式属性
每个样式定义可以包含:
| 属性 | 类型 | 说明 |
|---|---|---|
fg | RGBA | 前景色(文字颜色) |
bg | RGBA | 背景色 |
bold | boolean | 粗体文字 |
italic | boolean | 斜体文字 |
underline | boolean | 下划线文字 |
dim | boolean | 暗淡文字 |
支持的语言
Code 使用 Tree-sitter 进行解析。Tree-sitter 支持以下语言:
- TypeScript / JavaScript
- Markdown
- Zig
- 以及任何具有 Tree-sitter 语法的语言
流式模式
当内容以增量方式到达时(例如 LLM 输出),启用流式模式:
const code = new CodeRenderable(renderer, {
id: "streaming-code",
content: "",
filetype: "typescript",
syntaxStyle,
streaming: true, // Enable streaming mode
})
// Later, append content
code.content += "const x = 1\n"
code.content += "const y = 2\n"
流式模式针对增量更新优化了高亮显示。
文本选择
启用文本选择以支持复制操作:
const code = new CodeRenderable(renderer, {
id: "code",
content: sourceCode,
filetype: "typescript",
syntaxStyle,
selectable: true,
selectionBg: "#264F78",
selectionFg: "#FFFFFF",
})
隐藏语法元素
conceal 选项控制是否隐藏某些语法元素(如 markdown 格式化字符):
const code = new CodeRenderable(renderer, {
id: "markdown",
content: "# Heading\n**bold** text",
filetype: "markdown",
syntaxStyle,
conceal: true, // Hide formatting characters
})
显示行号
使用 LineNumberRenderable 添加行号:
import { CodeRenderable, LineNumberRenderable, RGBA, ScrollBoxRenderable, SyntaxStyle } from "@opentui/core"
const sourceCode = "const answer = 42\nconsole.log(answer)\n"
const syntaxStyle = SyntaxStyle.fromStyles({
default: { fg: RGBA.fromHex("#E6EDF3") },
})
const code = new CodeRenderable(renderer, {
id: "code",
content: sourceCode,
filetype: "typescript",
syntaxStyle,
width: "100%",
})
const lineNumbers = new LineNumberRenderable(renderer, {
id: "code-with-lines",
target: code,
minWidth: 3,
paddingRight: 1,
fg: "#6b7280",
bg: "#161b22",
width: "100%",
})
// Wrap in ScrollBox for scrolling
const scrollbox = new ScrollBoxRenderable(renderer, {
id: "scrollbox",
width: 60,
height: 20,
})
scrollbox.add(lineNumbers)
renderer.root.add(scrollbox)
属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
content | string | "" | 要显示的源代码 |
filetype | string | - | 语法高亮的语言 |
syntaxStyle | SyntaxStyle | 必填 | 语法高亮主题 |
streaming | boolean | false | 针对增量内容更新进行优化 |
conceal | boolean | true | 隐藏被隐藏的语法元素 |
drawUnstyledText | boolean | true | 在高亮完成前显示文本 |
treeSitterClient | TreeSitterClient | - | 自定义 Tree-sitter 客户端实例 |
继承自 TextBufferRenderable
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
fg | string | RGBA | - | 默认前景色 |
bg | string | RGBA | - | 背景色 |
selectable | boolean | false | 启用文本选择 |
selectionBg | string | RGBA | - | 选区背景色 |
selectionFg | string | RGBA | - | 选区前景色 |
wrapMode | string | "word" | 文本换行模式:"none"、"char"、"word" |
tabIndicator | string | number | - | Tab 显示字符或宽度 |
附加属性
| 属性 | 类型 | 说明 |
|---|---|---|
lineCount | number | 内容的行数 |
scrollY | number | 当前垂直滚动位置(可读写) |
scrollX | number | 当前水平滚动位置(可读写) |
scrollWidth | number | 总可滚动宽度(只读) |
scrollHeight | number | 总可滚动高度(只读) |
isHighlighting | boolean | 是否正在进行高亮处理 |
plainText | string | 纯文本内容 |
Markdown 样式
对于 markdown 高亮,使用 markup 前缀的样式名称:
const markdownStyle = SyntaxStyle.fromStyles({
"markup.heading": { fg: RGBA.fromHex("#58A6FF"), bold: true },
"markup.heading.1": { fg: RGBA.fromHex("#00FF88"), bold: true, underline: true },
"markup.heading.2": { fg: RGBA.fromHex("#00D7FF"), bold: true },
"markup.bold": { fg: RGBA.fromHex("#F0F6FC"), bold: true },
"markup.strong": { fg: RGBA.fromHex("#F0F6FC"), bold: true },
"markup.italic": { fg: RGBA.fromHex("#F0F6FC"), italic: true },
"markup.list": { fg: RGBA.fromHex("#FF7B72") },
"markup.quote": { fg: RGBA.fromHex("#8B949E"), italic: true },
"markup.raw": { fg: RGBA.fromHex("#A5D6FF") },
"markup.raw.block": { fg: RGBA.fromHex("#A5D6FF") },
"markup.link": { fg: RGBA.fromHex("#58A6FF"), underline: true },
"markup.link.url": { fg: RGBA.fromHex("#58A6FF"), underline: true },
default: { fg: RGBA.fromHex("#E6EDF3") },
})