Effect CLI 交互式 Prompt 选择项高亮机制解析:基于 changeset 的 active option 渲染原理与主题定制 📅 发布时间:2026/9/15 3:42:04 👁 浏览次数: Effect CLI 交互式 Prompt 选择项高亮机制解析基于 changeset 的 active option 渲染原理与主题定制【免费下载链接】effectBuild production-ready applications in TypeScript项目地址: https://gitcode.com/GitHub_Trending/ef/effect本篇技术指南聚焦 Effect 开源仓库中一个具体而典型的变更——changeset 记录 所描述的Prompt.select与Prompt.multiSelect活动选项active option标签高亮功能。文章以该变更说明为骨架结合 Prompt 模块源码 与 CLI 测试用例从渲染实现、主题系统、自定义配置到可运行示例逐层展开。读完你将掌握Effect 交互式终端 Prompt 的选择状态是如何被渲染出来的、cyan 高亮背后的主题色primaryColor机制、以及如何通过 Theme 定制自己的选择项外观。变更说明一次让选择状态看得见的 patch该 changeset 属于effect包的patch级别变更原文只有一句话Highlight active option labels inPrompt.selectandPrompt.multiSelectusing cyan text so selection state is visible beyond the pointer / checkbox icon.翻译过来即在Prompt.select与Prompt.multiSelect中使用青色cyan文本高亮当前活动的选项标签使选中状态不再仅仅依赖指针pointer或复选框checkbox图标来传达。这一变更解决的是一个真实的终端可用性问题在此之前单选Select与多选MultiSelect提示符的当前活动项主要由左侧的指针符号❯或复选框图标来标识当选项被禁用、分页翻页、或用户扫读长列表时仅靠图标区分正在高亮的是哪一项并不直观。将活动选项的标题文本本身着色后视觉焦点更加明确。在源码中实际的导出名称是Prompt.Select与Prompt.MultiSelect详见 构造器定义 与 多选构造器changeset 中的select/multiSelect是其口语化写法。Effect CLI Prompt 模块概览一个终端 UI 的 Effect 抽象PromptA是 Prompt 模块 的核心抽象其类型定义为export interface PromptOutput extends Effect.EffectOutput, Terminal.QuitError, Environment { readonly [TypeId]: { readonly _Output: CovariantOutput } }从类型签名可以看出见 源码 L52-L56一个Prompt本质上就是一个Effect成功时产出Output可能以Terminal.QuitError失败例如用户按下退出键或终端输入流结束运行需要Environment即FileSystem.FileSystem | Path.Path | Terminal.Terminal三个服务的组合见 L72。模块内建了多种提示符构造器覆盖常见交互场景构造器用途Prompt.Text文本输入Prompt.Password密码输入返回Redacted见 L1175-L1177Prompt.Confirm是/否确认Prompt.Toggle开关切换Prompt.Int/Prompt.Number整数/浮点数输入Prompt.Date日期编辑Prompt.List按分隔符拆分输入的列表Prompt.File文件系统选择Prompt.Select单选本次变更涉及Prompt.MultiSelect多选本次变更涉及Prompt.AutoComplete输入过滤的自动补全选择本次变更涉及的Select与MultiSelect均基于Custom构造器实现。Custom接受一个初始状态和一组Handlersrender/process/clear形成一个渲染循环render输出当前帧的 ANSI 文本Terminal服务获取用户输入process根据输入计算下一个ActionBeep/NextFrame/Submitclear清理上一帧。这一机制定义在 Custom 源码 L884-L911。高亮实现的核心renderChoiceTitle 与主题色本次 changeset 的核心代码路径是renderChoiceTitle见 源码 L3348-L3366const renderChoiceTitle A( choice: SelectChoiceA, isSelected: boolean, theme: Theme, renderOptions?: RenderOptions | undefined ) { if (renderOptions?.plain true) { return choice.title } const title choice.title if (isSelected) { return choice.disabled ? Ansi.annotate(title, Ansi.combine(Ansi.underlined, theme.mutedColor)) : Ansi.annotate(title, Ansi.combine(Ansi.underlined, theme.primaryColor)) } return choice.disabled ? Ansi.annotate(title, Ansi.combine(Ansi.strikethrough, theme.mutedColor)) : title }这段代码完整诠释了 changeset 的意图值得逐分支拆解renderOptions?.plain true以纯文本模式渲染例如输出到非 TTY 或管道时不做任何 ANSI 着色返回原始title活动项且未禁用isSelected !choice.disabled使用Ansi.annotate(title, Ansi.combine(Ansi.underlined, theme.primaryColor))渲染——下划线 主题色。这正是 changeset 所说的active option labels ... using cyan text在默认主题下primaryColor就是青色活动项但被禁用下划线 mutedColor弱化色表明它正被聚焦但不可选非活动项但被禁用删除线strikethroughmutedColor语义化地表达该选项不可用普通非活动项纯文本。对应的多选路径是renderMultiSelectChoices见 源码 L2710-L2767与renderMultiSelectTitle见 L2698-L2708const renderMultiSelectTitle ( title: string, isHighlighted: boolean, theme: Theme, renderOptions?: RenderOptions | undefined ) { if (renderOptions?.plain true || !isHighlighted) { return title } return Ansi.annotate(title, Ansi.combine(Ansi.underlined, theme.primaryColor)) }多选渲染时活动选项的复选框图标同样会被Ansi.annotate(checkbox, figures.primaryColor)着色见 L2752-L2754从而实现图标 文本双重视觉标识。主题系统cyan 来自哪里changeset 中cyan text并非硬编码而是来源于Theme的默认主题。Theme接口定义了提示符的全部视觉元素见 源码 L162-L197其中与本变更直接相关的是颜色字段字段语义默认值primaryColor活动元素的主色Ansi.cyanBright亮青色mutedColor次要/弱化元素Ansi.blackBrightsuccessColor完成/提交标记Ansi.greenerrorColor校验错误Ansi.redsubmittedColor已提交的值Ansi.white默认主题定义在 defaultTheme L601-L619其中primaryColor: Ansi.cyanBright位于 L614。也就是说changeset 所说的cyan在实现上是通过theme.primaryColor默认Ansi.cyanBright注入renderChoiceTitle的。如果你把primaryColor改成其他颜色高亮色会随之改变——这保证了高亮机制可主题化而不是写死的青色。此外windowsTheme L621-L629 针对 Windows 平台替换了部分符号如☒→[*]、❯→但颜色字段继承自defaultTheme因此本次高亮在 Windows 下同样生效只是图标字符不同。主题的获取链路由getThemeL657-L658完成先读取Theme上下文Context.Reference默认值makeTheme见 L653-L655再与构造器传入的theme选项浅合并——单个 prompt 的theme选项优先级高于全局上下文主题。实操编写一个带高亮的选择提示符将高亮机制落地到自己的 CLI 应用中标准用法如下基于Prompt.Select的 构造器签名 L1236-L1247 与SelectOptions/SelectChoice定义 L448-L548import { Effect, FileSystem, Path, Terminal } from effect import { Prompt } from effect/unstable/cli // 单选活动项的标题将被 primaryColor默认亮青色 下划线高亮 const framework await Prompt.run( Prompt.Select({ message: 选择你的框架, choices: [ { title: effect, value: effect }, { title: zod, value: zod }, { title: io-ts, value: io-ts } ] }) ) // 多选活动项的高亮同样作用于标题与复选框图标 const features await Prompt.run( Prompt.MultiSelect({ message: 选择需要的特性空格切换可多选, choices: [ { title: Schema, value: schema, selected: true }, { title: Stream, value: stream }, { title: CLI, value: cli, disabled: true }, // 删除线 mutedColor { title: Http, value: http } ] }) )要点说明SelectChoice的title是显示给用户的标签高亮作用的对象value是最终产出的值description会在活动项下方以mutedColor显示disabled项不可选择活动时下划线 mutedColor非活动时删除线selected仅在多选下生效用于默认勾选单选最多允许一个selected否则抛出InvalidArgumentException见 getSelectInitialIndex L1207-L1223maxPerPage默认10超出后分页显示分页箭头↑/↓会出现在列表首尾行见renderPagingPrefixL810-L819提示符通过Prompt.run驱动L1191-L1205运行依赖FileSystem、Path、Terminal三个服务在测试或非交互环境中可以像 Prompt.all 文档示例 那样用Layer提供桩实现FileSystem.layerNoop({})、Path.layer、自定义Terminal。实操自定义高亮颜色与主题如果不满足于默认的亮青色有两种定制方式二者可叠加方式一单 prompt 级 theme 选项优先级更高见 getTheme L657-L658Prompt.Select({ message: 选择语言, choices: [{ title: TypeScript, value: ts }, { title: Rust, value: rs }], theme: { primaryColor: \u001b[32m // ANSI 绿色活动项高亮变为绿色 } })方式二全局 Theme 上下文一次提供整个应用的所有 prompt 生效见 Theme 上下文 L653-L655import { Layer, Effect } from effect import { Prompt } from effect/unstable/cli const CustomTheme Layer.effect( Prompt.Theme, Effect.succeed(Prompt.makeTheme({ primaryColor: \u001b[35m })) // 亮紫色 ) const program Effect.gen(function*() { // 这里所有 prompt 的活动项高亮都使用亮紫色 }) await Effect.runPromise(Effect.provide(program, CustomTheme))Prompt.makeThemeL637-L640会先按平台选择windowsTheme或defaultTheme再合并你的覆盖项。注意Theme接口中的颜色字段是原始 ANSI 转义序列字符串例如Ansi.cyanBright就是\u001b[96m一类序列因此传入的覆盖值也应是 ANSI 序列或Ansi模块的产物。源码验证与测试佐证本次变更的渲染行为在仓库中有完整的实现与测试支撑实现文件Prompt.ts4069 行是 CLI 交互式提示符的唯一实现renderChoiceTitle/renderMultiSelectTitle/renderMultiSelectChoices构成高亮核心测试文件Prompt.test.ts 覆盖Select/MultiSelect/AutoComplete等构造器的渲染帧与交互行为可通过运行对应测试用例验证高亮输出中是否包含 ANSI 高亮序列配套文档CLI 基础指南 演示了如何将 Prompt 组合进Command构建完整的命令行应用而本变更让其中的选择类交互在视觉上更清晰。需要指出的是从源码结构看Select与MultiSelect共用同一套renderChoiceTitle高亮逻辑AutoComplete自动补全选择也复用了它见 L3388-L3412 的renderAutoCompleteChoices因此本次高亮增强实际上惠及了三种选择型 prompt而不仅仅是 changeset 字面提到的两种。小结eff-769-select-text-highlight这一 changeset 虽然只有一句话却点出了一个终端 UI 库的关键设计取向选择状态的可读性不能只依赖图标还要作用于文本本身。在 Effect 的实现中这一目标通过三层机制达成渲染层renderChoiceTitle对活动项标题施加Ansi.underlined theme.primaryColor默认亮青色与左侧primaryColor着色的 pointer/checkbox 形成双重标识主题层颜色不是硬编码的 cyan而是可配置的primaryColor支持单 prompt 覆盖与全局上下文注入两种定制路径一致性层单选、多选、自动补全共用同一渲染函数一次变更同时提升三类交互的可用性。如果你正在用 Effect 构建 CLI 工具可直接在 Prompt 模块 中找到上述实现并参考 测试文件 了解各构造器的完整行为矩阵。【免费下载链接】effectBuild production-ready applications in TypeScript项目地址: https://gitcode.com/GitHub_Trending/ef/effect创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考