news 2026/9/20 20:55:54

spaceship-prompt 通用工具函数完全指南:Zsh 提示符 Section 开发者的 API 手册

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
spaceship-prompt 通用工具函数完全指南:Zsh 提示符 Section 开发者的 API 手册

spaceship-prompt 通用工具函数完全指南:Zsh 提示符 Section 开发者的 API 手册

【免费下载链接】spaceship-prompt🚀✨ Minimalistic, powerful and extremely customizable Zsh prompt项目地址: https://gitcode.com/gh_mirrors/sp/spaceship-prompt

本文是 spaceship-prompt 通用工具函数(General utilities)的完整技术指南,内容以 docs/api/utils.md(乌克兰语镜像见 docs/uk/api/utils.md)为骨架,并对照 lib/utils.zsh 与 lib/extract.zsh 的源码实现、tests/utils.test.zsh 与 tests/extract.test.zsh 的测试用例进行纵深验证。读完本文,你将掌握spaceship::existsspaceship::is_gitspaceship::upsearchspaceship::extract等十余个内建工具函数的签名、返回码约定与底层原理,并能熟练地在自定义 Section 中调用它们完成命令探测、仓库识别、异步调度、数据文件查询等实战任务。

在 spaceship-prompt 中,lib/utils.zsh的文件头注释明确写道:“This file is used as a API for sections developers”——这份文件就是面向 Section 开发者的公共 API。理解这些工具函数,是编写健壮、符合官方规范的自定义 Section 的前提。

一、工具函数的设计约定

所有通用工具函数都遵循一套统一的调用约定,理解它才能正确使用:

  • 均以spaceship::为命名空间前缀,与 Section 的spaceship_前缀命名规范(见 docs/api/section.md)区分开;
  • 退出码即返回值:多数判断型工具“返回零表示成立、非零表示不成立”,可直接用if ...; then||&&等 Zsh 惯用语法串联;
  • 保持静默:除spaceship::upsearch(默认输出路径)与spaceship::extract(输出查询结果)外,判断类工具不向 stdout 输出任何内容,只通过退出码传达结果。

二、命令与函数探测:spaceship::existsspaceship::defined

spaceship::exists <command>

spaceship::exists <command>

该工具校验给定程序是否可用于执行:它会检查$PATH中的二进制文件、shell 函数以及内建命令(builtins)。若command存在则返回零退出码,否则返回非零退出码。

从源码看,它的实现极其简洁(lib/utils.zsh):

spaceship::exists() { command -v $1 > /dev/null 2>&1 }

其核心是 Zsh 内建命令command -v,同时把标准输出与标准错误全部丢弃,仅保留退出码语义。因为command -v能同时命中 PATH 中的可执行文件、已定义的函数和内建命令,所以官方文档特别强调“It checks for PATH binaries, functions, and builtins”。

典型用途是“探测某程序是否安装,再据此决定后续动作”,可以返回错误并退出,也可以继续执行脚本:

# 检查多个命令是否存在 if spaceship::exists nvm; then # 提取 nvm 版本 elif spaceship::exists node; then # 提取 node 版本 else return fi # docker 未安装则什么也不做 spaceship::exists docker || return

lib/extract.zsh 内部就大量使用spaceship::exists来探测yqrubypython3等解析后端,这正体现了“探测-分派”的经典用法。

spaceship::defined <function>

spaceship::defined <function>

该工具与spaceship::exists语义相同,但针对的是函数:若function此前已被定义则返回零退出码,否则返回非零。

其实现(lib/utils.zsh)借助typeset -f +判断:

spaceship::defined() { typeset -f + "$1" &> /dev/null }

typeset -f会列出指定函数的定义,存在则命令成功,配合+选项与&> /dev/null静默化后仅保留退出码。可用于检查用户此前是否自定义过某个函数:

# 检查 Section 是否已定义 if spaceship::defined spaceship_section; then spaceship_section else # Section 未找到 fi

这个工具在核心渲染流程中承担关键职责:lib/core.zsh 遍历 Section 顺序时,先用spaceship::defined "spaceship_$section"判断是否已有同名自定义函数;若已定义则直接跳过加载,这保证了用户自定义 Section 永远优先于内建 Section

三、版本仓库环境探测:spaceship::is_gitspaceship::is_hg

