Skip to content

Latest commit

 

History

History
160 lines (123 loc) · 5.95 KB

File metadata and controls

160 lines (123 loc) · 5.95 KB

主题系统

文档索引 · English

内置主题

dsh-TUI 提供三套 Gentle Mist Blue 色板,外加一个 auto 伪主题:

名称 用途
auto 伪主题:跟随系统/终端背景,自动解析为 lightdark
light 暖白背景、墨色正文、雾蓝交互色
dark 深色终端适配,暖灰正文与柔雾蓝强调色
dark-ansi 只依赖 16 色 ANSI 的兼容回退

未明确指定主题时,TUI 会通过 OSC 11 查询终端背景并在 lightdark 之间 选择;终端不响应时回退到 dark

auto 把这次性启动检测变成常驻选择:它在 /themeDSH_TUI_THEME~/.dsh-tui/theme.json 中都是合法值。选中 auto 时立即应用上次检测结果,并 在后台重新查询 OSC 11——跟随系统主题的终端切换深浅色后,再次选择 auto(或 重启)即可跟上。/theme status 会显示 auto 当前解析到的色板。解析结果通过 getTheme('auto') 对所有消费方生效。注意:用户自定义主题若命名为 auto 会被 内置伪主题遮蔽(选择器中不列出)。

选择优先级:

DSH_TUI_THEME
  > ~/.dsh-tui/theme.json 中的持久化选择
  > OSC 11 背景检测
  > dark 回退

切换主题

  • /theme:打开主题选择器。auto 与内置主题在前,静态 JSON 主题和插件主题在后。
  • /theme <name>:直接切换静态或运行时插件主题。
  • /theme status:显示当前主题与持久化位置。

选择器确认后立即热切换,并把选择写入 ~/.dsh-tui/theme.json。如果设置了 DSH_TUI_THEME,它在下一次启动时仍然优先。

自定义主题

~/.dsh-tui/themes/ 下放置 JSON 文件。每个文件定义一个主题,并从一个内置 色板开始覆盖:

{
  "name": "sakura",
  "displayName": "樱花粉",
  "base": "dark",
  "colors": {
    "claude": "#FF9EC7",
    "claudeShimmer": "#FFC0D5",
    "permission": "#FFB3CC",
    "promptBorder": "#B08B99",
    "text": "#E8E6E0",
    "inactive": "#A99BA0",
    "subtle": "#8A7A80",
    "selectionBg": "#5C3A44",
    "success": "#9CC7A8",
    "error": "#E08591",
    "warning": "#E0C08A"
  }
}

字段:

字段 必需 说明
base lightdarkdark-ansi,作为未覆盖颜色的来源
colors Theme 语义键的部分覆盖
name 主题 ID;缺省使用文件名
displayName 选择器显示名称;缺省使用 name

如果文件声明了 name,文件名仍可作为加载别名。完整语义键见 src/theme.ts 中的 Theme 类型。

npm 插件主题

npm 插件可以通过 dsh-tui-extensions 行注册运行时主题,不需要写入 ~/.dsh-tui/themes/

import type { Context } from '@deepseek-ai/cordis'
import type { TuiThemeDescriptor } from '@deepseek-harness-tui/dsh-tui/extensions'

export function apply(ctx: Context): void {
  const themes = ctx.get('tuiThemes', false)
  themes?.register({
    name: 'my-plugin:night',
    displayName: 'Night',
    base: 'dark',
    colors: { claude: '#88AAFF', selectionBg: '#334466' },
  }, ctx)
}

使用 plugin-id:theme-id 形式的小写安全 ID。base 仍为 lightdarkdark-ansicolorsTheme 语义键的部分覆盖;auto、内置主题和 status 不能作为插件主题名。注册会随插件 activation 自动清理,返回的 disposer 可以提前注销。插件主题出现在 /theme 选择器、补全和直接切换中,名字沿用 ~/.dsh-tui/theme.json 持久化。内置主题优先于静态 JSON,静态 JSON 优先于同名 插件主题;旧 profile 没有 tuiThemes 时插件静默降级,静态主题不受影响。

常用可覆盖键分组:

分组
工具卡衬底(深浅两档) toolCardBackgroundtoolCardBackgroundDim
工具状态点(按分类) toolDotExectoolDotReadtoolDotWritetoolDotWebtoolDotTask
diff 行色 diffAddeddiffRemoveddiffAddedDimmeddiffRemovedDimmeddiffAddedWorddiffRemovedWord
diff 语法高亮 syntaxKeywordsyntaxStringsyntaxCommentsyntaxNumbersyntaxFunctionsyntaxTypesyntaxVariablesyntaxOperatorsyntaxPunctuationsyntaxConstant

diff 语义优先于语法色:改动词组总是使用 diffAddedWord / diffRemovedWord, 语法色只作用于未变更的文本。

颜色格式

支持:

  • #rgb
  • #rrggbb
  • #rrggbbaa
  • rgb(r,g,b)
  • ansi256(n)
  • ansi:blackansi:redBright 等 16 色 ANSI 名称

颜色必须是具体值,不能使用 CSS 变量、渐变或任意 CSS 颜色名。

校验与失败策略

  • 未知 Theme 键:跳过该键并写入警告,其余颜色继续生效。
  • 非法颜色:跳过该值并写入警告。
  • 非法 base、损坏的 JSON、非对象 colors:跳过整个文件。
  • 环境变量或偏好文件引用不存在的主题:写入警告并继续背景自动检测。
  • 一个坏主题不会阻止 TUI 启动,也不会影响其他主题。

主题名来自用户输入,加载器会检查路径是否仍位于主题目录内,防止通过名称跳出 ~/.dsh-tui/themes/。修改这部分实现时必须保留路径约束。

设计建议

  • 使用语义键而不是只替换 textbackground。至少检查正文、非活动文字、 焦点、选择、成功、警告、错误和 diff 色。
  • 浅色主题应在真正的浅色终端验证;深色主题同理。
  • 检查 16 色、256 色和 truecolor 终端的回退表现。
  • 在窄终端、工具 diff、问卷、多行输入与选区状态下检查对比度。
  • 不要把密钥或其他用户数据写进主题文件;主题只应包含显示元数据和颜色。

开发主题系统时运行:

node --import tsx/esm scripts/verify-themes.mjs

进一步的终端能力与渲染说明见架构与限制