CubeFS 命令行交互背后的 Go readline 库:desertbit/readline 演进史与核心机制解析
存储分布式文件系统对象存储云原生【免费下载链接】cubefscloud-native distributed storage项目地址https://gitcode.com/gh_mirrors/cu/cubefs点击查看免费下载导读本文以 CubeFS 仓库中 vendored 的github.com/desertbit/readline其官方 CHANGELOG 收录于 vendor/github.com/desertbit/readline/CHANGELOG.md为绝对主线完整梳理该库从 1.0 到 1.4 的版本演进脉络逐条解读自动补全、历史记录、Vim 模式、密码输入、多行编辑、信号处理等核心能力并结合仓库内源码实现与 CubeFS 的 CLI 落地方式做纵深印证。读完本文你将理解一个纯 Go 实现的 GNU-Readline 风格库在跨平台终端交互上的设计取舍也能看清它在 CubeFSblobstore/cli交互式命令行中承担的角色。一、库的定位纯 Go 实现的 GNU-Readline 风格库desertbit/readline是一个纯 Go 实现、面向Linux/macOS/Windows/Solaris的 readline 库其包注释见 readline.go明确自述为 a pure go implementation for GNU-Readline kind library。在 CubeFS 仓库中它通过 go.mod 以github.com/desertbit/readline v1.5.1 // indirect的形式被引入注意 go.mod 中锁定的版本已高于 CHANGELOG 记录的 1.4说明 1.4 之后仍有迭代具体代码全部落在 vendor/github.com/desertbit/readline 目录下共约 30 个.go文件按职责可分成几大块入口与配置readline.goInstance、Config、std.go全局单例 API行编辑核心runebuf.goRuneBuffer、operation.go事件循环、runes.gorune 工具函数功能模块complete.go 与 complete_helper.go补全、history.go历史记录、vim.goVim 模式、password.go密码输入、search.go历史搜索平台层term.gotermios 原始模式及各平台的term_linux.go/term_windows.go/ansi_windows.go/rawreader_windows.go/windows_api.go等CHANGELOG 记录了 2015-10-141.0 首发至 2016-07-251.4的演进本文按两条线索组织先给出完整时间线再按功能主题做源码级深挖。二、完整版本演进时间线ChangeLog 全量解读以下内容完整覆盖 CHANGELOG.md 的全部条目issue 编号如 #60、#38均沿用原文仅省略其外链。1.4 - 2016-07-25支持动态自动补全#60补全候选不再局限于静态枚举可在运行时由回调函数生成为命令参数、文件路径等动态场景铺路。修复 Windows 上的 ANSI 解析器Windows 控制台对 ANSI 转义序列的处理与 Unix 不同此版本修正了 Windows 下终端色彩/控制序列的解析。修复 Windows 补全模式下错误的列宽计算补全候选以矩阵形式排版展示Windows 下列宽计算错误会导致候选列表错位本版本修复。移除对golang.org/x/crypto/ssh/terminal的依赖此前终端 raw mode 等能力依赖x/crypto子包1.4 起改为自实现仓库中 term.go 的MakeRaw/Restore/IsTerminal即内嵌了基于 termios 的原始模式实现降低了外部依赖耦合。1.3 - 2016-05-09为前缀补全接口新增SetChildren#38PrefixCompleter的子树可在运行时动态替换补全树结构不再只读。提升多行输入兼容性#42多行编辑如一次提交多条 SQL的兼容性改进。移除子包 runes 以兼容 gopkg#43将 runes 工具内聚便于 gopkg 导入。支持带空格前缀行的自动补全#46此前以空格开头的行shell 中常见补全会异常本版本修复。支持挂起进程CtrlZ即 #48终端内可挂起 readline 进程并恢复。修复与上一条命令做相等比较的 bug#49历史记录判重逻辑修正。修复输入缓冲区为空时整数除零 panic#53空缓冲区场景下求补全列宽/候选矩阵时发生divide by zero本版本修复对应 complete.go 中补全矩阵宽度计算逻辑。1.2 - 2016-03-05新增密码强度检查 demo由社区 sahib 贡献演示密码输入 实时强度提示的组合用法。支持 stdin 重映射#23Config.Stdin可替换为任意io.ReadCloser为测试注入与管道输入提供可能。新增UniqueEditLine配置项#27用户提交行后自动擦除当前编辑行典型场景是 IM即时通讯输入框避免上一行内容残留视觉干扰。新增多行输入 demo支持通过多行回车提交一条完整 SQL。即使 stdin/stdout 不是 tty 也能正常工作管道、重定向、CI 环境下 readline 依旧可用结合Config.FuncIsTerminal与ForceUseInteractive见 readline.go。新增单实例简易 API见 std.goLine/Password/AddHistory等无需自行管理Instance注意使用该 API 时需手动保存历史SetHistoryPath配合AddHistory。修复历史记录工作异常#28。Vim 模式新增c、d、x删除字符、r替换字符#33详见下文Vim 模式小节。1.1 - 2015-11-20新增Delete/Home/End按键支持#12补全了行编辑的基本按键集。仅在需要时进入原始模式只有真正调用Readline()交互时才进入 raw mode程序在非交互阶段仍能正常收到信号如 CtrlC避免长期占用终端状态。修复PrefixCompleter的若干 bug。Shell 化的 EOF/Interrupt 语义在空行按CtrlD返回io.EOF任意时刻按CtrlC返回ErrInterrupt而非io.EOF提供类 shell 的用户体验二者均可用Config定制提示文案。改用 32 位原子函数#17让库可在 arm 32 位设备上运行对应 std.go 中CancelableStdin.closed的atomic.LoadInt32/CompareAndSwapInt32。提供全新的密码输入体验readline.ReadPasswordEx()带掩码与监听器的密码读取。1.0 - 2015-10-14首次公开发布初始版本上线。三、源码级机制深挖从 ChangeLog 到实现3.1 自动补全静态前缀树 → 动态回调#38 / #46 / #60ChangeLog 中 #38、#46、#60 三条都围绕补全展开其实现横跨两个文件complete.go 定义了核心接口AutoCompleterDo(line []rune, pos int) (newLine [][]rune, length int)按 TAB 触发Config.AutoComplete见 readline.go。OnComplete会先尝试聚合公共前缀runes.Aggregate再进入候选选择模式EnterCompleteSelectMode支持方向键/PageUp/PageDown 遍历矩阵候选。complete_helper.go 提供了开箱即用的PrefixCompleter/PcItem构造器PcItem(get, PcItem(key))即可构建命令树。#38 引入的SetChildren第 78-80 行允许运行期替换子树#60 引入的动态补全通过PcItemDynamic(callback, ...)第 95-101 行与DynamicCompleteFunc func(string) []string实现回调接收当前行、返回候选列表GetDynamicNames中每个候选自动追加一个空格后缀便于连续补全。而#46带空格前缀行的补全的修复点在doInternal第 111 行起先runes.TrimSpaceLeft(line[:pos])裁剪光标前的空白再匹配子命令使得 shell 脚本常见的行首缩进输入也能正确补全。3.2 信号与错误语义shell 化的 CtrlD / CtrlC1.11.1 版确立的错误语义至今沿用空行CtrlD→io.EOF任意时刻CtrlC→ErrInterrupt。定义见 operation.goErrInterrupt errors.New(Interrupt)Instance.Readline()的注释也写明返回值是nil / io.EOF / readline.ErrInterrupt三者之一readline.go。配套的Result.CanContinue()/CanBreak()readline.go允许调用方把被中断但已有输入的行继续提交实现 shell 式交互。两个提示文案可通过Config.InterruptPrompt/Config.EOFPrompt定制默认分别为^C/^D置为\n可关闭提示readline.go。仅在需要时进入 raw mode则体现在 term.go 的MakeRaw第 38-60 行按 termios(3) 的cfmakeraw语义关闭ECHO/ICANON/ISIG/IXON等标志位、将VMIN设为 1、VTIME设为 0仅在Readline()交互期间生效退出即Restore因此程序在非交互阶段仍能收到 CtrlC 信号。3.3 历史记录持久化、去重、折叠搜索#28 / #49 / 1.2历史功能的配置集中在 readline.goHistoryFile持久化文件路径、HistoryLimit上限默认 500置 -1 禁用、DisableAutoSaveHistory、HistorySearchFold不区分大小写搜索。实现见 history.go加载与持久化historyUpdatePath第 66-95 行以O_APPEND|O_CREATE|O_RDWR打开历史文件逐行回读超过HistoryLimit时通过rewriteLocked第 109-137 行先写临时文件再os.Rename原子替换避免历史文件无限膨胀。去重与上限Compact第 97-101 行从链表头部裁剪超出上限的旧条目。#49 修复的与上一条命令相等比较bug即体现在此处对历史条目的去重比较逻辑中。搜索FindBck/FindFwd第 147-180 行向后/向前模糊匹配支持HistorySearchFold的大小写折叠runes.IndexAllBckEx。#27 的UniqueEditLine与1.2 的历史修复#28一起保证了提交即擦除的 IM 场景下历史回放与当前编辑行互不干扰。3.4 多行输入与 stdin 重映射#23 / #42 / 1.2stdin 重映射#23Config.Stdin可注入任意io.ReadCloser。Config.Init()readline.go内部还会用NewCancelableStdinNewFillableStdin两级包装实现见 std.go前者提供可取消的异步读配合io.Pipe实现WriteStdin预填充后者支持先读本地缓冲、再回落真实 stdin。这也正是Instance.WriteStdin能实现 test[cursor]预填充效果readline.go的原因。多行输入#42rune 缓冲区runebuf.go天然支持跨行编辑1.2 的多行 demo 展示了一次提交多条 SQL 的用法而 1.3 的 #42 进一步提升了多行场景下光标定位与换行重绘的兼容性。非 tty 支持Config.useInteractive()readline.go根据ForceUseInteractive或FuncIsTerminal判定管道/重定向下自动退化为非交互读取。3.5 Vim 模式从移动键到c/d/x/r#33vim.go 定义VIM_NORMAL/VIM_INSERT/VIM_VISUAL三种状态由Config.VimMode开启默认进入 insert 模式见 readline.go。Normal 模式移动handleVimNormalMovement第 40-96 行h/j/k/l四方向、0/^/$行首行尾、b/B/w/W/e/E单词移动、f/F/t/T字符查找移动、x删字符、r替换字符、d前缀 d/w/h/l组合删除、p粘贴yank、dd整行删除。进入插入模式handleVimNormalEnterInsert第 98-131 行i/I/a/A/s/S/c含cc/cw/ch/cl等 Vim 惯用语义全部在 1.2 的 #33 中补齐。无效操作触发终端 Bell第 149 行与普通模式无缝切换。3.6 密码输入掩码与掩码 rune1.1password.go 的PasswordConfig()第 22-32 行展示密码模式的完整配置EnableMask: true、InterruptPrompt/EOFPrompt置\n关闭提示、HistoryLimit: -1禁用历史。Config.MaskRune决定掩码字符默认*可通过Instance.SetMaskRunereadline.go运行时更换。API 上ReadPassword/ReadPasswordEx(prompt, l)分别对应 1.1 的普通版与带Listener的增强版配合 1.2 的密码强度 demo 思路可实现输入密码同时显示强度条的体验。EnableMask/MaskRune字段定义在 readline.go。3.7 单实例 APIstd.go1.21.2 引入的全局单例 APIstd.go基于sync.Once惰性初始化DisableAutoSaveHistory: true对外暴露SetHistoryPath(fp)、SetAutoComplete(c)、AddHistory(content)、Password(prompt)、Line(prompt)。关键约束CHANGELOG 与代码注释双重确认该 API不会自动提交历史若要持久化历史需先SetHistoryPath再手动AddHistorySetHistoryPath()可阻止落盘此时AddHistory恒返回 nil。适合快速脚本与小型工具而大型 CLI 通常改用NewEx(Config{...})的显式实例。3.8 平台与稳定性修复1.4 / #17 / #53Windows 侧ansi_windows.go 与 term_windows.go 承载 ANSI 解析与列宽计算1.4 的两个修复ANSI 解析、补全模式列宽都在此落地rawreader_windows.go 处理 Windows 下的按键原始读取。arm 32 位#17原子操作统一走 32 位函数atomic.LoadInt32等见 std.go保证 arm 32 位设备可运行。除零 panic#53补全候选矩阵的列数计算对 0 宽度/空缓冲做了保护对应 complete.go 的候选索引取模与nextCandidate的负数归一化逻辑。依赖精简1.4term.go内嵌了原本来自x/crypto/ssh/terminal的MakeRaw/Restore/IsTerminal/GetState/ReadPassword第 29-123 行彻底去掉该外部依赖。四、在 CubeFS 中的落地blobstore CLI 的交互式 ShellCubeFS 的blobstore/cli正是这套 readline 能力的直接消费者。其依赖链为blobstore/cli的 app.go 通过grumble.New(grumble.Config{...})创建命令框架而 grumble 内部使用 readline 驱动交互循环。关键证据在 vendor/github.com/desertbit/grumble/app.goa.rl, err readline.NewEx(readline.Config{ Prompt: a.currentPrompt, HistorySearchFold: true, // enable case-insensitive history searching DisableAutoSaveHistory: true, HistoryFile: a.config.HistoryFile, HistoryLimit: a.config.HistoryLimit, AutoComplete: newCompleter(a.commands), })对照上文可以清晰看到 CHANGELOG 各特性的实际运用HistorySearchFold: true即 1.1 起支持的大小写折叠历史搜索DisableAutoSaveHistory: true与显式HistoryFile/HistoryLimit对应历史持久化与去重上限机制history.goAutoComplete: newCompleter(a.commands)把 grumble 的命令树接入AutoCompleter接口#38/#60 的补全能力主循环对readline.ErrInterrupt与io.EOF的分流处理vendor/github.com/desertbit/grumble/app.go正是 1.1 确立的shell 化错误语义CtrlC走interruptHandler继续循环CtrlD正常退出readline.ClearScreen(a.rl)第 353 行与内置clear命令打通说明 readline 不仅提供行编辑还暴露了ClearScreen等终端工具函数。CubeFS 的 blobstore 各模块 CLIaccess、clustermgr、blobnode、scheduler、shardnode等见 blobstore/cli 目录均构建在这一交互底座之上。若需本地体验可参照仓库的 blobstore/Makefile 编译相关 CLI 后进入其交互 Shell 试用补全、历史搜索、CtrlC中断与CtrlD退出等能力。五、结语回看 CHANGELOG.md这个库的演进路径非常清晰1.0 完成基础行编辑1.1 确立 shell 化信号语义与密码输入1.2 补齐单实例 API、多行/非 tty/重映射能力与 Vim 编辑命令1.3 完善补全树与稳定性1.4 收尾于动态补全与跨平台修复并削减外部依赖。每个版本条目都能在 vendor/github.com/desertbit/readline 的源码中找到对应实现也能在 CubeFS 的 blobstore CLI经 grumble 间接消费中看到真实运用——这正是从 ChangeLog 到源码再到生产实践的完整闭环也是理解 Go 终端交互编程的一份高质量参考教材。赞分享存储分布式文件系统对象存储云原生【免费下载链接】cubefscloud-native distributed storage项目地址https://gitcode.com/gh_mirrors/cu/cubefs点击查看免费下载相关推荐buildah 依赖剖析chzyer/readline 库版本演进与命令行交互能力详解buildah 依赖剖析chzyer/readline 库版本演进与命令行交互能力详解 导读 chzyer/readline 是一个纯 Go 实现、跨平台云原生Go 语言 readline 库演进全解chzyer/readline 1.0 到 1.4 核心能力与源码实现Go 语言 readline 库演进全解chzyer/readline 1.0 到 1.4 核心能力与源码实现 本文以 chzyer/readline 的官方云原生容器运行时探索高效命令行交互ReadLine库探索高效命令行交互ReadLine库 项目介绍 在开发基于控制台的应用时提供高效的用户输入管理是关键的一环。 ReadLine https://github上一篇终极Redux-Thunk性能优化指南避免8个常见异步陷阱下一篇K-quant还是I-quantKwaipilot_KAT-Coder-V2.5-Dev-GGUF量化格式选择终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