spaceship::is_git

若当前工作目录位于 Git 仓库内则返回零退出码,否则返回非零。官方示例:

# 当前目录不是 git 仓库则返回 spaceship::is_git || return

源码实现(lib/utils.zsh)委托给 Git 自身完成判断:

spaceship::is_git() { # See https://git.io/fp8Pa for related discussion [[ $(command git rev-parse --is-inside-work-tree 2>/dev/null) == true ]] }

它执行git rev-parse --is-inside-work-tree并比对输出是否为true。这带来一个重要特性:在仓库的任意子目录中调用都会返回真,因为--is-inside-work-tree检查的是“是否处于某个工作树内部”,而非“当前目录是否是仓库根”。tests/utils.test.zsh 中的test_is_git专门验证了这一点:在仓库根目录与子目录foo中均断言为真,而在仓库之外断言为假。

spaceship::is_hg

spaceship::is_git对应,但针对 Mercurial 仓库:

# 当前目录不是 Mercurial 仓库则返回 spaceship::is_hg || return

实现(lib/utils.zsh)复用了另一个工具函数spaceship::upsearch,向上查找.hg目录:

spaceship::is_hg() { local hg_root="$(spaceship::upsearch .hg)" [[ -n "$hg_root" ]] &>/dev/null }

这里体现了工具函数之间的组合复用:is_hg通过upsearch向上搜索.hg标记目录,若找到(路径非空)即为 Mercurial 仓库。tests/utils.test.zsh 中的test_is_hg还特别验证了带空格的目录路径(foo with space)不会被误判为仓库内,且当系统未安装hg时测试会跳过。

四、异步模式判断:spaceship::is_section_asyncspaceship::is_prompt_async

异步渲染是 spaceship-prompt 的核心性能特性,这两个工具是连接通用工具层与异步工作器(worker)的桥梁。

spaceship::is_section_async <section>

通过检查SPACESHIP_<SECTION>_ASYNC选项判断某 Section 是否为异步执行:

spaceship::is_section_async <section>

参数说明:

  1. section必填— 需要检查的 Section 名称。

返回约定:Section 为异步时返回零退出码,否则返回非零。有两个特殊规则:

  • SPACESHIP_PROMPT_ASYNC设为false,则所有 Section 一律视为同步
  • 部分 Section无论配置如何都强制同步,以保证命令行提示符正确工作,它们是:userdirhostexec_timeasyncline_sepjobsexit_codechar

这两条规则与源码中的判定逻辑完全一致(lib/utils.zsh):

spaceship::is_section_async() { local section="$1" local sync_sections=(user dir host exec_time async line_sep jobs exit_code char) # 某些 Section 必须始终同步 if spaceship::includes sync_sections "$section"; then return 1 fi # 若用户对整个提示符关闭了异步渲染 if [[ "$SPACESHIP_PROMPT_ASYNC" != true ]]; then return 1 fi local async_option="SPACESHIP_${(U)section}_ASYNC" [[ "${(P)async_option}" == true ]] }

三个关键细节值得注意:

  1. 强制同步清单以源码中的sync_sections数组为准,与文档列出的 9 个 Section 完全一致;
  2. 通过${(U)section}把 Section 名转成大写,再拼接出SPACESHIP_<SECTION>_ASYNC变量名,最后用${(P)...}参数间接展开取出该变量的值——这是 Zsh 中“按名字取变量值”的标准写法;
  3. 判定顺序是“先查强制同步清单,再查全局开关,最后查 Section 专属开关”,三者构成 AND 关系。

test_is_section_async(tests/utils.test.zsh)逐一验证了:SPACESHIP_FOO_ASYNC=truefoo异步成立;全局SPACESHIP_PROMPT_ASYNC=false时即使 Section 开关为真也判定为同步;9 个系统 Section 即使显式设置SPACESHIP_<NAME>_ASYNC=true也始终返回假。

spaceship::is_prompt_async

判断整个提示符是否处于异步工作模式:

spaceship::is_prompt_async

返回约定:异步模式返回零退出码,否则非零。判定条件有两个,需同时满足:

  • SPACESHIP_PROMPT_ASYNC设为true
  • zsh-async已成功加载(源码中表现为全局变量ASYNC_INIT_DONE为真)。

实现(lib/utils.zsh):

spaceship::is_prompt_async() { [[ "$SPACESHIP_PROMPT_ASYNC" == true ]] && (( ASYNC_INIT_DONE )) }

ASYNC_INIT_DONE由 zsh-async 库初始化时置位。对应的测试(tests/utils.test.zsh)覆盖了四种组合:开关与初始化都就绪时为真;开关关闭为假;开关开启但异步库未初始化时同样为假。

在核心渲染流程中的调用链

这两个工具贯穿了提示符渲染的主流程:

  • lib/core.zsh 在加载 Section 时逐个调用spaceship::is_section_async,只要存在任一异步 Section 就触发spaceship::worker::load加载异步工作器;
  • lib/core.zsh 在spaceship::core::refresh_section中依据spaceship::is_section_async "$section"决定把 Section 交给后台 worker 异步执行(spaceship::worker::run)还是同步执行;
  • lib/worker.zsh 中worker::initworker::flushworker::evalworker::run四个函数都先用spaceship::is_prompt_async做前置判断,确保只在异步模式下才操作 zsh-async 的 worker。

可以推断,正是这一层“两级异步判断”,使得全局开关、Section 级开关与强制同步清单能够以统一、可测试的方式组合生效,保证chardir等关键 Section 永远即时渲染。

五、弃用警告:spaceship::deprecated

spaceship::deprecated <option> [message]

该工具检查名为option的变量是否已设置,若已设置则打印message警告。message支持 Zsh 的 prompt 转义序列(escape sequences),可设置前景色、背景色及其他视觉效果。

参数说明:

  1. option必填— 被弃用变量的名称。若该变量已设置(含任意值),将打印"%B$deprecated%b is deprecated.",其中%B%b是设置/取消粗体字样的转义序列;
  2. message可选— 附加的弃用提示文本,可包含 prompt 扩展。

(转义序列的完整语法可查阅 Zsh 文档中 Prompt Expansion 一节。)

使用示例:

# 检查 SPACESHIP_BATTERY_ALWAYS_SHOW 是否已设置 spaceship::deprecated SPACESHIP_BATTERY_ALWAYS_SHOW "Use %BSPACESHIP_BATTERY_SHOW='always'%b instead." # SPACESHIP_BATTERY_ALWAYS_SHOW is deprecated. Use SPACESHIP_BATTERY_SHOW='always' instead.

实现(lib/utils.zsh)揭示了三层防御逻辑:

spaceship::deprecated() { [[ -n $1 ]] || return local deprecated=$1 message=$2 local deprecated_value=${(P)deprecated} # the value of variable name $deprecated [[ -n $deprecated_value ]] || return print -P "%B$deprecated%b is deprecated. $message" }
  • 第一层:option参数为空则直接返回,避免空指针式的展开错误;
  • 第二层:用${(P)deprecated}间接展开取出变量值;
  • 第三层:变量值也为空(即用户未设置该弃用变量)则静默返回,不打印任何警告

只有当用户确实设置了旧变量时才通过print -P输出,其中-P选项启用 prompt 转义解析。测试test_deprecated(tests/utils.test.zsh)验证了无附加信息与带附加信息两种输出的精确渲染结果。

六、人类可读时间格式化:spaceship::displaytime

spaceship::displaytime <seconds> [precision]

将秒数转换为易读的时间格式,按天(d)、小时(h)、分钟(m)、秒(s)拆分输出。

参数说明:

  1. seconds必填— 待转换的秒数;
  2. precision可选— 输出精度(秒的小数位数),默认值为1

使用示例:

spaceship::displaytime 123456 # 1d 10h 17m 36.0s spaceship::displaytime 123.45 2 # 2m 3.45s

实现(lib/utils.zsh)先用整数运算拆分天/时/分,再用浮点运算保留秒的小数部分:

spaceship::displaytime() { local duration="$1" precision="$2" [[ -z "$precision" ]] && precision=1 integer D=$((duration/60/60/24)) integer H=$((duration/60/60%24)) integer M=$((duration/60%60)) local S=$((duration%60)) [[ $D > 0 ]] && printf '%dd ' $D [[ $H > 0 ]] && printf '%dh ' $H [[ $M > 0 ]] && printf '%dm ' $M printf %.${precision}f%s $S s }

细节说明:DHM声明为integer(整数除法自动截断),而S保留浮点,因此能输出36.0s3.45s这样带小数的秒;天/时/分仅在对应值大于 0 时输出,秒则总是输出并带上单位s。例如 123456 秒 = 1 天 10 小时 17 分 36 秒,输出1d 10h 17m 36.0s。tests/utils.test.zsh 用 1234567 秒验证了输出14d 6h 56m 7.0s。该工具最常见的消费方是exec_timeSection,用于把命令执行耗时渲染成易读文本。

七、数组合并与去重:spaceship::union

spaceship::union <arr1[ arr2[ ...]]>

对两个及以上数组执行并集(union)操作,列出所有数组中出现过的内容。参数为待合并的数组列表。

官方示例:

arr1=('a' 'b' 'c') arr2=('b' 'c' 'd') arr3=('c' 'd' 'e') spaceship::union $arr1 $arr2 $arr3 # a b c d e

实现(lib/utils.zsh)借助 Zsh 的typeset -U(unique)数组属性一行完成去重:

spaceship::union() { typeset -U sections=("$@") echo $sections }

typeset -U声明数组时自动消除重复元素,且保持首次出现的顺序,因此结果稳定为a b c d e。对应测试见 tests/utils.test.zsh。

spaceship-prompt 内部用它对SPACESHIP_PROMPT_ORDERSPACESHIP_RPROMPT_ORDER两个 Section 列表做并集,以确定“需要加载哪些 Section 文件”:

  • lib/core.zsh 的spaceship::core::load_sectionsspaceship::union $SPACESHIP_PROMPT_ORDER $SPACESHIP_RPROMPT_ORDER得到去重后的完整 Section 集合;
  • lib/core.zsh 的spaceship::core::start同样用它遍历刷新所有 Section。

这种设计保证了即使某个 Section 同时出现在主提示符与右侧提示符中,也只会被加载、执行一次。

八、向上搜索:spaceship::upsearch

spaceship::upsearch [--silent] <paths...>

从当前目录逐级向上搜索指定的文件或目录,返回第一个命中项的完整路径;向上最多搜到仓库根或文件系统根目录。该工具对理解当前目录的“项目上下文”非常有用。

参数说明:

  1. paths...必填— 待搜索的路径列表;
  2. --silent-s可选— 静默模式:只要paths中至少有一个被找到即返回零退出码,否则返回非零,不打印任何路径。

使用示例:

# 识别项目上下文 spaceship::upsearch -s package.json node_modules && echo "Node project detected." # 向上查找特定文件 spaceship::upsearch package.json # /path/to/project/package.json

实现(lib/utils.zsh)的算法值得细读:

spaceship::upsearch() { # 解析 CLI 选项 zparseopts -E -D \ s=silent -silent=silent local files=("$@") local root="$(pwd -P)" # 逐级向上直到根目录 while [ "$root" ]; do # 对每个作为参数的文件 for file in "${files[@]}"; do local find_match="$(find $root -maxdepth 1 -name $file -print -quit 2>/dev/null)" local filename="$root/$file" if [[ -n "$find_match" ]]; then [[ -z "$silent" ]] && echo "$find_match" return 0 elif [[ -e "$filename" ]]; then [[ -z "$silent" ]] && echo "$filename" return 0 fi done if [[ -d "$root/.git" || -d "$root/.hg" ]]; then # 到达仓库根仍未找到,返回非零 return 1 fi # 向上一级 root="${root%/*}" done # 到达文件系统根仍未找到,返回非零 return 1 }

要点:

  1. 边界停止条件:循环中一旦发现当前目录含有.git.hg就立即以失败返回(非零),即搜索不会越过仓库根继续向外扩散——这是is_hg能依赖它的前提;
  2. 搜索顺序:在同一级目录内按参数给定的顺序逐一尝试,find -maxdepth 1负责处理文件名中的通配符;
  3. 静默语义--silent/-s存在时抑制路径输出,仅保留退出码,便于&&/||短路判断。

spaceship::upsearch是众多语言/工具 Section 识别项目类型的核心手段,仓库内有大量真实用例,例如:

  • sections/bun.zsh:spaceship::upsearch -s bun.lockb bun.lock bunfig.toml || return
  • sections/dart.zsh:查找pubspec.yaml pubspec.yml pubspec.lock dart_tool
  • sections/docker.zsh:同时探测Dockerfile与一组 compose 文件名;
  • sections/ansible.zsh:向上查找ansible.cfg/.ansible.cfg

这些 Section 的通用模式是:用-s静默探测命中即继续渲染,未命中则立即return,与文档示例高度一致。

九、数据文件查询:spaceship::extract(别名spaceship::datafile

!!! note 本工具的别名是spaceship::datafile(向后兼容)。

spaceship::extract用于从数据文件中查询指定键的值,返回该键对应的内容;当文件类型未知、数据无法读取或键不存在时,以非零退出码结束。

spaceship::extract --<type> <file> [...keys]

参数说明:

  1. --type必填— 数据文件类型,可取jsonyamltomlxml
  2. file必填— 数据文件路径;
  3. key可选— 要在数据文件内查询的键,支持点号(dot notation)路径,例如author.name;可传多个键作为备选。

使用示例:

spaceship::extract --json package.json "author.name" # "John Doe"

读取不同格式的数据文件需要相应的命令行工具:

  • JSONjqyqpython-yqpythonnode中的任意一个;
  • YAMLyqpython-yqpython
  • TOMLtomlq(随python-yq附带提供);
  • XMLxq(随python-yq附带提供)。

官方文档给出的建议是:读取数据文件最通用的解决方案是使用python-yq(它同时覆盖 YAML/TOML/XML,并附带tomlqxq)。工具缺失时spaceship::extract会返回非零退出码。

源码中的后端分派链

lib/extract.zsh 中spaceship::extract的实现展示了完整的后端降级策略(fallback chain),每种格式都按“优先级从高到低”尝试可用工具:

  • YAMLyqrubypython3
  • JSONjqyqrubypython3node
  • TOMLtomlqpython3(Python 3.11+ 使用标准库tomllib,更早版本回退到第三方包tomli,见 lib/extract.zsh);
  • XML:仅xq

每一条分派链都以spaceship::exists探测工具是否可用,全部缺失则返回 1。这一点再次印证了spaceship::exists作为基础设施工具的价值。别名spaceship::datafile只是简单转发(lib/extract.zsh)。

安全性设计:文件路径绝不内插进脚本

tests/extract.test.zsh 中一组针对性测试揭示了一个重要的安全设计:数据文件路径始终以命令行参数(argv)方式传给后端解释器,而不是拼接进生成的脚本代码中。测试特意构造了包含'+\touch PWNED`+'` 这种恶意片段的文件名,并断言:

  • Python 后端使用-c执行脚本,文件经sys.argv[1]读取,脚本源码中不出现文件名字面量(test_python_json_passes_file_as_argv);
  • Ruby 后端在--之后传递文件,脚本内通过ARGV[0]引用,同样不内插文件名;
  • Node 后端通过process.argv[1]配合require('path').resolve解析路径,--分隔符保留。

这从测试层面确认:spaceship::extract能安全处理带特殊字符的路径,避免 shell 注入风险,属于值得自定义 Section 作者借鉴的实现范式。

十、测试与验证:工具函数的可观测保证

所有工具函数都有对应的 shunit2 测试(见 tests/utils.test.zsh 与 tests/extract.test.zsh),覆盖了正常路径与边界场景:

工具函数测试用例验证要点
spaceship::existstest_exists内建命令cd为真、随机串为假、函数为真
spaceship::definedtest_defined函数为真、内建命令/随机串为假
spaceship::is_gittest_is_git仓库根、子目录均为真,仓库外为假
spaceship::is_hgtest_is_hg仓库根、子目录为真,带空格路径不误判
spaceship::is_section_asynctest_is_section_asyncSection 开关、全局开关、强制同步清单的组合
spaceship::is_prompt_asynctest_is_prompt_async全局开关 × 异步库初始化状态
spaceship::deprecatedtest_deprecated警告文本的精确渲染(含/不含附加信息)
spaceship::displaytimetest_displaytime大秒数拆分14d 6h 56m 7.0s
spaceship::uniontest_union多数组去重并集a b c d e
spaceship::extracttest_*_passes_file_as_argv各后端参数传递与防注入安全

十一、小结:如何在自己的 Section 中组合使用

回顾 docs/api/utils.md 的完整脉络,这些工具函数共同构成了一套面向 Section 开发的“标准库”。推荐的实战组合套路如下:

  1. 探测依赖:用spaceship::exists <tool>判断运行时是否就绪,未就绪直接return
  2. 识别项目:用spaceship::upsearch -s <marker...>静默向上查找项目特征文件(如package.jsonDockerfile),命中才渲染 Section;
  3. 读取元数据:用spaceship::extract --json package.json "version"等从数据文件取出版本号等展示信息;
  4. 仓库判断:需要区分 Git/Mercurial 时用spaceship::is_git/spaceship::is_hg
  5. 尊重异步配置:在自定义 Section 中如需感知异步调度,通过spaceship::is_section_asyncspaceship::is_prompt_async判断(注意不要把这些工具与 Section 渲染函数spaceship::section::render混淆,后者见 docs/api/section.md);
  6. 处理弃用与时间:旧配置项迁移用spaceship::deprecated,耗时展示用spaceship::displaytime

若需编写可测试的自定义逻辑,可参考 docs/api/testkit.md 了解官方测试工具包,并仿照 tests/utils.test.zsh 的结构为自己的函数补充断言。理解了这套“探测—识别—查询—渲染”的 API 体系,你就能写出与内建 Section 同样健壮、同样风格统一的自定义提示符组件。

【免费下载链接】spaceship-prompt🚀✨ Minimalistic, powerful and extremely customizable Zsh prompt项目地址: https://gitcode.com/gh_mirrors/sp/spaceship-prompt

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 20:55:04

SAP PP中MPS与MRP的区别、配置及实操排查全解析

做SAP PP顾问这几年&#xff0c;我面试过不少候选人&#xff0c;也带过很多刚转行做PP模块的新人。有一个问题我几乎每次都会问&#xff1a;MPS和MRP到底有什么区别&#xff1f;结果十个人里有六七个答不清楚&#xff0c;剩下的几个也大多是背概念&#xff0c;一放到实际业务场…

作者头像 李华
网站建设 2026/9/20 20:53:15

Multisim单管与多级放大电路仿真实践:从静态工作点到数据报告

简介&#xff1a;一份面向电子电路课程实训的Multisim仿真教学PPT&#xff0c;围绕单管低频共射极放大电路与RC耦合两级放大电路&#xff0c;系统讲解静态工作点测量与调整、动态参数仿真、参数扫描分析及仿真数据处理&#xff0c;适合高校电子信息类专业学生、课程设计者及电路…

作者头像 李华
网站建设 2026/9/20 20:49:46

Atlas 300V 24G 推理加速卡上 YOLO 模型部署实战指南

最近好多人在问「Atlas 300V 24G 是不是运算加速卡」&#xff0c;还有人直接抛出一句「atlas 部署 YOLO 怎么弄」。这两个问题放在一起特别有意思&#xff1a;前者说明大家还没搞清这张卡的定位&#xff0c;后者说明已经想把它用到实际业务里了。我前后在 Atlas 300V 系列上折腾…

作者头像 李华
网站建设 2026/9/20 20:48:29

四自由度机械臂建模:Matlab Robotics Toolbox实战指南

1. 为什么四自由度机械臂是入门机器人建模的“黄金切口”我带过十几届自动化和机电专业的学生做课程设计&#xff0c;也帮过七八家初创机器人公司搭仿真底座。每次被问“该从哪开始学机器人建模”&#xff0c;我的第一反应从来不是直接扔出DH参数表或推导雅可比矩阵——而是先拉…

作者头像 李华
网站建设 2026/9/20 20:48:02

基于 Spring Boot 的社区志愿时长统计管理系统设计与实现

温馨提示&#xff1a;本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 1. 引言 随着社区治理的不断深化&#xff0c;志愿服务已成为社区建设的重要组成部分。然而&#xff0c;传统的人工登记方式在志愿时长统计方面存在记录易丢失、统计效率…

作者头像 李华
网站建设 2026/9/20 20:45:24

react className 敲空格才出提示?用 TaoToken 接 Codex 对着插件配置查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华