[{"content":"","date":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories"},{"content":"","date":null,"permalink":"/tags/go/","section":"标签","summary":"","title":"Go"},{"content":"一、为什么又要造轮子 #说到内网穿透，frp 是绕不开的名字——功能全、生态好、star 数万。但对我而言，它有几个始终让我不太舒服的点：\n第一，太重了。 frp 的二进制加上配置文件、权限体系、插件系统，做一个简单的端口映射显得杀鸡用牛刀。我很多时候只是想把本地的 8080 端口临时暴露到公网上，让同事看一眼我正在开发的东西，不需要 dashboard、不需要加密、不需要负载均衡。\n第二，看不懂。 这不是贬义——frp 是一个成熟的生产级项目，代码量和复杂度自然高。但\u0026quot;看不懂\u0026quot;意味着出了问题只能去翻 issue、等别人修。对于工具类项目，我更希望自己能从头到尾读懂每一行代码。\n第三，依赖多。 frp 引入了相当多的第三方库，升级、维护、安全审计都有成本。\n所以 gopm 的设计目标从一开始就明确了：\n纯 Go 标准库，零外部依赖，单二进制，一个文件搞定。\n这不是要替代 frp，而是在另一个极端上做一个选择——用最少的代码做最核心的事。\n二、gopm 是什么 #gopm（Go Port Mapping）是一个通过反向 TCP 隧道实现内网穿透的工具。服务端和客户端共用同一个二进制文件，通过 -mode 参数区分角色。\n一句话概括它的工作方式：\n内网服务 ←→ 客户端 ←→ 公网服务器 ←→ 外部访客 你在公网服务器上跑服务端，在内网机器上跑客户端，告诉它把本地的哪个端口映射到公网的哪个端口。然后任何人访问公网的那个端口，流量就会被转发到你的内网服务上。\n就这么简单。\n三、核心设计 #3.1 双连接模型 #gopm 最重要的架构决策是控制连接与数据连接分离：\n控制连接：客户端启动后与服务端建立一个长连接，维持整个生命周期。心跳包（ping/pong）走这条连接，新访客到达的通知也走这条连接。 数据连接：每当有外部访客访问映射端口，服务端通知客户端，客户端新建一条 TCP 连接到服务端，建立数据隧道，双向透传流量。 为什么不让一条连接既传控制消息又传数据？因为 TCP 是字节流，控制消息是 JSON 文本，而数据是原始二进制——混在一起就需要做协议分帧，复杂度立马上来。分开之后，控制连接只走 JSON 行协议，数据连接 join 握手后直接变成 raw TCP 透传，干净利落。\n访客 ──→ 服务器:映射端口 ──→ 服务器通知客户端 ──→ 客户端建数据连接 ──→ 本地服务 3.2 协议极简 #控制连接上的消息是 \\n 分隔的 JSON 行，只有几种类型：\n消息类型 方向 用途 register 客户端→服务端 注册端口映射 register_ok 服务端→客户端 注册成功确认 ping / pong 双向 心跳保活 new_conn 服务端→客户端 通知有新访客 join 客户端→服务端 数据连接加入隧道 join_ok 服务端→客户端 隧道建立完成 握手完成后，数据连接上不再有任何 JSON——纯 TCP 双向透传，零开销。\n消息大小限制为 4 KiB，防止恶意客户端发送超大消息耗尽内存。\n3.3 心跳与超时回收 #客户端每 15 秒发送一次 ping，服务端回复 pong。如果服务端 45 秒没有收到任何消息（包括心跳），就判定客户端已失联，自动回收映射资源、关闭监听端口。\n这个机制解决了一个很实际的问题：客户端网络断开但没有正常关闭连接（比如笔记本合盖、WiFi 断了），服务端需要能自动发现并清理，否则映射端口会一直被占用。\n3.4 断线重连 #-retry 参数启用后，客户端在连接断开时自动重连，重连间隔按退避策略递增：\n1秒 → 2秒 → 5秒 → 10秒 → 10秒 … 重连成功后自动重新发送注册请求，恢复映射。对于网络不稳定的环境（比如移动网络、校园网），这个功能几乎是必需的。\n四、功能一览 #服务端参数 # 1 ./gopm -mode server -port \u0026lt;控制端口\u0026gt; [-token \u0026lt;令牌\u0026gt;] [-timeout \u0026lt;秒\u0026gt;] [-verbose] 参数 说明 -port 控制端口，接收客户端连接 -token 可选鉴权令牌，设置后客户端必须提供相同值 -timeout 自动关闭时长（秒），0 为永久运行 -verbose 输出详细日志 客户端参数 # 1 2 ./gopm -mode client -server \u0026lt;地址\u0026gt; -local \u0026lt;本地地址\u0026gt; -map \u0026lt;映射端口\u0026gt; \\ [-token \u0026lt;令牌\u0026gt;] [-name \u0026lt;名称\u0026gt;] [-retry] [-timeout \u0026lt;秒\u0026gt;] [-verbose] 参数 说明 -server 服务端控制地址，如 1.2.3.4:9000 -local 本地服务地址，支持 8080 或 127.0.0.1:8080 -map 服务端暴露的映射端口 -token 鉴权令牌，需与服务端一致 -name 客户端标识名称，方便在日志中区分 -retry 启用断线自动重连 -timeout 自动关闭时长（秒） -verbose 详细日志 五、使用场景 #场景一：临时展示本地 Web 服务 #开发了一个前端项目，想给同事看看效果：\n1 2 3 4 5 # 公网服务器 ./gopm -mode server -port 9000 # 你的电脑 ./gopm -mode client -server YOUR_SERVER:9000 -local 3000 -map 8080 -retry 同事访问 http://YOUR_SERVER:8080 即可看到你本地的 localhost:3000。\n场景二：带鉴权的正式使用 #给服务端加个 Token，防止任何人随意注册映射：\n1 2 3 4 5 # 服务端 ./gopm -mode server -port 9000 -token my_secret # 客户端 ./gopm -mode client -server YOUR_SERVER:9000 -local 8080 -map 8080 -token my_secret -retry Token 不匹配的客户端会收到 unauthorized 错误。\n场景三：映射内网数据库 #需要远程连接内网的 MySQL：\n1 ./gopm -mode client -server YOUR_SERVER:9000 -local 192.168.1.50:3306 -map 13306 -token db_tunnel 外部通过 YOUR_SERVER:13306 即可连接内网数据库。\n场景四：多客户端并行 #一个服务端可以同时服务多个客户端，每个映射不同端口：\n1 2 3 4 5 # 客户端 A：Web 服务 ./gopm -mode client -server YOUR_SERVER:9000 -local 3000 -map 8080 # 客户端 B：API 服务 ./gopm -mode client -server YOUR_SERVER:9000 -local 9090 -map 9090 端口冲突会被自动检测并拒绝——同一映射端口只能被一个客户端占用。\n场景五：定时自动关闭 #临时调试，不想忘了关进程？用 -timeout 设个倒计时：\n1 2 3 4 5 # 服务端，1 小时后自动关闭 ./gopm -mode server -port 9000 -timeout 3600 # 客户端，30 分钟后自动关闭 ./gopm -mode client -server YOUR_SERVER:9000 -local 8080 -map 8080 -timeout 1800 超时后自动触发优雅关闭，打印日志并退出。\n六、安全设计 # 特性 说明 Token 鉴权 服务端设置 -token 后，注册和数据连接均需携带相同 Token 消息大小限制 单条消息不超过 4 KiB，防止内存耗尽攻击 心跳超时回收 45 秒无心跳自动移除映射，防止静默断连占用端口 并发写保护 控制连接 Writer 通过互斥锁保护，防止数据损坏 优雅关闭 SIGINT/SIGTERM 触发资源清理，不丢连接 这些不是事后补丁，而是写第一版代码时就考虑进去的。安全不是功能，是习惯。\n七、造轮子的意义 #有人可能会问：frp 能用，为什么要自己写？\n我的回答是：造轮子的意义不在于轮子本身，而在于你理解了轮子的每一根辐条。\n当你自己实现了心跳保活、断线重连、端口映射、并发安全这些机制之后，你对网络编程的理解就不再是\u0026quot;知道有这些概念\u0026quot;，而是\u0026quot;知道为什么这样设计、不这样会出什么问题\u0026quot;。\ngopm 全部代码不到 1000 行，纯标准库，从零读完一遍也就一个下午。如果它对你有用，直接拿去用；如果你正在学网络编程，它的代码也许比这篇文章更有价值。\nGitHub: https://github.com/jacksalad/gopm\nLicense: MIT\n","date":"May 3, 2026","permalink":"/posts/gopm-intro/","section":"文章列表","summary":"用纯 Go 标准库从零实现内网穿透——不依赖 frp，不依赖任何第三方库，一个二进制文件搞定端口映射。这篇文聊聊为什么要造这个轮子，以及它是怎么工作的。","title":"gopm：一个极简的内网穿透工具"},{"content":"","date":null,"permalink":"/tags/","section":"标签","summary":"","title":"标签"},{"content":"","date":null,"permalink":"/tags/%E5%B7%A5%E5%85%B7/","section":"标签","summary":"","title":"工具"},{"content":"","date":null,"permalink":"/","section":"欢迎来到我的博客","summary":"","title":"欢迎来到我的博客"},{"content":"","date":null,"permalink":"/categories/%E6%8A%80%E6%9C%AF%E5%B7%A5%E5%85%B7/","section":"Categories","summary":"","title":"技术工具"},{"content":"","date":null,"permalink":"/tags/%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/","section":"标签","summary":"","title":"内网穿透"},{"content":"","date":null,"permalink":"/tags/%E7%BD%91%E7%BB%9C/","section":"标签","summary":"","title":"网络"},{"content":"","date":null,"permalink":"/posts/","section":"文章列表","summary":"","title":"文章列表"},{"content":"1793年，英国派遣由马夏尔尼率领的使团访问清朝，试图与中国建立更稳定的外交与贸易关系。这次会面后来被不断简化为一个问题：「马夏尔尼到底跪没跪？」然而，真正值得反思的，并不在于一位外国使节是否完成了某种礼仪，而在于清朝如何理解这个正在迅速变化的世界。\n礼：秩序的骨架 #在清代政治文化中，「礼」并非细枝末节，而是国家秩序的核心象征。三跪九叩不仅是对皇帝个人的尊敬，更是对「天朝—藩属」天下体系的确认。正因如此，清廷在接待马夏尔尼使团时，高度关注其是否遵守既定礼仪。这种重视在当时并不反常——它是一种制度化、文化化的本能反应。\n问题在于，这套以礼仪和等级为核心的天下观，正面临一个全新的挑战。\n认知错位：两套逻辑的碰撞 #马夏尔尼并非传统意义上的「贡使」。他所代表的英国，已经完成工业革命的起飞，正在全球扩展贸易与海权。英国关注的不是象征性的朝贡地位，而是制度化通商、对等外交和长期利益安排。\n清廷却将这次来访纳入熟悉的框架加以理解：远方国家来华，行礼、觐见、受赏，然后各归其位。在这种理解中，最重要的问题自然是「礼是否合乎规范」，而不是对方背后所代表的技术、经济和制度变革。\n因此，马夏尔尼事件并非简单的外交失败，而是一场深刻的认知错位：\n维度 清朝的关切 英国的关切 核心诉求 礼仪规范、秩序稳定 制度通商、对等外交 对使团的定位 藩属贡使 平等主权国家代表 关注焦点 形式与象征 实质与利益 世界观基础 天下体系、道德秩序 工业资本、海权扩张 清朝关注的是秩序形式的稳定，英国关注的是世界运行方式的改变。\n「天朝物产丰盈」：自信，还是盲目？ #乾隆皇帝所说的「天朝物产丰盈，无所不有」，并非虚妄自大。这是农业文明长期积累下的真实自信——广袤的疆域、庞大的人口、自给自足的经济体系，确实给了清朝「无所不有」的底气。\n但这种自信未能意识到，世界权力的基础正在发生根本性转移：从土地、人口与道德秩序，转向工业、技术与资本。\n从后来的历史看，马夏尔尼是否跪下，对中英关系乃至中国命运的影响都十分有限。真正重要的是，清朝未能意识到这次接触所释放的时代信号。清政府并非拒绝一切交流，但它只能在不触动既有天下秩序的前提下理解外部世界。一旦对方提出制度性改变的要求，便被视为对根本秩序的威胁。\n错过的不是机会，是窗口 #需要指出的是，这并不意味着清朝只要在马夏尔尼事件中「让步」，就能顺利实现工业化。科举制度、财政结构、官僚体系等深层问题，决定了工业化转型本就异常艰难。\n但可以说，清朝错过的并不是一个确定成功的机会，而是一个更早认识世界变化、以更低代价调整自身的时间窗口。\n两者之间的区别至关重要：机会意味着「做了就能成」，窗口意味着「做了才能开始理解」。马夏尔尼使团提供的不是一张工业化路线图，而是一面镜子——如果清朝愿意照一照，至少能更早地看清自己的处境。\n规则已经改变 #今天反复纠结「马夏尔尼跪没跪」，本身就带有某种历史讽刺意味。它恰恰重复了当年的错误：把注意力放在形式与象征上，而非运行逻辑的变化。\n真正值得追问的，不是一次礼仪的得失，而是一个文明在自身解释框架开始失效时，是否有能力意识到规则已经改变。\n马夏尔尼事件提醒我们：当世界运行逻辑发生变化时，若仍执着于形式与象征，往往会在不知不觉中错过时代。\n","date":"May 1, 2026","permalink":"/posts/maccartney-misjudgment/","section":"文章列表","summary":"1793年马夏尔尼使团访华，后来被简化为「跪没跪」的礼仪之争。但真正值得追问的，不是一次跪拜的得失，而是一个文明在自身解释框架开始失效时，能否意识到规则已经改变。","title":"跪与不跪之外：马夏尔尼使团与清朝的时代误判"},{"content":"","date":null,"permalink":"/tags/%E5%8E%86%E5%8F%B2/","section":"标签","summary":"","title":"历史"},{"content":"","date":null,"permalink":"/categories/%E5%8E%86%E5%8F%B2%E9%9A%8F%E7%AC%94/","section":"Categories","summary":"","title":"历史随笔"},{"content":"","date":null,"permalink":"/tags/%E6%B8%85%E6%9C%9D/","section":"标签","summary":"","title":"清朝"},{"content":"","date":null,"permalink":"/tags/%E6%80%9D%E7%BB%B4/","section":"标签","summary":"","title":"思维"},{"content":"","date":null,"permalink":"/tags/%E5%A4%96%E4%BA%A4/","section":"标签","summary":"","title":"外交"},{"content":"","date":null,"permalink":"/tags/linux/","section":"标签","summary":"","title":"Linux"},{"content":"","date":null,"permalink":"/tags/lsp/","section":"标签","summary":"","title":"LSP"},{"content":"","date":null,"permalink":"/tags/neovim/","section":"标签","summary":"","title":"Neovim"},{"content":"Neovim 0.12.0 于 2026 年 3 月 29 日正式发布，代号 \u0026ldquo;The year of Nvim OOTB\u0026rdquo;——开箱即用的 Neovim 之年。这个版本的核心叙事不再只是\u0026quot;新功能列表\u0026quot;，而是：更多编辑器能力现在不需要插件栈就能获得。\n本文将从特性解读出发，带你一步步编写适配 0.12 的配置文件。\n一、重量级新特性 #1.1 内置插件管理器 vim.pack #这是 0.12 最具里程碑意义的新增。Neovim 终于有了自己的插件管理器，不再必须依赖 Packer、Lazy 等第三方方案。\n1 2 3 4 5 6 7 8 9 10 11 12 -- init.lua 或 lua/config/pack.lua vim.pack.add({ -- 直接用 GitHub URL \u0026#39;https://github.com/sainnhe/gruvbox-material\u0026#39;, \u0026#39;https://github.com/nvim-treesitter/nvim-treesitter\u0026#39;, -- 指定版本锁定 { src = \u0026#39;https://github.com/neovim/nvim-lspconfig\u0026#39;, version = \u0026#39;v2.0.0\u0026#39; }, -- 自定义插件名（避免长 URL 重复引用） { src = \u0026#39;https://github.com/user/long-repo-name\u0026#39;, name = \u0026#39;my-plugin\u0026#39; }, }) 关键细节：\n方面 说明 存储位置 site/pack/core/opt/（data path 下） 锁文件 ~/.config/nvim/nvim-pack-lock.json，建议纳入 git 更新 vim.pack.update() 打开确认 buffer 审阅变更 删除 vim.pack.del({'old-plugin'}) 限制 基于 Git；不是懒加载框架；不会自动校验已下载插件的版本一致性 更新操作变体：\n1 2 3 4 vim.pack.update({ \u0026#39;nvim-treesitter\u0026#39; }) -- 只更新指定插件 vim.pack.update(nil, { force = true }) -- 强制更新，跳过确认 vim.pack.update(nil, { offline = true }) -- 离线模式 vim.pack.update(nil, { target = \u0026#39;lockfile\u0026#39; }) -- 锁定到 lockfile 版本 安装后钩子通过 PackChanged 事件实现：\n1 2 3 4 5 6 7 vim.api.nvim_create_autocmd(\u0026#39;PackChanged\u0026#39;, { callback = function(ev) if ev.data.spec.name == \u0026#39;nvim-treesitter\u0026#39; then vim.system({ \u0026#39;make\u0026#39; }, { cwd = ev.data.path }) end end, }) 1.2 内置插入模式自动补全 #0.12 新增 'autocomplete' 选项，开启后无需 nvim-cmp 等插件即可获得基本补全：\n1 2 3 4 vim.o.autocomplete = true vim.o.pumborder = \u0026#39;rounded\u0026#39; -- 补全菜单边框样式 vim.o.pummaxwidth = 40 -- 补全菜单最大宽度 vim.o.completeopt = \u0026#39;menu,menuone,noselect,nearest\u0026#39; 'complete' 选项新增：\nF{func} — 用指定 Lua 函数补全 F — 用 'completefunc' 补全 o — 用 'omnifunc' 补全 {flag}^\u0026lt;limit\u0026gt; — 限制每个源的匹配数，如 .^5,t^3,w 'completeopt' 新增 nearest 标志，按距离光标远近排序。\n1.3 LSP 支持大幅扩展 #0.12 让内置 LSP 更加\u0026quot;开箱即用\u0026quot;：\n推荐配置模式（不再依赖 nvim-lspconfig）：\n1 2 3 4 5 6 vim.lsp.config[\u0026#39;lua_ls\u0026#39;] = { cmd = { \u0026#39;lua-language-server\u0026#39; }, filetypes = { \u0026#39;lua\u0026#39; }, root_markers = { { \u0026#39;.luarc.json\u0026#39;, \u0026#39;.luarc.jsonc\u0026#39; }, \u0026#39;.git\u0026#39; }, } vim.lsp.enable(\u0026#39;lua_ls\u0026#39;) 新增 LSP 能力：\n能力 说明 selectionRange v_an 向外选、v_in 向内选（无 Treesitter 时回退到此） inlineCompletion 行内补全 documentLink gx 打开光标处的文档链接 semanticTokens/range 仅请求可视区域 token，性能优化 diagnostic pull 诊断（含增量 id） codeLens Code Lens 以虚拟行显示 内置默认映射：\n按键 功能 gra Code Actions gri Implementations grn Rename grr References grt Type Definition gO Document Symbols Ctrl-S（Insert） Signature Help 交互式管理：:lsp 命令；健康检查：:checkhealth vim.lsp\n1.4 实验性 UI2 重设计 #0.12 引入了核心消息和命令行 UI 的重设计：\n1 require(\u0026#39;vim._core.ui2\u0026#39;).enable() 效果：\n✅ 消除大量 \u0026ldquo;Press ENTER\u0026rdquo; 打断 ✅ 命令行实时语法高亮 ✅ Pager 变为正式 buffer + window ✅ 消除 W10 等警告延迟 目前标记为实验性，建议先体验再决定是否日常启用。\n二、内置工具与新命令 # 命令 说明 :Undotree 内置可视化撤销树（需 :packadd nvim.undotree） :DiffTool dir1 dir2 内置目录/文件对比 :restart 重启 Nvim 并重连所有 UI :connect addr 动态连接到 Neovim 服务器 :uniq 去重当前 buffer 行 :iput 像 :put 但自动调整缩进 :retab -indentonly 仅改首行缩进空白 :wall ++p 写所有 buffer + 自动创建缺失父目录 :help! 智能猜测光标处 help tag 三、性能提升与 Lua API #3.1 性能 # vim.glob.to_lpeg() 新 LPeg 实现（Peglob），复杂模式约 50% 加速 i_CTRL-R 插入寄存器提速 10x（改为字面插入） :packadd 不再清空 Lua package path cache，改善启动时间 3.2 新 Lua API # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 -- HTTP 请求（内置！） local res = vim.net.request(\u0026#39;https://api.github.com/repos/neovim/neovim\u0026#39;) print(res.body) -- 文件扩展名 vim.fs.ext(\u0026#39;init.lua\u0026#39;) -- =\u0026gt; \u0026#39;lua\u0026#39; vim.fs.ext(\u0026#39;archive.tar.gz\u0026#39;) -- =\u0026gt; \u0026#39;gz\u0026#39; -- 去重 vim.list.unique({ 1, 2, 2, 3, 1 }) -- =\u0026gt; { 1, 2, 3 } -- 二分查找 vim.list.bisect({ 10, 20, 30, 40 }, 25) -- =\u0026gt; 2 -- 实验性 Position/Range local pos = vim.pos(0, 5) -- 行 0，列 5 local rng = vim.range(pos, vim.pos(0, 10)) 迭代器增强：\n1 2 3 4 5 6 7 8 -- take/skip 支持谓词 vim.iter({ 1, 2, 3, 4, 5 }):take(function(x) return x \u0026lt; 4 end):totable() -- {1,2,3} -- peek（不消费） vim.iter(range):peek() -- unique vim.iter({ 1, 1, 2, 3 }):unique():totable() -- {1,2,3} 四、终端与 TUI 改进 # 支持同步输出（DEC private mode 2026），减少撕裂 支持 CSI 3 J 清除滚动回溯 nvim_open_term() 可在非空 buffer 上调用（内容通过 PTY 显示） 挂起进程显示 [Process suspended]，按键恢复 退出显示虚拟文本 + 状态栏退出码 TUI 渲染 SGR dim/faint、blink、conceal、overline OSC 9;4 原生进度条 五、破坏性变更（升级必看） #这是升级最需要注意的部分：\n5.1 API 重命名 # 旧 新 vim.diff vim.text.diff vim.lsp.semantic_tokens.start/stop vim.lsp.semantic_tokens.enable 5.2 诊断 Signs #sign-define 方式彻底废弃，必须迁移到 vim.diagnostic.config()：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 -- ❌ 旧方式（0.12 中无效） vim.fn.sign_define(\u0026#39;DiagnosticSignError\u0026#39;, { text = \u0026#39;E\u0026#39;, texthl = \u0026#39;DiagnosticError\u0026#39; }) -- ✅ 新方式 local sev = vim.diagnostic.severity vim.diagnostic.config({ severity_sort = true, signs = { text = { [sev.ERROR] = \u0026#39;E\u0026#39;, [sev.WARN] = \u0026#39;W\u0026#39;, [sev.INFO] = \u0026#39;I\u0026#39;, [sev.HINT] = \u0026#39;H\u0026#39;, }, }, }) vim.diagnostic.disable() 和 is_disabled() 已移除；旧签名 vim.diagnostic.enable() 不再支持。\n5.3 行为变更 # i_CTRL-R 现在字面插入寄存器内容（旧行可用 \u0026lt;C-R\u0026gt;=@x） 'shelltemp' 默认改为 false vim.treesitter.get_parser() 不再抛异常，返回 nil LSP JSON null → vim.NIL（不再是 nil） tohtml 不再默认加载 Python 3.7/3.8 支持移除 六、完整配置实战 #下面给出一个适配 0.12 的最小但实用的配置结构，让你开箱即用。\n6.1 目录结构 #~/.config/nvim/ ├── init.lua ├── nvim-pack-lock.json ← vim.pack 自动生成 └── lua/ └── config/ ├── init.lua ← 入口 ├── options.lua ← 编辑器选项 ├── keymaps.lua ← 按键映射 ├── diagnostics.lua ← 诊断配置 ├── lsp.lua ← LSP 配置 ├── pack.lua ← 插件管理 └── ui2.lua ← UI2（可选） 6.2 init.lua # 1 require(\u0026#39;config\u0026#39;) 6.3 lua/config/init.lua # 1 2 3 4 5 6 require(\u0026#39;config.options\u0026#39;) require(\u0026#39;config.pack\u0026#39;) -- 插件要先加载 require(\u0026#39;config.keymaps\u0026#39;) require(\u0026#39;config.diagnostics\u0026#39;) require(\u0026#39;config.lsp\u0026#39;) -- require(\u0026#39;config.ui2\u0026#39;) -- 实验性，按需启用 6.4 lua/config/options.lua # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 -- 基本选项 vim.o.number = true vim.o.relativenumber = true vim.o.tabstop = 4 vim.o.shiftwidth = 4 vim.o.expandtab = true vim.o.smartindent = true vim.o.wrap = false vim.o.swapfile = false vim.o.undofile = true vim.o.ignorecase = true vim.o.smartcase = true vim.o.termguicolors = true vim.o.signcolumn = \u0026#39;yes\u0026#39; vim.o.cursorline = true -- 0.12 新选项：内置自动补全 vim.o.autocomplete = true vim.o.pumborder = \u0026#39;rounded\u0026#39; vim.o.pummaxwidth = 40 vim.o.completeopt = \u0026#39;menu,menuone,noselect,nearest\u0026#39; -- 搜索 vim.o.hlsearch = true vim.o.incsearch = true -- 默认 diffopt 已含 indent-heuristic + inline:char，可追加 vim.o.diffopt = vim.o.diffopt .. \u0026#39;,inline:word\u0026#39; -- shada 排除临时目录（0.12 新默认行为，此处显式声明） vim.o.shada = vim.o.shada .. \u0026#39;,/tmp/,/private/\u0026#39; 6.5 lua/config/pack.lua # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 vim.pack.add({ -- 主题 \u0026#39;https://github.com/sainnhe/gruvbox-material\u0026#39;, -- Treesitter \u0026#39;https://github.com/nvim-treesitter/nvim-treesitter\u0026#39;, -- 如仍需 nvim-lspconfig（补充内置不足的语言服务器） { src = \u0026#39;https://github.com/neovim/nvim-lspconfig\u0026#39;, version = \u0026#39;v2.0.0\u0026#39; }, }) -- 安装后钩子：自动编译 Treesitter vim.api.nvim_create_autocmd(\u0026#39;PackChanged\u0026#39;, { callback = function(ev) if ev.data.spec.name == \u0026#39;nvim-treesitter\u0026#39; then vim.system({ \u0026#39;make\u0026#39; }, { cwd = ev.data.path }) end end, }) 6.6 lua/config/keymaps.lua # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 -- 空格为 Leader vim.g.mapleader = \u0026#39; \u0026#39; -- 0.12 已内置 LSP 映射（gra/gri/grn/grr/grt/gO/Ctrl-S） -- 此处补充自定义映射 -- 窗口 vim.keymap.set(\u0026#39;n\u0026#39;, \u0026#39;\u0026lt;leader\u0026gt;w\u0026#39;, \u0026#39;\u0026lt;C-w\u0026gt;\u0026#39;, { desc = \u0026#39;Window\u0026#39; }) vim.keymap.set(\u0026#39;n\u0026#39;, \u0026#39;\u0026lt;leader\u0026gt;wc\u0026#39;, \u0026#39;\u0026lt;C-w\u0026gt;c\u0026#39;, { desc = \u0026#39;Close window\u0026#39; }) -- Buffer vim.keymap.set(\u0026#39;n\u0026#39;, \u0026#39;\u0026lt;leader\u0026gt;bd\u0026#39;, \u0026#39;:bdelete\u0026lt;CR\u0026gt;\u0026#39;, { desc = \u0026#39;Delete buffer\u0026#39; }) -- 诊断浮动窗口 vim.keymap.set(\u0026#39;n\u0026#39;, \u0026#39;\u0026lt;leader\u0026gt;df\u0026#39;, vim.diagnostic.open_float, { desc = \u0026#39;Diagnostic float\u0026#39; }) vim.keymap.set(\u0026#39;n\u0026#39;, \u0026#39;\u0026lt;leader\u0026gt;dl\u0026#39;, vim.diagnostic.setloclist, { desc = \u0026#39;Diagnostic loclist\u0026#39; }) -- 0.12 新命令快捷键 vim.keymap.set(\u0026#39;n\u0026#39;, \u0026#39;\u0026lt;leader\u0026gt;ur\u0026#39;, \u0026#39;:Undotree\u0026lt;CR\u0026gt;\u0026#39;, { desc = \u0026#39;Undo tree\u0026#39; }) vim.keymap.set(\u0026#39;n\u0026#39;, \u0026#39;\u0026lt;leader\u0026gt;R\u0026#39;, \u0026#39;:restart\u0026lt;CR\u0026gt;\u0026#39;, { desc = \u0026#39;Restart Nvim\u0026#39; }) -- Treesitter 结构选择（0.12 新增） vim.keymap.set(\u0026#39;v\u0026#39;, \u0026#39;an\u0026#39;, nil, { desc = \u0026#39;Select outward (TS/LSP)\u0026#39; }) -- 内置 vim.keymap.set(\u0026#39;v\u0026#39;, \u0026#39;in\u0026#39;, nil, { desc = \u0026#39;Select inward (TS/LSP)\u0026#39; }) -- 内置 6.7 lua/config/diagnostics.lua # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 local sev = vim.diagnostic.severity vim.diagnostic.config({ severity_sort = true, update_in_insert = false, float = { border = \u0026#39;rounded\u0026#39;, source = true, }, signs = { text = { [sev.ERROR] = \u0026#39;✘\u0026#39;, [sev.WARN] = \u0026#39;▲\u0026#39;, [sev.INFO] = \u0026#39;●\u0026#39;, [sev.HINT] = \u0026#39;○\u0026#39;, }, }, -- 虚拟文本只显示最高级别 virtual_lines = { current_line = true }, underline = true, }) -- 诊断状态可用于自定义 statusline -- vim.diagnostic.status() 返回统计表 -- vim.lsp.status() 返回 LSP 进度 6.8 lua/config/lsp.lua # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 -- Python vim.lsp.config[\u0026#39;pyright\u0026#39;] = { cmd = { \u0026#39;pyright-langserver\u0026#39;, \u0026#39;--stdio\u0026#39; }, filetypes = { \u0026#39;python\u0026#39; }, root_markers = { { \u0026#39;pyproject.toml\u0026#39;, \u0026#39;setup.py\u0026#39; }, \u0026#39;.git\u0026#39; }, } vim.lsp.enable(\u0026#39;pyright\u0026#39;) -- Go vim.lsp.config[\u0026#39;gopls\u0026#39;] = { cmd = { \u0026#39;gopls\u0026#39; }, filetypes = { \u0026#39;go\u0026#39;, \u0026#39;gomod\u0026#39;, \u0026#39;gowork\u0026#39; }, root_markers = { \u0026#39;go.mod\u0026#39;, \u0026#39;.git\u0026#39; }, } vim.lsp.enable(\u0026#39;gopls\u0026#39;) -- Lua vim.lsp.config[\u0026#39;lua_ls\u0026#39;] = { cmd = { \u0026#39;lua-language-server\u0026#39; }, filetypes = { \u0026#39;lua\u0026#39; }, root_markers = { { \u0026#39;.luarc.json\u0026#39;, \u0026#39;.luarc.jsonc\u0026#39; }, \u0026#39;.git\u0026#39; }, settings = { Lua = { runtime = { version = \u0026#39;LuaJIT\u0026#39; }, diagnostics = { globals = { \u0026#39;vim\u0026#39; } }, workspace = { library = { vim.env.VIMRUNTIME } }, }, }, } vim.lsp.enable(\u0026#39;lua_ls\u0026#39;) -- 健康检查 -- :checkhealth vim.lsp 6.9 lua/config/ui2.lua（可选，实验性） # 1 2 3 require(\u0026#39;vim._core.ui2\u0026#39;).enable() -- 注意：这是实验性功能，可能导致某些插件不兼容 -- 建议先用几天观察稳定性再长期启用 七、迁移 Checklist #从旧版本升级到 0.12 时，逐一检查：\n项目 操作 插件管理器 评估是否用 vim.pack 替代 Packer/Lazy 诊断 Signs 删除所有 sign-define 代码，改用 vim.diagnostic.config() vim.diff 改为 vim.text.diff semantic_tokens start()/stop() → enable() vim.diagnostic.disable() 移除，0.12 中已不存在 vim.treesitter.get_parser() 加 nil 检查，不再依赖抛异常 Insert Ctrl-R 如需旧行为（解释特殊字符），改用 \u0026lt;C-R\u0026gt;=@x tohtml 需手动 :packadd nvim.tohtml shellmenu 插件 已移除 'shelltemp' 默认变为 false，如依赖旧行为需手动设 true 八、总结 #Neovim 0.12 的核心故事不只是\u0026quot;又加了几个功能\u0026quot;——它让编辑器本身承担了更多原来需要插件栈才能实现的能力。内置插件管理、自动补全、LSP增强、UI重设计、诊断配置简化——五根支柱撑起了\u0026quot;开箱即用\u0026quot;的承诺。\n对于轻度用户，0.12 可能意味着你可以删掉半数插件。对于深度定制用户，新 API 和行为变更需要仔细迁移，但换来的是更干净的架构和更快的启动速度。\n官方参考：\n:help news-0.12 :help vim.pack :help lsp :help diagnostic-signs :help ui2 :help deprecated-0.12 ","date":"April 30, 2026","permalink":"/posts/neovim-0.12-new-features/","section":"文章列表","summary":"Neovim 0.12「开箱即用之年」——内置插件管理、自动补全、LSP增强、UI2重设计，附完整迁移配置教程","title":"Neovim 0.12 新特性详解与配置实战"},{"content":"","date":null,"permalink":"/tags/%E7%BC%96%E8%BE%91%E5%99%A8/","section":"标签","summary":"","title":"编辑器"},{"content":"","date":null,"permalink":"/categories/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/","section":"Categories","summary":"","title":"读书笔记"},{"content":"","date":null,"permalink":"/tags/%E5%8F%91%E6%98%8E/","section":"标签","summary":"","title":"发明"},{"content":"从小到大，我们被反复教育一件事——懒惰是坏毛病。老师说懒，爸妈说懒，连自己都觉得懒是一种罪恶。\n但有一位美国人，叫 F.J. 凯利，写了一篇《懒惰的智慧》，核心论点颠覆常识：\n懒惰，推动了人类的进步。\n听起来离谱？别急，往下看。\n一、直立行走：懒得爬的祖先站了起来 #凯利先把我们拉回远古时代。\n想象我们的祖先，四肢着地，爬行翻山越岭——又慢又累又费劲。然后有一天，有个\u0026quot;懒人\u0026quot;站了起来：爬着走太累了，站着走是不是更快？省力，还能腾出两只手干别的。\n于是，人类从爬行变成直立行走。\n如果不是因为\u0026quot;懒\u0026quot;——不想费那么大力气，我们可能今天还在地上爬。\n二、家用电器：懒得洗衣服的主妇改变了世界 #长期以来，妇女们承担着沉重的家务——洗衣、洗碗、扫地、做饭，日复一日。\n然后一个\u0026quot;懒惰\u0026quot;的主妇出现了：\n不想洗衣服 → 洗衣机 不想洗碗 → 洗碗机 不想扫地 → 吸尘器 不想做饭 → 电饭煲、微波炉 几乎所有让生活变方便的东西，都源于一个简单念头——\u0026ldquo;我不想干这个活\u0026rdquo;。懒惰的主妇们，用她们的\u0026quot;懒\u0026quot;，发明了现代家用电器，解放了千千万万女性的双手。\n三、工程师：最懒的人造了最伟大的东西 #凯利说，最懒的人是谁？工程师。\n懒得爬楼梯 → 电梯 懒得走路 → 汽车 懒得写信等回信 → 电话 懒得自己算 → 计算机 这些发明听起来是伟大成就，但起点都很朴素——就是不想干那个费力的活。工程师不是靠勤奋爬楼梯证明自己厉害，而是靠想出一个不用爬楼梯的办法来改变世界。\n四、取水的演进：懒惰层层递进，技术步步升级 #凯利讲了一个精彩的例子——人类取水的演进：\n阶段 动机 结果 ① 每天走到河边取水 — 又远又累 ② 发明水管引水到门口 走那么远太辛苦 稍省力 ③ 发明水车，水自动流进屋 连出门都懒得动 更省力 ④ 自来水 水车还得建造维护 终极偷懒 每一步进步，都是因为有人觉得上一个方案还不够省力。懒惰层层递进，技术步步升级。\n五、对数、传送带与索引：懒得重复的人创造了文明 #凯利还列举了更多例子：\n一个懒少年不想逐笔逐笔地算 → 发明了对数 一个懒人不想来回搬运 → 发明了传送带 一个懒人不想一页页翻书 → 发明了索引系统 几乎所有伟大的发明家都是\u0026quot;懒惰\u0026quot;的。他们不是勤奋地重复同样的工作，而是懒洋洋地坐着，想着——能不能用更少的力气做更多的事情？\n六、现代视角：程序员与AI——懒惰的正循环 #凯利写这篇文章时是上个世纪，但他说的道理在今天更加成立。\n想想程序员。好程序员绝不每天手动重复同样操作——写脚本一键自动化，搭流水线自动测试、自动部署。程序员的口头禅：\nDon\u0026rsquo;t repeat yourself — 不要重复自己。说白了就是：我懒得干重复的事。\n再想想AI。大模型的出现，本质上也是人类懒得写每一行代码、懒得查每一份资料、懒得做每一张图。我们训练了一个AI来帮我们干这些活。\n懒惰 → 找省力方法 → 发明工具 → 解放人力 → 创造新可能 → 继续懒 → 继续发明……\n这是一个正循环。懒惰不是终点，而是起点。它推动的不是堕落，而是进化。\n总结 #所以，下次有人说你懒，你可以理直气壮地回答——\n\u0026ldquo;我不是懒，我是在推动人类进步。\u0026rdquo;\n当然，前提是你得用懒惰来思考，而不是用懒惰来躺平。\n真正的懒惰智慧，不是什么都不干，而是想办法让该干的事变得更简单。\n凯利说得好——懒惰，是人类进步的动力，是智慧的源泉。\n原文作者：F.J.凯利（美国） 出处：语文版八年级上册第12课（旧版教材，统编教材已删）\n","date":"April 30, 2026","permalink":"/posts/lazy-wisdom/","section":"文章列表","summary":"从直立行走到AI时代，人类一切发明创造的根源竟是一种被诅咒的品质——懒惰。凯利的反常识论证告诉我们：真正的懒惰不是躺平，而是用智慧让该干的事变得更简单。","title":"懒惰的智慧：懒人如何推动了人类进步"},{"content":"","date":null,"permalink":"/tags/%E9%9A%8F%E7%AC%94/","section":"标签","summary":"","title":"随笔"},{"content":"","date":null,"permalink":"/tags/%E5%93%B2%E5%AD%A6/","section":"标签","summary":"","title":"哲学"},{"content":"","date":null,"permalink":"/tags/%E5%8D%9A%E5%BC%88%E8%AE%BA/","section":"标签","summary":"","title":"博弈论"},{"content":"定义：一层之差，天壤之别 #共有知识（Mutual Knowledge）：每个人都知道某个事实，但不确定别人是否也知道。\n公共知识（Common Knowledge）：每个人都知道，每个人都知道每个人都知道，每个人都知道每个人都知道每个人都知道……无限递归。\n看似只差一层\u0026quot;你知道我知道\u0026quot;，但正是这层递归，决定了集体能否从\u0026quot;想行动\u0026quot;跨越到\u0026quot;敢行动\u0026quot;。\n泥孩悖论：一个经典实验 #三个孩子脸上都有泥，各自只看到别人的泥——\u0026ldquo;有人有泥\u0026quot;是共有知识。每人知道事实，却无法推断自己。\n父亲当众宣布\u0026quot;至少一人有泥\u0026rdquo;——同一事实瞬间成为公共知识。三轮追问后，三个泥孩全部正确推断出自己有泥。没有公开宣布，推理链无法启动。\n从想→敢：公开化的力量 #金融泡沫 #投资者私下都知道估值虚高（共有知识），但没人敢先卖——缺少协调基础。权威人物公开喊出\u0026quot;这是泡沫\u0026quot;，公共知识建立，雪崩式抛售随即触发。做空者等待的不是虚高本身，而是虚高变成公共知识的那个瞬间。\n集体行动 #所有人都厌恶独裁者（共有知识），但反抗需要大量人同时行动，个人出头等于送死。一个公开信号——大规模集会、领袖号召——把\u0026quot;很多人愿意站出来\u0026quot;变成公共知识，革命爆发。独裁者压制媒体的本质不是让你不知道真相，而是阻止真相成为公共知识——阻止协调。\n组织变革 #公司里每个人都觉得某制度不合理（共有知识），但没人提——怕被领导视为唯一抱怨者。领导在全员大会上公开承认\u0026quot;这个制度有问题，要改\u0026quot;，公共知识建立，改革阻力骤降。优秀领导者做的事不是发现问题，而是公开承认问题。\n房间里的大象 #聚会中有人说了冒犯的话，所有人都觉得不对（共有知识），但没人开口。第一个公开表态的人承担了把共有知识变成公共知识的成本，后续者的社交风险归零。吹哨人的价值远超其个人——ta创造了公共知识。\n决策框架 # 目标 需要 关键动作 协调集体行动 公共知识 公开宣布，让所有人看到\u0026quot;所有人都看到了\u0026quot; 阻止协调 阻止公共知识 切断公开渠道，压制广场式传播 释放组织潜力 公共知识 领导公开承认问题，而非私下征求意见 破解沉默螺旋 公共知识 做第一个公开表态的人 稳定预期 公共知识 制度与规则的公开制定 一句话 # 共有知识让人想做某事，公共知识让人敢做某事。从想→敢的关键一步，是公开化。\n人类社会发明了广场、媒体、议会、法庭、公告栏、社交平台——本质上都是公共知识制造器。理解这一点，你就理解了为什么某些变革只需要一个公开的时刻。\n","date":"April 29, 2026","permalink":"/posts/common-knowledge-vs-mutual-knowledge/","section":"文章列表","summary":"博弈论中两个看似相近的概念，却是理解集体行动、泡沫崩盘与组织变革的关键钥匙","title":"共有知识 vs 公共知识：行为决策的影响"},{"content":"","date":null,"permalink":"/tags/%E5%86%B3%E7%AD%96/","section":"标签","summary":"","title":"决策"},{"content":"","date":null,"permalink":"/categories/%E6%80%9D%E7%BB%B4%E5%B7%A5%E5%85%B7/","section":"Categories","summary":"","title":"思维工具"},{"content":"","date":null,"permalink":"/tags/%E4%BF%A1%E6%81%AF%E7%BB%8F%E6%B5%8E%E5%AD%A6/","section":"标签","summary":"","title":"信息经济学"},{"content":"","date":null,"permalink":"/tags/congo/","section":"标签","summary":"","title":"Congo"},{"content":"本篇文章将演示 Hugo Congo 主题支持的三大核心功能：代码高亮、LaTeX 数学公式和 Mermaid 图表。\n1. 代码高亮演示 #Congo 主题内置 Hugo Chroma 代码高亮引擎，支持数百种编程语言。\nPython 示例 # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def fibonacci(n: int) -\u0026gt; list[int]: \u0026#34;\u0026#34;\u0026#34;计算斐波那契数列前 n 项\u0026#34;\u0026#34;\u0026#34; if n \u0026lt;= 0: return [] elif n == 1: return [0] fib = [0, 1] for i in range(2, n): fib.append(fib[i-1] + fib[i-2]) return fib # 示例调用 result = fibonacci(10) print(f\u0026#34;斐波那契数列前10项: {result}\u0026#34;) Go 示例 # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package main import ( \u0026#34;fmt\u0026#34; \u0026#34;context\u0026#34; ) func worker(ctx context.Context, id int, jobs \u0026lt;-chan int, results chan\u0026lt;- int) { for job := range jobs { select { case \u0026lt;-ctx.Done(): fmt.Printf(\u0026#34;Worker %d cancelled\\n\u0026#34;, id) return default: result := job * 2 fmt.Printf(\u0026#34;Worker %d processed job %d -\u0026gt; %d\\n\u0026#34;, id, job, result) results \u0026lt;- result } } } func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() jobs := make(chan int, 100) results := make(chan int, 100) // 启动 3 个 worker for w := 1; w \u0026lt;= 3; w++ { go worker(ctx, w, jobs, results) } // 发送 10 个任务 for j := 1; j \u0026lt;= 10; j++ { jobs \u0026lt;- j } close(jobs) // 收集结果 for r := 1; r \u0026lt;= 10; r++ { \u0026lt;-results } } JavaScript 示例 # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 // 异步迭代器处理流式数据 async function* streamProcessor(url) { const response = await fetch(url); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = \u0026#39;\u0026#39;; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split(\u0026#39;\\n\u0026#39;); buffer = lines.pop() ?? \u0026#39;\u0026#39;; for (const line of lines) { if (line.trim()) { yield JSON.parse(line); } } } } // 使用示例 for await (const data of streamProcessor(\u0026#39;/api/events\u0026#39;)) { console.log(\u0026#39;Received:\u0026#39;, data); } Rust 示例 # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 use std::collections::HashMap; #[derive(Debug, Clone)] pub struct LRUCache\u0026lt;K, V\u0026gt; { capacity: usize, cache: HashMap\u0026lt;K, V\u0026gt;, order: Vec\u0026lt;K\u0026gt;, } impl\u0026lt;K: Clone + std:#️⃣:Hash + Eq, V\u0026gt; LRUCache\u0026lt;K, V\u0026gt; { pub fn new(capacity: usize) -\u0026gt; Self { Self { capacity, cache: HashMap::with_capacity(capacity), order: Vec::with_capacity(capacity), } } pub fn get(\u0026amp;mut self, key: \u0026amp;K) -\u0026gt; Option\u0026lt;\u0026amp;V\u0026gt; { if let Some(value) = self.cache.get(key) { self.order.retain(|k| k != key); self.order.push(key.clone()); Some(value) } else { None } } pub fn put(\u0026amp;mut self, key: K, value: V) { if self.cache.contains_key(\u0026amp;key) { self.order.retain(|k| k != \u0026amp;key); } else if self.cache.len() \u0026gt;= self.capacity { if let Some(lru_key) = self.order.first().cloned() { self.cache.remove(\u0026amp;lru_key); self.order.remove(0); } } self.cache.insert(key.clone(), value); self.order.push(key); } } Shell 示例 # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #!/bin/bash # Docker 容器健康检查脚本 CONTAINER_NAME=\u0026#34;myapp\u0026#34; MAX_RETRIES=30 RETRY_INTERVAL=2 check_container_health() { local status=$(docker inspect --format=\u0026#39;{{.State.Health.Status}}\u0026#39; $CONTAINER_NAME 2\u0026gt;/dev/null) case $status in \u0026#34;healthy\u0026#34;) echo \u0026#34;✓ 容器状态正常\u0026#34; return 0 ;; \u0026#34;unhealthy\u0026#34;) echo \u0026#34;✗ 容器状态异常\u0026#34; docker logs --tail 50 $CONTAINER_NAME return 1 ;; \u0026#34;starting\u0026#34;) echo \u0026#34;⏳ 容器正在启动...\u0026#34; return 2 ;; *) echo \u0026#34;✗ 无法获取容器状态\u0026#34; return 3 ;; esac } echo \u0026#34;开始健康检查...\u0026#34; for i in $(seq 1 $MAX_RETRIES); do echo \u0026#34;尝试 $i/$MAX_RETRIES\u0026#34; check_container_health status=$? if [ $status -eq 0 ]; then echo \u0026#34;健康检查通过\u0026#34; exit 0 elif [ $status -eq 1 ]; then exit 1 fi sleep $RETRY_INTERVAL done echo \u0026#34;健康检查超时\u0026#34; exit 1 2. LaTeX 数学公式演示 #行内公式 #质能方程 $E = mc^2$ 是物理学中最著名的公式之一。\n块级公式 #2.1 线性代数 #矩阵乘法：\n$$ \\begin{align} \\begin{bmatrix} a_{11} \u0026 a_{12} \u0026 a_{13} \\\\ a_{21} \u0026 a_{22} \u0026 a_{23} \\\\ a_{31} \u0026 a_{32} \u0026 a_{33} \\end{bmatrix} \\begin{bmatrix} x_1 \\\\ x_2 \\\\ x_3 \\end{bmatrix} = \\begin{bmatrix} b_1 \\\\ b_2 \\\\ b_3 \\end{bmatrix} \\end{align} $$2.2 微积分 #泰勒展开式：\n$$ f(x) = f(a) + \\frac{f'(a)}{1!}(x-a) + \\frac{f''(a)}{2!}(x-a)^2 + \\cdots + \\frac{f^{(n)}(a)}{n!}(x-a)^n + R_n(x) $$2.3 概率论 #正态分布概率密度函数：\n$$ f(x) = \\frac{1}{\\sigma\\sqrt{2\\pi}} e^{-\\frac{(x-\\mu)^2}{2\\sigma^2}} $$2.4 复杂公式 #傅里叶变换：\n$$ \\hat{f}(\\xi) = \\int_{-\\infty}^{\\infty} f(x) e^{-2\\pi i x \\xi} dx $$ 3. Mermaid 图表演示 #3.1 流程图 #\rgraph TD A[开始] --\u003e B{是否有 Hugo} B --\u003e|是| C[安装 Congo 主题] B --\u003e|否| D[安装 Hugo Extended] D --\u003e C C --\u003e E[配置主题参数] E --\u003e F[创建内容] F --\u003e G[预览效果] G --\u003e H{满意?} H --\u003e|是| I[部署上线] H --\u003e|否| E I --\u003e J[完成] 3.2 时序图 #\rsequenceDiagram participant U as 用户 participant B as 浏览器 participant S as 服务器 participant D as 数据库 U-\u003e\u003eB: 访问博客首页 B-\u003e\u003eS: GET /index.html S-\u003e\u003eD: 查询文章列表 D--\u003e\u003eS: 返回文章数据 S--\u003e\u003eB: 返回 HTML + CSS + JS B--\u003e\u003eU: 渲染页面 Note over U,D: 用户开始阅读文章 U-\u003e\u003eB: 点击文章链接 B-\u003e\u003eS: GET /posts/xxx/ S-\u003e\u003eD: 查询文章详情 D--\u003e\u003eS: 返回文章内容 S--\u003e\u003eB: 返回文章页面 B--\u003e\u003eU: 显示文章内容 3.3 状态图 #\rstateDiagram-v2 [*] --\u003e 待支付 待支付 --\u003e 已支付: 支付成功 待支付 --\u003e 已取消: 超时/取消 已支付 --\u003e 配货中: 商家发货 配货中 --\u003e 运输中: 快递揽收 运输中 --\u003e 已签收: 确认收货 已签收 --\u003e [*] 已取消 --\u003e [*] 3.4 类图 #\rclassDiagram class Animal { +String name +int age +makeSound() void } class Dog { +String breed +fetch() void } class Cat { +boolean indoor +scratch() void } class Bird { +double wingSpan +fly() void } Animal \u003c|-- Dog: 继承 Animal \u003c|-- Cat: 继承 Animal \u003c|-- Bird: 继承 总结 #以上演示涵盖了：\n代码高亮: Python, Go, JavaScript, Rust, Shell 等多种语言 LaTeX: 行内公式、块级公式、矩阵、积分、概率等复杂公式 Mermaid: 流程图、时序图、状态图、类图等多种图表类型 Congo 主题完美支持这些功能，让你的技术博客更加专业美观！\n","date":"January 15, 2026","permalink":"/posts/feature-demo/","section":"文章列表","summary":"\u003cp\u003e本篇文章将演示 Hugo Congo 主题支持的三大核心功能：代码高亮、LaTeX 数学公式和 Mermaid 图表。\u003c/p\u003e","title":"Congo 主题功能演示"},{"content":"","date":null,"permalink":"/tags/hugo/","section":"标签","summary":"","title":"Hugo"},{"content":"","date":null,"permalink":"/categories/%E6%8A%80%E6%9C%AF%E6%95%99%E7%A8%8B/","section":"Categories","summary":"","title":"技术教程"},{"content":"","date":null,"permalink":"/tags/%E6%BC%94%E7%A4%BA/","section":"标签","summary":"","title":"演示"},{"content":"你好，我是 RedJACK #一个长期计算机爱好者，也是一个兴趣广泛的人。\n底层原理比\u0026quot;能用就行\u0026quot;重要 #我对技术的态度很简单——不满足于表面。一个工具能跑起来只是起点，搞清楚它为什么能跑、底层怎么运转，才是真正有意思的部分。这种好奇心驱动了我对计算机的长期投入，也塑造了我面对任何领域的方式：先理解，再使用。\n跨界是优势，不是偏差 #人的路径不必是直线。在不同的领域之间穿行，反而能获得单一视角永远看不到的东西——化学的思维、教育的直觉、技术的精确，这些东西拼在一起，比任何单独一块都更有力。我相信跨界的经验不是浪费，而是积累。\n广泛涉猎和深入钻研同样重要 #好奇心不应该被领域限定。技术之外，国际象棋、地缘政治、纪录片——这些看似无关的兴趣，其实都在训练同一种能力：从复杂系统中识别模式、做出判断。广泛涉猎不是分心，是给深度思考提供更多原材料。\nAI 是工具，也是镜子 #深度使用大模型三年以上，让我对 AI 有了一个清醒的认知：它是极好的工具，但真正决定输出质量的，始终是人提出的问题和判断标准。AI 放大的不是能力，是方向——方向对了，事半功倍；方向错了，跑得更快也只是更快地偏离。\n这个博客 #这里记录琢磨过的东西——技术心得、学习笔记、偶尔的想法。没有什么宏大目标，就是把思考的过程留下来，给自己看，也给同路人看。\n","date":null,"permalink":"/about/","section":"欢迎来到我的博客","summary":"","title":"关于我"}]