Tree-sitter

OpenTUI 集成了 Tree-sitter,提供快速、精确的语法高亮功能。你可以全局注册解析器,也可以按客户端注册。

全局添加解析器

在创建客户端之前使用 addDefaultParsers()

import { addDefaultParsers, getTreeSitterClient } from "@opentui/core"

addDefaultParsers([
  {
    filetype: "python",
    wasm: "https://github.com/tree-sitter/tree-sitter-python/releases/download/v0.23.6/tree-sitter-python.wasm",
    queries: {
      highlights: ["https://raw.githubusercontent.com/tree-sitter/tree-sitter-python/master/queries/highlights.scm"],
    },
  },
])

const client = getTreeSitterClient()
await client.initialize()

按客户端添加解析器

import { TreeSitterClient } from "@opentui/core"

const client = new TreeSitterClient({ dataPath: "./cache" })
await client.initialize()

client.addFiletypeParser({
  filetype: "rust",
  wasm: "https://github.com/tree-sitter/tree-sitter-rust/releases/download/v0.23.2/tree-sitter-rust.wasm",
  queries: {
    highlights: ["https://raw.githubusercontent.com/tree-sitter/tree-sitter-rust/master/queries/highlights.scm"],
  },
})

解析器配置

interface FiletypeParserOptions {
  filetype: string
  aliases?: string[]
  wasm: string
  queries: {
    highlights: string[]
    injections?: string[]
  }
  injectionMapping?: {
    nodeTypes?: Record<string, string>
    infoStringMap?: Record<string, string>
  }
}

aliases 将额外的文件类型 ID 映射到同一组解析器资源。

语言注入

使用 queries.injections 来高亮嵌入的语言。

  • injectionMapping.nodeTypes 将注入的节点类型映射到文件类型 ID。
  • injectionMapping.infoStringMap 将代码围栏语言标签映射到文件类型 ID。
client.addFiletypeParser({
  filetype: "markdown",
  wasm: "https://github.com/tree-sitter-grammars/tree-sitter-markdown/releases/download/v0.5.1/tree-sitter-markdown.wasm",
  queries: {
    highlights: ["./assets/markdown/highlights.scm"],
    injections: [
      "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/markdown/injections.scm",
    ],
  },
  injectionMapping: {
    nodeTypes: {
      inline: "markdown_inline",
      pipe_table_cell: "markdown_inline",
    },
    infoStringMap: {
      js: "javascript",
      jsx: "javascriptreact",
      ts: "typescript",
      tsx: "typescriptreact",
    },
  },
})

如果 infoStringMap 没有匹配项,则使用代码围栏语言标签作为文件类型 ID。

使用本地文件

import pythonWasm from "./parsers/tree-sitter-python.wasm" with { type: "file" }
import pythonHighlights from "./queries/python/highlights.scm" with { type: "file" }

addDefaultParsers([
  {
    filetype: "python",
    wasm: pythonWasm,
    queries: {
      highlights: [pythonHighlights],
    },
  },
])

自动化资源管理

使用 updateAssets 工具来下载解析器并生成导入语句。

CLI 用法

{
  "scripts": {
    "prebuild": "bun node_modules/@opentui/core/lib/tree-sitter/update-assets.js --config ./parsers-config.json --assets ./src/parsers --output ./src/parsers.ts"
  }
}

编程用法

import { updateAssets } from "@opentui/core/tree-sitter/update-assets"

await updateAssets({
  configPath: "./parsers-config.json",
  assetsDir: "./src/parsers",
  outputPath: "./src/parsers.ts",
})

与 CodeRenderable 配合使用

import { CodeRenderable, RGBA, SyntaxStyle, getTreeSitterClient } from "@opentui/core"

const client = getTreeSitterClient()
await client.initialize()

const syntaxStyle = SyntaxStyle.fromStyles({
  default: { fg: RGBA.fromHex("#E6EDF3") },
})

const code = new CodeRenderable(renderer, {
  id: "code",
  content: "const x = 1",
  filetype: "typescript",
  syntaxStyle,
  treeSitterClient: client,
})

缓存

解析器和查询文件会缓存在客户端的 dataPath 中。设置自定义缓存目录:

const client = new TreeSitterClient({
  dataPath: "./my-cache",
})

文件类型解析

import { pathToFiletype, extToFiletype, infoStringToFiletype } from "@opentui/core"

const ft1 = pathToFiletype("src/main.rs")
const ft2 = extToFiletype("ts")
const ft3 = infoStringToFiletype("TSX title=Button.tsx")

infoStringToFiletype() 用于 Markdown 围栏代码块。

你可以在运行时扩展或覆盖映射:

import { extensionToFiletype, basenameToFiletype } from "@opentui/core"

extensionToFiletype.set("templ", "html")
basenameToFiletype.set("mytoolrc", "yaml")