OWASP Top 10:2025 之 A04 加密机制失效(Cryptographic Failures)深度解析与防护实战

OWASP Top 10:2025 之 A04 加密机制失效(Cryptographic Failures)深度解析与防护实战

应用安全 【免费下载链接】Top10 Official OWASP Top 10 Document Repository 项目地址: https://gitcode.com/gh_mirrors/top/Top10 点击查看 免费下载 导读:本文以 OWASP Top 10:2025 官方文档仓库中的 A04:2025 加密机制失效(西班牙语版&…

2026/10/12 1:32:50 阅读更多 →
Claude Code 成本暴跌 92%:从 26 美元到 2 美元的 API 降本实践

Claude Code 成本暴跌 92%:从 26 美元到 2 美元的 API 降本实践

上个月我把一个攒了很久的个人项目丢给 Claude Code 去重跑:全量重构、改接口、补测试、顺手写一堆文档和迁移脚本。二十多天下来,终端里累计跑掉了 400 万 Tokens,月底打开 API 账单一看,26 美元。这个数字放到企业项目里不算什么…

2026/10/12 1:32:50 阅读更多 →
Ant Design Blazor Spin 组件加载状态实战指南:从基本用法到自定义指示符

Ant Design Blazor Spin 组件加载状态实战指南:从基本用法到自定义指示符

