Starship「No Empty Icons」预设指南:只有拿到工具版本才渲染图标
【免费下载链接】starship☄🌌️ The minimal, blazing-fast, and infinitely customizable prompt for any shell!项目地址: https://gitcode.com/GitHub_Trending/st/starship
Starship 的语言/工具链模块(Rust、Node.js、Python 等)会依据项目内的工具集文件(如Cargo.toml、package.json)决定是否出现,即使当前环境中没有安装对应的命令行工具,提示符也常常会输出一个“光秃秃”的图标。本文基于 starship 仓库中的 No Empty Icons 预设文档 及其配套的 no-empty-icons.toml 配置,讲解该预设解决的问题、覆盖的模块范围、底层 format 字符串原理,以及一条命令完成安装与深度定制的方法。读完本文,你将理解为何“无版本图标”会出现、如何一键消除它,并能依据同样的条件组语法手工迁移到任意模块。
一、预设解决的问题:识别到工具集文件,却拿不到版本号
先回顾 Starship 各工具链模块的默认行为。以 Rust 模块为例,在 默认配置 中其format为:
format = "via $symbol($version )"模块渲染的判定分两步(参见 rust 模块实现):
- 探测项目文件:是否出现
Cargo.toml、.rs文件等(detect_files/detect_extensions),命中则启用模块; - 探测工具版本:调用
rustc --version等命令解析版本,把结果填充到$version。
问题恰恰出在这两步并不等价:当项目文件存在、但当前环境里没有安装rustc(例如刚 clone 的仓库、CI 容器、干净镜像),$version为空,可模块依旧会渲染出via 🦀。此时图标被“空显示”——既没有版本信息,又占据提示符宽度,还容易让人误以为工具链已就绪。
No Empty Icons 预设的目标(对应 docs/presets/README.md 与 预设说明)就是:
默认行为下,只要识别到工具集文件就显示图标;该预设改为只有能确定工具集信息(拿到版本)时才显示图标。
它的效果可以从配套截图直观看到:启用后,未安装工具链的目录里不再出现无意义的图标。
二、适用模块:覆盖 46 个按文件探测的工具链模块
从 no-empty-icons.toml 的完整内容看,该预设一次性改写 46 个模块的format字段:
| 类型 | 覆盖模块 |
|---|---|
| 编译型语言 | rust、c、cpp、cmake、cobol、fortran、haskell、java、scala、swift、zig、vlang、nim、odin 之外所列 |
| 脚本/解释型语言 | python、ruby、php、perl、lua、raku、crystal、dart、deno、bun、nodejs、fennel、gleam、elixir、erlang、elm、purescript、typst、rlang、quarto |
| 构建/包管理 | buf、maven、gradle、xmake、dotnet、package、helm、opa、daml、vagrant |
| 云端/其他 | gcloud、aws、azure、kubernetes 等不在列表中 |
逐项核对配置后,被修改的模块准确清单为:buf、bun、c、cpp、cmake、cobol、crystal、daml、dart、deno、dotnet、elixir、elm、erlang、fennel、fortran、gleam、golang、haskell、helm、java、julia、kotlin、lua、nim、nodejs、ocaml、opa、package、perl、php、purescript、python、quarto、raku、red、rlang、ruby、rust、scala、swift、typst、vagrant、vlang、xmake、zig,共 46 个模块,且每个模块都采用同一种“把整段图标包进条件组”的写法。
没有被覆盖的模块(如git_branch、directory、character、status等)不依赖“工具存在与否”,自然不在此预设的语义范围内。
三、工作机制:format 字符串里的条件组(...)
理解本预设的关键在 Starship 的 format 语法。对照 string formatter 的条件组实现 可以看到:格式串中(...)组成的是一个条件组,渲染引擎会检查组内引用的变量是否被解析出实际内容,若变量为空(如工具探测失败、版本不可得),整段条件组被丢弃、不产生任何输出。
以此为基础对比两种写法:
默认写法(图标无条件显示)
format = "via $symbol($version )"这里图标$symbol位于条件组之外,无论$version是否为空都会被输出。
预设写法(图标随版本联动)
format = "(via $symbol($version ))"via前缀、$symbol图标、$version三者被整体包进外层条件组。当环境无法探测出工具版本时,$version为空,外层条件组随之整段消失——via 🦀不再出现;只有当版本成功解析时,图标才与版本号一同渲染。
这正好印证了预设说明中“图标只在工具集信息可确定时显示”的设计意图,也是把“空图标”问题从根源上解决的方式。
四、一行命令安装:应用与覆盖既有配置
应用该预设只需要一个命令。Starship 的preset子命令定义见 src/main.rs,其底层实现见 print.rs 中的 preset_command:
# 将预设写入默认配置文件(首次配置推荐) starship preset no-empty-icons -o ~/.config/starship.toml该命令的完整行为如下:
| 参数 | 作用 |
|---|---|
starship preset no-empty-icons | 不加-o时,将 TOML 内容打印到标准输出,用于预览,不会改动文件 |
-o, --output <file> | 将预设内容写入指定文件(原子写入) |
-f, --force | 目标文件已存在时强制覆盖(需配合-o使用) |
-l, --list | 列出所有可用的预设名称 |
Windows 用户可将输出路径替换为~\.config\starship.toml(%USERPROFILE%\.config\starship.toml)后再执行,效果等价。
务必注意:-o是整体覆盖写入,不是“合并追加”。如果你已经有一套自定义配置,直接用该命令会清空原有内容。正确的做法是:
- 先运行
starship preset no-empty-icons,把输出保存到一份独立文件; - 再将该文件里的
[xxx]各模块表合并进你现有的starship.toml; - 重新加载 shell(或运行
exec $SHELL)验证效果。
如果你不确定某个模块的默认字段,预设文件开头"$schema"指向的 JSON Schema 以及 config-schema.json 都提供了完整的模块与字段说明,可作合并时的参考。
五、预设的完整 TOML 配置(可直接复制)
以下是仓库中 no-empty-icons.toml 的完整内容,也是上面命令实际写入的配置:
"$schema" = 'https://starship.rs/config-schema.json' [buf] format = '(with $symbol($version ))' [bun] format = '(via $symbol($version ))' [c] format = '(via $symbol($version(-$name) ))' [cpp] format = '(via $symbol($version(-$name) ))' [cmake] format = '(via $symbol($version ))' [cobol] format = '(via $symbol($version ))' [crystal] format = '(via $symbol($version ))' [daml] format = '(via $symbol($version ))' [dart] format = '(via $symbol($version ))' [deno] format = '(via $symbol($version ))' [dotnet] format = '(via $symbol($version )(🎯 $tfm ))' [elixir] format = '(via $symbol($version \(OTP $otp_version\) ))' [elm] format = '(via $symbol($version ))' [erlang] format = '(via $symbol($version ))' [fennel] format = '(via $symbol($version ))' [fortran] format = "(via $symbol($version ))" [gleam] format = '(via $symbol($version ))' [golang] format = '(via $symbol($version ))' [haskell] format = '(via $symbol($version ))' [helm] format = '(via $symbol($version ))' [java] format = '(via $symbol($version ))' [julia] format = '(via $symbol($version ))' [kotlin] format = '(via $symbol($version ))' [lua] format = '(via $symbol($version ))' [nim] format = '(via $symbol($version ))' [nodejs] format = '(via $symbol($version ))' [ocaml] format = '(via $symbol($version )(\($switch_indicator$switch_name\) ))' [opa] format = '(via $symbol($version ))' [package] format = '(is $symbol$version )' [perl] format = '(via $symbol($version ))' [php] format = '(via $symbol($version ))' [purescript] format = '(via $symbol($version ))' [python] format = '(via ${symbol}${pyenv_prefix}(${version} )(\($virtualenv\) ))' [quarto] format = '(via $symbol($version ))' [raku] format = '(via $symbol($version-$vm_version ))' [red] format = '(via $symbol($version ))' [rlang] format = '(via $symbol($version ))' [ruby] format = '(via $symbol($version ))' [rust] format = '(via $symbol($version ))' [scala] format = '(via $symbol($version ))' [swift] format = '(via $symbol($version ))' [typst] format = '(via $symbol($version ))' [vagrant] format = '(via $symbol($version ))' [vlang] format = '(via $symbol($version ))' [xmake] format = '(via $symbol($version ))' [zig] format = '(via $symbol($version ))'六、少数模块的“结构件”变量:不止有版本号
大多数模块只需处理$symbol+$version,但预设里几个模块保留了额外的结构性变量,值得单独说明(全部以官方模块支持的变量为准,对应 configs 目录下的默认定义):
- C / C++(
$name):($version(-$name) )——$name是编译器(如 clang、gcc)的名字,用内层条件组保证“有名才显示、名字缺失不留下括号”。 - .NET(
$tfm):🎯 $tfm表示目标框架(如net8.0),tfm为空时不显示圆靶符号。 - Elixir(
$otp_version):括号内额外携带 OTP 版本,若无法确定则不输出。 - OCaml(
$switch_indicator/$switch_name):用于 opam switch 的上下文信息,同样以独立条件组包裹。 - Python:保留
$pyenv_prefix(pyenv 版本)与$virtualenv(虚拟环境名),(\($virtualenv\) )确保没有激活虚拟环境时连括号一起隐藏。 - Raku(
$vm_version):($version-$vm_version )仅在能同时得到版本与虚拟机版本时渲染。 - package:使用
(is $symbol$version ),把is前缀与图标一并纳入条件组,语义上是“这是某个包时才显示”。
这些例子说明预设并非机械地删字符,而是按每个模块的格式模板把“可能为空的信息块”逐层用条件组隔离。
七、深度定制:把同一模式应用到其他模块
理解(...)条件组之后,你可以把该模式推广到任何“探测到文件但探测不到工具”的场景。示例:为预设未覆盖或后续新增的模块手工套用,只需在 starship.toml 中写入:
# 自定义示例:把该模式扩展到 vlang 之外的其它模块 [terraform] format = '(via $symbol($version ))'几点建议:
- 先阅读对应模块在 configs 中的默认
format,确认其变量名(如$version、$symbol、$style)与默认前缀词(via、with、on等),再整体包一层条件组; - 条件组里保留的文本(如
via)应放在$symbol同一层,避免版本为空时留下“via”孤词; - 修改后运行
starship prompt(参见 main.rs 的 Prompt 命令)可立即预览当前目录下的渲染结果,无需重启终端。
八、验证、回退与小结
验证是否生效:进入一个“只有项目文件、没有对应工具”的目录(例如删掉依赖的纯模板目录),观察提示符不再出现对应语言图标;再用starship preset --list确认预设可被starship识别。
回退方式:由于配置是可逆的文本,备份原starship.toml后用-f覆盖回去即可;若是手工合并的,删除预设新增的[module]段即恢复默认行为。
No Empty Icons 预设用一段统一的 format 改写,把 46 个工具链模块从“有文件就显示图标”收敛为“有版本才显示图标”,对容器、CI、多工具链切换场景非常实用。如果你还想调整图标或样式本身,可以继续参考 Presets 集合 中的其它预设,以及在 docs/config 中查看每个模块的完整字段与默认值。
【免费下载链接】starship☄🌌️ The minimal, blazing-fast, and infinitely customizable prompt for any shell!项目地址: https://gitcode.com/GitHub_Trending/st/starship
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考