最近在整理开发环境时我越来越觉得“上下文”是效率的头号杀手。比如你正开着三个终端窗口一个在调A项目的接口一个在翻B项目的日志还有个窗口里挂着刚才跑起来的本地服务。来回切几次你很快就会忘掉当前目录是哪、环境变量被谁改过、上一次的命令输出是什么。这种状态混在一起的情况就是典型的上下文串味。我今天想聊的 context-mode就是专门为这种问题准备的一套工作方式把“当前正在干什么”显式地定义成一个个模式进入某个模式就加载对应的状态退出时再保存回去让工具跟着任务走而不是人跟着工具走。这套东西听起来很玄其实核心特别简单它就是一个状态管理器。你可以把它做成一个命令行工具也可以只是自己常用的一个 shell 函数集。我之所以觉得值得拿出来写一篇是因为它解决的不只是终端里的问题还延伸到 AI 对话、IDE 工作区、多版本开发环境管理等场景。不管你是天天敲命令的运维、写代码的程序员还是经常跟各种工具打交道的效率党都能从这里找到一点能直接用的思路。1. context-mode 到底在解决什么问题1.1 上下文丢失与上下文污染我们先从最痛的场景说起。假设你在终端里同时负责两个项目项目A是 Java 后端项目B是 Python 数据处理。按照惯例你会开两个终端窗口或者用 tmux 开两个面板。但你会发现光是有一块单独的窗口是不够的因为很多状态并不跟着窗口走。比如当前目录窗口独立的但如果你用cd乱跳还是容易搞乱。环境变量项目A要设置JAVA_HOME和MAVEN_OPTS项目B要设置PYTHONPATH和VIRTUAL_ENV。如果在一个 shell 里先加载了 A 的环境再切去跑 B 的命令轻则变量冲突重则整个命令跑错。命令历史A项目里你查过的curl接口B项目里可能完全没用。历史混在一起按上下箭头翻半天。临时文件/会话信息比如你在 A 里登录了一个数据库连接凭证存在某个环境变量里切到 B 时这个凭证很容易残留。这种两个任务互相干扰的情况就是上下文污染。还有一种更隐蔽的问题是上下文丢失你开了十几个标签页但任何一个都没完整保存“当前思路”。过两天回来你得重新想一遍当时做到哪了。context-mode 的核心目标就是把一组彼此相关的状态打包成一个可命名的上下文让切换变成“进入一个 context”和“退出一个 context”而不是手工盯着每个变量。1.2 模式mode这个抽象到底是什么意思我之所以叫它 context-mode而不是单纯说“环境切换”是因为“模式”这个词更形象。就像 Vim 编辑器里有普通模式和插入模式在普通模式下你按i会进入插入模式按Esc会回去。每个模式都有一套专属的按键行为切换是显式的、有边界的。context-mode 做的是同一件事只是把“模式”从编辑器扩展到了整个工作环境。一个模式可以包含这些状态片段工作目录cwd环境变量集合envShell 局部变量和别名当前绑定的 Python 虚拟环境 / Node 版本 / JDK命令历史片段甚至是一段 AI 对话的上下文消息列表当你执行cm enter project-a时工具读取 project-a 模式里保存的所有状态把它们恢复进当前 shell执行cm exit时把当前 shell 的最新状态再写回这个模式。这样project-a 和 project-b 各自是干净的不会串味。有人可能会说这跟direnv有什么区别direnv是根据目录自动加载环境变量它解决的只是“进入目录自动配置环境”这一层而且它不负责保存状态、不管理命令历史、不处理会话列表。context-mode 更像是一个通用状态舱目录只是我们能挂载的状态之一。说白了direnv是“目录模式”而 context-mode 是“任务模式”边界由你手动控制灵活度更高。1.3 适用场景清单在往下聊实现之前先明确一下这玩意儿到底适合谁、怎么用。我实测下来最常用的场景有这些多项目并行开发同时维护好几个代码仓库每个仓库有独立的环境变量、端口配置、虚拟环境。多客户环境运维接多个客户的服务器每台机器的连接方式、密钥路径、常用操作命令都不一样。本地 AI 对话调试同时跑好几个对话任务需要给每个任务独立的上下文窗口避免互相干扰。演示/直播环境需要快速切换一套干净的演示环境不能把平时的环境和演示环境搞混。如果你的工作流相对单一可能用不上这么重的方案但哪怕只是抱着学习状态管理思路的目的也值得往下看。2. 设计一个 context-mode 的关键点2.1 上下文状态存到哪里我觉得做这种工具第一件要决定的事就是状态存哪。最省事的方案是放在~/.context-mode/目录下一个 context 一个文件夹里面用普通文本文件保存各个状态。优点是肉眼可见、好备份好调试。比如~/.context-mode/ default/ cwd env.sh history.txt meta.json project-a/ cwd env.sh history.txt meta.jsoncwd里就写一行当前目录路径env.sh是一个可被source的 shell 脚本里面是export KEYVALUE形式history.txt你可以直接存最近的命令历史meta.json存创建时间、描述等元信息。用文本文件的好处是出问题时你直接cat就能看到状态不用打开数据库。如果你需要频繁地查询、导入导出或者想把 context 和某个服务端同步那换成 SQLite 更好。我在后来的版本里就用了 SQLite主要是因为免驱动、单文件、支持并发。说实话对于个人用途JSON 文件就够了SQLite 属于锦上添花。关键不是存储引擎而是你要有一个清晰的读写协议什么字段、什么时候写、读的时候采用什么覆盖策略。2.2 状态切换的两个时序问题一个 context-mode 最容易被忽略的地方是“切换顺序”。我最初写的时候踩过坑进入一个 context 时应该先把当前 shell 的状态快照保存到旧 context再加载新 context。否则你在 project-a 里辛苦调整的环境变量会被 project-b 给覆盖掉。简单画一下正常流程用户输入cm enter project-b。工具把当前 shell 的所有有效状态即 project-a 最新的状态去掉那些临时改动保存回 project-a。读取 project-b 的cwd、env.sh、history等文件。清空当前 shell 中所有在 context 控制范围内的变量。加载 project-b 的变量切换目录替换历史文件。提示已进入 project-b。其中“清空”这步特别关键。如果只export新变量而不清理旧变量旧的PYTHONPATH就会残留在新 context 里造成污染的源头。怎么知道哪些变量需要清理最简单粗暴的办法是维护一个“受控变量列表”比如CONTROLLED_VARS [JAVA_HOME, PYTHONPATH, VIRTUAL_ENV, NODE_VERSION, CUSTOM_FLAG]切换 context 时先把这些变量全部unset再加载新的值。更通用的办法是在进入一个 context 时记录完整的环境 hash退出时对比 env 差异删除在本次会话里新增的变量。第二种更自动化但实现复杂度高。我的建议是刚开始做时先手动维护一个白名单够用就行等真有需要再升级。2.3 默认 context 和继承关系另一个很实用的设计是“默认 context”。比如我平时总有一些通用配置不管进哪个项目都要有常用的几个别名、EDITORvim、LANGzh_CN.UTF-8。如果每次进一个 context 都要重复写一遍这些变量那太浪费了。我采用的方式是三层继承全局默认层default所有 context 共享的底层状态。项目层比如project-a、project-b这一层覆盖默认层的同名变量。任务层比如project-a-debug在主项目 context 里再细分通常只用于临时任务用完即弃。加载一个 context 时工具会先读取 default再读取当前层再读取更具体的层。同一名字的变量越靠后的层优先级越高。这种设计其实就是你熟悉的后端配置中心的优先级逻辑放在本地工具里同样适用。3. 实操用 Python 写一个轻量级 context-mode3.1 准备工作与最小依赖现在我来分享一个真正能跑起来的实现。我选了 Python 而不是 Go 或 Rust原因很简单Python 在系统里通常已经自带而且写这种状态管理和字符串处理很快。如果你要发布给很多人用那用 Go 编译成单二进制更合适。但作为自己日常工作流增强Python 足够。我们需要的东西只有 Python 3.9 以上版本外加标准库的argparse、os、subprocess、sqlite3不需要任何第三方依赖。整个工具就一个cm.py文件建议放在~/.local/bin/cm.py或者直接打包成可执行脚本。为什么不用 Click 或 FastAPI 那套因为命令行工具的交互就几个子命令用标准库argparse写起来更直接不会有依赖升级的烦恼。你要给别人的脚本尽量少依赖别人用起来才不会一脸问号。3.2 核心代码状态保存与加载下面这段是我实际在用的核心逻辑做了简化去掉了配色和日志只保留骨架#!/usr/bin/env python3 import argparse import json import os import sqlite3 import shlex from pathlib import Path DB_PATH Path.home() / .context-mode / contexts.db CONTROLLED_VARS [JAVA_HOME, PYTHONPATH, VIRTUAL_ENV, NODE_VERSION, CUSTOM_FLAG] def get_conn(): conn sqlite3.connect(DB_PATH) conn.execute( CREATE TABLE IF NOT EXISTS contexts ( name TEXT PRIMARY KEY, cwd TEXT, env TEXT, created_at TEXT ) ) return conn def save_context(name, cwdNone, envNone): conn get_conn() if cwd is None: cwd os.getcwd() if env is None: env {k: v for k, v in os.environ.items() if k in CONTROLLED_VARS} conn.execute( INSERT OR REPLACE INTO contexts (name, cwd, env, created_at) VALUES (?,?,?,datetime(now)), (name, cwd, json.dumps(env)), ) conn.commit() def load_context(name): conn get_conn() row conn.execute(SELECT cwd, env FROM contexts WHERE name?, (name,)).fetchone() if not row: return None cwd, env_json row return cwd, json.loads(env_json) def enter_cmd(name): # 先保存当前上下文到 default防止丢失 save_context(default) data load_context(name) if data is None: save_context(name) data load_context(name) cwd, env data # 生成 shell 代码交给 eval 执行 lines [] for var in CONTROLLED_VARS: lines.append(funset {var}) for k, v in env.items(): lines.append(fexport {k}{shlex.quote(v)}) lines.append(fcd {shlex.quote(cwd)}) print(; .join(lines))这段代码的核心思想是cm.py本身不直接修改当前 shell 的环境因为一个子进程无法修改父进程的变量。它只是把“要执行的 shell 命令”打印出来然后由你在 bash 函数里用eval执行。这是这种工具最常见的实现套路必须先讲明白。你可以看到enter_cmd先把当前 shell 保存到default接着去加载目标 context。如果目标不存在就先创建它。unset那步是为了把可能残留的旧变量清掉然后按需重新export。shlex.quote用来处理路径和值里的空格很多新手会在这一步踩坑。3.3 接入 Shell让 cm 能直接改当前环境Python 代码打印的是一串 shell 命令所以我们需要在.bashrc或.zshrc里写一个包一层的小函数cm() { if [[ $1 enter ]]; then eval $(python3 ~/.local/bin/cm.py enter $2) elif [[ $1 exit ]]; then eval $(python3 ~/.local/bin/cm.py exit) else python3 ~/.local/bin/cm.py $ fi }这里eval是关键也是风险点。如果cm.py输出的内容里有意外字符eval可能会执行你不想执行的东西所以shlex.quote不能省。另外不要接受任何未做转义的远程数据直接传给cm enter这属于基本的安全习惯。exit子命令的逻辑类似保存当前 context 的状态再切到 default。你可以自己补上exit_cmddef exit_cmd(): name os.getenv(CM_CONTEXT, default) save_context(name) load load_context(default) if load: cwd, env load lines [funset {v} for v in CONTROLLED_VARS] for k, v in env.items(): lines.append(fexport {k}{shlex.quote(v)}) lines.append(fcd {shlex.quote(cwd)}) print(; .join(lines))这个版本算是能用了。你把cm enter project-a执行一次当前 shell 就切到 project-a 的上下文cm exit又回到默认。你每次进入一个context时你的工作目录、相关环境变量都会自动恢复这就是最基础的 context-mode。3.4 让提示符显示当前 context进完环境后最容易遇到的问题就是忘了自己现在在哪个 context。我建议在PS1里加一个标识。以 Bash 为例# .bashrc get_cm_context() { echo ${CM_CONTEXT:-default} } PS1[\u\h \W $(get_cm_context)]\$ 同时在cm.py的enter_cmd里记得打印一行export CM_CONTEXTproject-a让 shell 时刻知道当前模式名。这行代码虽然不起眼但在实际使用中能帮你少犯很多错。4. context-mode 的进阶玩法AI 对话与多环境管理4.1 在 AI 对话中实现上下文模式现在很多 AI 工具所谓的“上下文”其实是把对话窗口里的历史消息一股脑塞给模型。但问题来了如果你在一个对话里既讨论项目A的接口设计又讨论项目B的日志格式AI 很容易把两边信息混在一起回答开始“精分”。这时候context-mode 的思想就能直接套用。我试过一种做法给每个任务建一个独立的上下文文件只保存这个任务相关的消息列表。调用大语言模型 API 时先从文件里读出当前任务的messages再拼接新问题请求结束后把回复追加回文件。这样切换任务时只要改一下上下文文件名即可。你可以只用一个环境变量AI_CONTEXT来标识当前任务ai() { cmd$(python3 ~/tools/ai_cli.py --context ${AI_CONTEXT:-default} $) eval $cmd }ai_cli.py根据AI_CONTEXT去读对应的历史消息再调用模型。模型返回后把新的 user/assistant 消息追加进同一个文件。这样一来project-a-support和project-b-support两个 AI 上下文完全隔离不会因为聊过别的东西而互相影响。你甚至可以随时cm enter project-a后再运行ai当前对话就直接带着项目A的上下文。4.2 用 context-mode 管理多套开发环境除了 AI 对话我在本机维护多套开发环境时也用它。比如项目A需要用 Python 3.8 某个老版本依赖项目B需要用 Python 3.12 最新的库。以前我靠手动切换pyenv global和source venv/bin/activate偶尔忘了切pip 装错地方是常事。接入 context-mode 之后每个 context 的env.sh都会写入类似这样的内容export PYENV_VERSION3.8.20 export VIRTUAL_ENV$HOME/.venvs/project-a export PATH$VIRTUAL_ENV/bin:$PATH进入project-acontext自动切到指定 Python 版本和虚拟环境退出或进入project-b又自动切回来。再配合上一条的命令历史隔离你在哪个项目敲过什么命令都有据可查排查问题的时候省了很大的力气。4.3 和 tmux / IDE 结合context-mode 并不是要取代 tmux 或 IDE 的工作区而是给它们补充“状态层”。我现在的习惯是tmux 负责窗口和面板context-mode 负责每个面板里的环境状态。每个面板可能进入不同的 context互不干扰。IDE 里也有类似概念。比如 VS Code 的“工作区”会保存打开的文件夹、窗口布局JetBrains 家的 IDE 也有 Project 概念。但 IDE 的 workspace 通常不支持跨 shell 的环境变量管理。我试过给 VS Code 写一个简单的任务插件在打开某个工程时自动读取~/.context-mode/project-a/env.sh并在集成终端里 source 一遍。这样代码编辑和终端环境也能统一起来。如果你不想写插件也可以手动在 IDE 的集成终端里执行cm enter project-a效果其实差不多。关键是让自己养成“在同一个任务里先进入 context 再操作”的习惯。5. 常见问题与排查技巧实录5.1 eval 之后环境变量没有生效这是最经常发生的问题。原因通常是 Python 的输出没有通过eval执行或者输出格式带了额外的引号。我建议你先手动跑一次python3 ~/.local/bin/cm.py enter project-a看看输出的 shell 命令对不对。只要输出形如unset JAVA_HOME; unset PYTHONPATH; export JAVA_HOME/...; cd /...;那在cm()函数里用eval应该能生效。如果没生效优先怀疑cm函数名有没有和系统命令冲突或者.bashrc没有重载。用type cm看一下cm到底指向哪里。5.2 切换后旧的命令历史还在我这里说的历史隔离有两个层面。如果你只是希望history命令不显示其他 context 的内容那需要给每个 context 指定独立的HISTFILE。Bash 和 Zsh 都支持运行时切换# 在 context 的 env.sh 里加 export HISTFILE$HOME/.context-mode/project-a/history export HISTSIZE1000 export SAVEHIST1000但注意eval执行时会先unset变量而HISTFILE不一定在CONTROLLED_VARS列表里。你把HISTFILE加进CONTROLLED_VARS就行。另外切换HISTFILE之后当前 shell 的历史不会自动清空我通常直接在函数里执行history -c来清屏再fc -R从新文件读。这步比较脏但能用。5.3 并发切换导致状态丢失如果你在同一个 shell 里同时跑几个cm enter或者开了多个终端窗口指向同一个 context后写会覆盖先写造成状态丢失。这个是文件/数据库存储的固有问题。我现在的策略有两个一是不要多个终端同时写同一个 context二是每次进入 context 时如果远端已经变了先git diff或手动确认再覆盖。如果非要支持并发更稳的方案是用数据库行锁并且把“保存当前”和“加载目标”做成一个事务。但说实话个人场景里“同一个 context 只被一个 shell 占用”是个合理约定不值得为它引入复杂锁。5.4 变量值里带了空格和特殊符号比如PYTHONPATH/home/my user/project这种带空格的路径如果直接export PYTHONPATH/home/my user/project一定会出错。所以一定要用shlex.quote()生成的命令才会变成export PYTHONPATH/home/my user/project。这个不用省省了就是给自己埋雷。5.5 误删了默认配置defaultcontext 承担了太多基础环境万一被覆盖成奇怪的变量会影响全局。建议给meta.json加一个is_default标记并把 default 单独备份一份例如default.env.bak。我曾在一次实验中把 default 的PATH搞没了导致ls都找不到最后还是靠export PATH/usr/bin:/bin救回来的。从那以后每次改 context 代码前我都会先备份整个~/.context-mode。6. 我的一点使用心得context-mode 这个概念本身不复杂但真正把它用顺需要花一两周磨合。我刚开始做时一股脑把所有变量都扔进 context结果切换时动不动就清掉重要变量最后反而更麻烦。后来我学乖了先只挑三五个真正和任务强相关的变量比如PYTHONPATH、VIRTUAL_ENV、CM_CONTEXT跑顺了再逐步增加。而且我越来越觉得context-mode 最大的价值不是“自动切换环境”而是“主动定义边界”。它逼着你把每天做的事划分成一个个有名字、有状态的模块而不是靠脑子硬记。这种思维在很多工具里都通用比如你在 IDE 里给不同项目建窗口在浏览器里按工作建浏览器配置文件本质都是 context-mode。最后分享一个小技巧把cm list的结果打印成一棵缩进树并用颜色区分默认层、项目层和任务层。这样你每隔几天回顾一次能很清楚地看到自己最近在哪些任务之间跳来跳去。如果发现切换频率特别高的两个 context往往说明它们应该合并或者你需要重新划分任务边界。这个观察角度是普通 tab 切换永远给不了你的。
企业数字化 ERP 产品动态
相关推荐
共享充电宝技术方案对比:外包开发与SaaS的实战分析 1. 项目背景:共享充电宝行业的两种技术路线之争 共享充电宝行业近年来经历了从野蛮生长到精细化运营的转变。在这个发展过程中,技术实现方案逐渐分化为两种典型路径:一种是采用外包团队定制开发(常见报价在2万元左右)&… · 2026/11/9 15:41:47
极值点、驻点与鞍点:导数为零后的判定流程 "极值点、驻点"这四个字,我在不同场合被问过不下几十次。学生问的是考试里怎么判、怎么列表、怎么写结论;做算法的同事问的是损失函数为什么卡在某个点不动了、明明梯度为零却还在往上飘;做工程优化的朋友问的是参数扫到某个值附近… · 2026/11/6 0:33:42
安卓开发工程师职业发展路径与核心技术解析 1. 安卓开发工程师职业全景解析 安卓开发工程师作为移动互联网时代的关键技术岗位,其职业发展路径呈现出明显的金字塔结构。从初级工程师到架构师,平均需要5-8年的技术沉淀。根据2023年行业调研数据显示,一线城市中级安卓开发的平均年薪已达2… · 2026/11/3 3:51:14
特种灯灯工是什么郑州报考避坑指南 特种灯灯工是什么郑州报考避坑指南 之前考的证在外省能不能转过来?别急,先搞清楚特种灯灯工到底是个啥。特种灯灯工在大家眼里可能是个陌生工种,但实际上,它属于特种作业范畴,主要负责各种照明设备的安装、维护和检修,特别是在建筑工地、电力设施、工业… · 2026/11/9 15:41:41
即墨电工证培训哪家好网上查询复审流程全解析 即墨电工证培训哪家好网上查询复审流程全解析 证书过期了不知道怎么复审延期,这事儿别慌!很多人都遇到过这种情况,尤其是电工证这类特种作业操作证,一旦到期不及时处理,不仅影响工作,还可能面临罚款甚至被暂停上岗资格。很多人第一反应是“网上查询”,… · 2026/11/9 15:41:41
高压电工证三线接线全流程办理指南 低压电工证三线接线怎么考?内部消息告诉你报名门槛低 你是不是也觉得 学历不高怕报不上名 ?其实现在考低压电工证已经不像以前那么难了, 内部消息… · 2026/11/9 15:41:41
低压电工证新老版本怎么考?2026河南最新政策来了 低压电工证新老版本怎么考?2026河南最新政策来了 实操考试心里没底怕挂科,你不是一个人。2026年河南低压电工证政策刚刚更新,很多人对新老版本之间的差异还不太清楚,导致报考流程走错、资料准备不全,甚至考试失利。本文就来帮你理清楚低压电工证… · 2026/11/9 15:41:41
即墨电工证培训哪家好怎么报考多少钱 即墨电工证培训哪家好怎么报考多少钱 你学历不高怕报不上名?别担心,我们来帮你搞清楚。现在市面上有很多培训机构打着“包过”“快速拿证”的旗号,但真正靠谱的少之又少。特别是像【即墨电工证培训哪家好】这样的关键词,大家搜来搜去,还是想找个靠谱的、… · 2026/11/9 15:40:41
电工证丢失还能补吗?千万别踩坑,丢了证等于失业 电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。… · 2026/11/9 2:05:04
电力电缆作业证直播报名入口与办理流程良心建议 电力电缆作业证直播报名入口与办理流程良心建议 你是不是也担心学历不高报不了名?别急,今天就给你讲讲 电力电缆作业证直播 的报名流程和那些你必须知道的干货, 良心建议 在这里,别错过。 电力电缆作业证直播报名需要什么条件?… · 2026/11/9 3:11:26
英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 怕考不过白交培训费?英德电工证报考费多少钱,你真的了解吗?现在市面上培训机构五花八门,价格参差不齐,很多人一不小心就花了冤枉钱,结果还考不过。别急,今天就来给你说清楚英德电工证的… · 2026/11/9 5:24:17
电工证不需要考复审延期怎么办理 通过率揭秘 电工证不需要考复审延期怎么办理 通过率揭秘 不知道去哪报名怕被中介坑?电工证不需要考复审延期怎么办理?最近不少学员都在问这个问题,尤其是刚拿到证的新手,对复审流程一知半解,生怕被培训机构套路。别担心,今天咱们就来聊聊电工证复审的真相,尤其是… · 2026/11/9 0:00:54
砀山哪里考电工证的多 电工证报考别踩坑 郑州报考避坑指南 砀山哪里考电工证的多 电工证报考别踩坑 郑州报考避坑指南 工地太忙根本没时间复习考试,这几乎是所有一线施工人员的共同心声。尤其是像电工这样的特种作业,操作证不仅关系到能不能上工,还直接关系到工资高低和职业发展。可偏偏,很多人连怎么报名、去哪… · 2026/11/9 0:00:54
南方电网电工作业含金量高吗?应届生怎么考怎么干? 南方电网电工作业含金量高吗?应届生怎么考怎么干? 工地太忙根本没时间复习考试,这不是个别现象,而是很多刚毕业的工程类学生面临的现实。南方电网电工作业的证书,听起来门槛不低,但 含金量… · 2026/11/9 0:00:54
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/9 11:23:35
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/9 11:23:58
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/9 11:25:08