前端UI组件设计系统 【免费下载链接】ant-design-blazor 基于 Ant Design 与 Blazor 的前端组件库。让开发者解放生产力,实现更大价值。 项目地址: https://gitcode.com/ant-design-blazor/ant-design-blazor 点击查看 免费下载 当页面局部正在等待异步…

2026/10/12 1:31:49 阅读更多 →

最新新闻

【深度学习新浪潮】Meta Muse 智能体:它是什么?有哪些特点?为什么突然火了?

【深度学习新浪潮】Meta Muse 智能体:它是什么?有哪些特点?为什么突然火了?

1. 引言 近期,Meta Muse 智能体在 AI 领域引发广泛关注,开发者、创作者与科技从业者纷纷展开讨论。许多初次接触者不禁疑惑:这是 Meta 推出的又一款大模型?抑或仅是蹭热度的 AI 玩具? 事实并非如此。Meta Muse 是 Meta 在 AI 智能体方向的一次战略性布局,它并非简单的对…

2026/10/12 2:24:22 阅读更多 →
Spring-boot-3 -注解 yaml配置 -日志

Spring-boot-3 -注解 yaml配置 -日志

4、核心技能1. 常用注解SpringBoot 摒弃 XML 配置方式,改为全注解驱动1. 组件注册Configuration 自定义配置类、SpringBootConfiguration 用来标注SpringBoot主启动类的Bean 可以在自定义配置类面创建对象交给ioc容器,组件在容器中的名字为方法名、Scope…

2026/10/12 2:24:22 阅读更多 →
Neuroimage: 动态功能连接方法的重测信度比较

Neuroimage: 动态功能连接方法的重测信度比较

本篇文献发表在Neuroimage杂志。所发布内容旨在与大家分享学术新知,促进交流学习版权归原作者或原出处所有,感谢各位学者的辛勤付出与研究成果。1.引言大脑的功能组织具有丰富的时空结构,可以使用功能连接指标进行探测。功能连接被定义为两个…

2026/10/12 2:24:22 阅读更多 →
page_alloc __rmqueue

page_alloc __rmqueue

__rmqueue() 是伙伴系统分配路径的核心调度器。它在持有 zone->lock 的前提下,按照碎片化风险从低到高的顺序,依次尝试不同的分配策略,直到成功或彻底失败。核心作用与策略链它的本质是一个多级降级策略链:先尝试最“干净”的方…

2026/10/12 2:24:22 阅读更多 →
游戏引擎中物理步进与动画采样的同步机制解析

游戏引擎中物理步进与动画采样的同步机制解析

1. 这不是教科书,是我在三个项目里拆过七次引擎后写下的物理与动画系统手记“游戏引擎架构深度解析(三):物理与动画系统”——看到这个标题,你大概率正卡在某个角色落地时穿模、布料抖动像癫痫发作、或者刚加完一个新关…

2026/10/12 2:24:22 阅读更多 →
产业与汇率全景分析深入分析多表格形成一篇文章

产业与汇率全景分析深入分析多表格形成一篇文章

产业与汇率全景深度分析:汇率是外生变量,产业是底层根基引言汇率从来不是孤立的数字,它是一国产业竞争力、贸易结构、资本流动、宏观政策、全球供需格局共同定价的结果;反过来,汇率波动又会重塑产业成本、订单、利润、…

2026/10/12 2:23:21 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/11 14:36:54 阅读更多 →