<?xml version="1.0" encoding="utf-8" standalone="yes"?><?xml-stylesheet type="text/xsl" href="/rss.xsl"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Vinfall@Geekademy</title><link>https://blog.vinfall.com/</link><description>Recent content on Vinfall@Geekademy</description><generator>Hugo</generator><language>en-US</language><managingEditor>Vinfall</managingEditor><webMaster>Vinfall</webMaster><copyright>Made with ❤ by Vinfall since 2017.</copyright><lastBuildDate>2026-09-10</lastBuildDate><atom:link href="https://blog.vinfall.com/index.xml" rel="self" type="application/rss+xml"/><item><title>VSC -&gt; Zed 迁移</title><link>https://blog.vinfall.com/posts/2026/03/vsc2zed/</link><pubDate>2026-09-01</pubDate><author>Vinfall</author><guid>https://blog.vinfall.com/posts/2026/03/vsc2zed/</guid><summary>Zed est de la partie</summary><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;距离 &lt;a href="https://blog.vinfall.com/posts/2024/05/farewell/"&gt;Time to Press the Stop Button&lt;/a&gt; 已经将近两年，这一波学习热潮总算是接近尾声。
从 &lt;a href="https://blog.vinfall.com/posts/2025/12/my-cli-setup/"&gt;My Cli Setup&lt;/a&gt; 开始陆续尝试了很多新工具，也重构了不少项目，这些统一在 &lt;a href="https://blog.vinfall.com/posts/2026/04/2025-recap-dev/"&gt;2025 年度总结 - 开发篇&lt;/a&gt; 介绍，今天就简单讲讲从 VSCodium（下称 VSC）到 Zed 的迁移过程。&lt;/p&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://zed.dev"&gt;Zed&lt;/a&gt; 算是近两年的热门编辑器，虽然看上去类似 VSCode，因为基于 tree-sitter 和 LSP，实际体验可能更贴近 neovim。最早作为闭源 macOS only 编辑器没多少热度，开源并支持 Linux/Windows 才逐渐起色。&lt;/p&gt;
&lt;p&gt;虽然我最早知道 Zed 还是因为 zedless，但后者开发过于缓慢，还不发布二进制，作为单纯的 fork 的意义不大。不像 VSCode -&amp;gt; VSCodium，后者间接推动了 Open VSX Registry 的发展，除了 Eclipse 本家还有一大堆 VSC fork 在用，避免了 Visual Studio Marketplace 的 vendor lock-in。&lt;/p&gt;
&lt;h2 id="迁移"&gt;迁移&lt;/h2&gt;
&lt;h3 id="设置"&gt;设置&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;虽然 Zed 官网也有 &lt;a href="https://zed.dev/docs/migrate/vs-code"&gt;How to Migrate from VS Code to Zed&lt;/a&gt;，但写得太简单，只看这里立马使用会浑身难受，建议过一遍自定义、设置项的文档再上手。&lt;/li&gt;
&lt;li&gt;内置的协作工具我觉得没什么用就直接关了，登录也是不可能登录的，直接隐藏按钮。&lt;/li&gt;
&lt;li&gt;OpenCode ACP 简单试了下，效果不是很行。LLM Provider API Key 也是明文储存，非常难绷。虽然可以通过配置收紧默认权限，申请权限也可以拒绝，但拒绝了就停了，权限控制堪称笑话……&lt;/li&gt;
&lt;li&gt;&lt;code&gt;file_scan_exclusions&lt;/code&gt; 对应 VSC &lt;code&gt;files.{exclude,watcherExclude}&lt;/code&gt;，类似的还有 &lt;code&gt;file_scan_inclusions&lt;/code&gt;，Zed 默认值要合理一点点，但自定义必须补全默认值，略冗长。&lt;/li&gt;
&lt;li&gt;file_types 逻辑和 VSC files.associations 反着来，更加合理。&lt;/li&gt;
&lt;li&gt;VSC 的 Code Runner 插件，支持近百种语言的一键运行。Zed 最近的几次更新在 shebang 和 code block 添加了运行按钮，能用，但非常凑合，手动编写 tasks.json 也只是亡羊补牢。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="更新"&gt;更新&lt;/h3&gt;
&lt;p&gt;为了防止供应链攻击 &lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;，我从来不用自动更新，而是通过其他方式管理。&lt;/p&gt;
&lt;p&gt;因为 Void 对 fork/Electron 极端排斥，只能下载 .deb 然后用 xdeb 转换成 xbps 安装。由于 VSC 不支持 &lt;a href="https://blog.vinfall.com/posts/2022/10/xdg-base-dir/"&gt;xdg-base-dir&lt;/a&gt;，安装后还要手动 patch &lt;code&gt;dataFolderName&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo sed -i &lt;span style="color:#e6db74"&gt;&amp;#39;s|&amp;#34;dataFolderName&amp;#34;: &amp;#34;.*&amp;#34;|&amp;#34;dataFolderName&amp;#34;: &amp;#34;.local/share/VSCodium&amp;#34;|g&amp;#39;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/usr/share/codium/resources/app/product.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Zed 这点做得很好，开箱支持。由于支持架构少了十几种，也不需要在一百多个 GitHub release assets 中翻找 &lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;，更新脚本写起来很简单，动态更新直接 &lt;code&gt;rsync -a --update --delete --links&lt;/code&gt; 即可。&lt;/p&gt;
&lt;h3 id="备份"&gt;备份&lt;/h3&gt;
&lt;p&gt;Zed 没有 workspace 的概念，打开一个文件夹即是一个 project。Project history 保存在 &lt;code&gt;~/.local/share/zed/db/*/db.sqlite&lt;/code&gt; 的 workspaces 表 &lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;，直接备份数据库即可，避免重装要手动拖上百个文件夹的惨剧。&lt;/p&gt;
&lt;p&gt;插件和 language server 列表当然也可以备份 &lt;code&gt;~/.local/share/zed/{extensions,languages}&lt;/code&gt;，但都可以在 &lt;code&gt;auto_install_extensions&lt;/code&gt; 设置项配置，没必要。&lt;/p&gt;
&lt;h2 id="linter"&gt;Linter&lt;/h2&gt;
&lt;p&gt;Zed 统一使用 LSP 对接，也可以调用外部 formatter/linter 处理 stdin，设计很合理。&lt;/p&gt;
&lt;p&gt;好处说完了，该开喷了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;启动 Zed 会自动下载 Node.js，哪怕系统已安装并且已经添加到 PATH 也如此。妥妥的流氓行径&lt;/li&gt;
&lt;li&gt;初次打开的文件类型，Zed 会自动下载对应 language server，这挺好，就是偶尔打开一次的文件还要装几百兆依赖有点蠢，好在被骂多了现在添加了提醒。但是，为了方便默认使用万恶的 prettier……&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;有点跑题了，回到 linter，简单列个表，算作 &lt;a href="https://blog.vinfall.com/posts/2025/04/mise-as-linter/#tldr"&gt;mise-as-linter#TLDR&lt;/a&gt; 的更新。
不过 VSC 用了这么多年，接触过的语言有点多，只能写一下目前已经配置的。&lt;/p&gt;
&lt;h3 id="注意"&gt;注意&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Linter 和 Language Server 分开列，Zed 内置支持则用括号表示。&lt;/li&gt;
&lt;li&gt;和 &lt;a href="https://blog.vinfall.com/posts/2025/04/mise-as-linter/#tldr"&gt;mise-as-linter&lt;/a&gt; 类似，这里的 linter 同时指代: linter, formatter, language server, extension。&lt;/li&gt;
&lt;li&gt;严格来说 LSP 指代 Language Server Protocol，即工具与 Language Server 交互的协议。而且 Zed 插件除了 language server，也有 syntax highlighter。为了简化逻辑，下文刻意混用，统一称作 LSP。&lt;/li&gt;
&lt;li&gt;Zed 文档和插件命名很混乱，为了减少歧义，按以下优先级降序
&lt;ol&gt;
&lt;li&gt;settings.json auto_install_extensions 的扩展名&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.local/share/zed/{languages,extensions/installed}&lt;/code&gt; 的文件夹名&lt;/li&gt;
&lt;li&gt;GitHub zed-extensions 的 repo 名&lt;/li&gt;
&lt;li&gt;Zed 文档中的命名 &lt;sup id="fnref:4"&gt;&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref"&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="列表"&gt;列表&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Linter&lt;/th&gt;
&lt;th&gt;LSP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bash&lt;/td&gt;
&lt;td&gt;shellcheck, shfmt&lt;/td&gt;
&lt;td&gt;(bash-language-server)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zsh&lt;/td&gt;
&lt;td&gt;shellcheck&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C/C++&lt;/td&gt;
&lt;td&gt;clangd&lt;/td&gt;
&lt;td&gt;(clangd)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JavaScript&lt;/td&gt;
&lt;td&gt;biome, oxlint&lt;/td&gt;
&lt;td&gt;biome+oxlint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TypeScript&lt;/td&gt;
&lt;td&gt;biome, oxlint&lt;/td&gt;
&lt;td&gt;vtsls+oxlint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSS&lt;/td&gt;
&lt;td&gt;biome&lt;/td&gt;
&lt;td&gt;vscode-css-languageservice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML&lt;/td&gt;
&lt;td&gt;biome&lt;/td&gt;
&lt;td&gt;html&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON/JSONC&lt;/td&gt;
&lt;td&gt;biome&lt;/td&gt;
&lt;td&gt;json-language-server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lua&lt;/td&gt;
&lt;td&gt;stylua&lt;/td&gt;
&lt;td&gt;lua&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Markdown&lt;/td&gt;
&lt;td&gt;markdownlint-cli2, autocorrect&lt;/td&gt;
&lt;td&gt;autocorrect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nginx&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;td&gt;nginx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nix&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;td&gt;nix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nushell&lt;/td&gt;
&lt;td&gt;nu-lint&lt;/td&gt;
&lt;td&gt;nu+nu-lint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PowerShell&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;td&gt;powershell&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;ruff, ty&lt;/td&gt;
&lt;td&gt;ruff+ty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;lintr, styler&lt;/td&gt;
&lt;td&gt;r&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQL&lt;/td&gt;
&lt;td&gt;sqlfluff&lt;/td&gt;
&lt;td&gt;sql&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SystemD&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;td&gt;ini&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TOML&lt;/td&gt;
&lt;td&gt;tombi&lt;/td&gt;
&lt;td&gt;toml+tombi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typst&lt;/td&gt;
&lt;td&gt;typstyle&lt;/td&gt;
&lt;td&gt;typst&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;XML/XSL&lt;/td&gt;
&lt;td&gt;xmllint&lt;/td&gt;
&lt;td&gt;xml&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YAML&lt;/td&gt;
&lt;td&gt;zizmor&lt;/td&gt;
&lt;td&gt;yaml+zizmor&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="解释"&gt;解释&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Zsh
&lt;ul&gt;
&lt;li&gt;tree-sitter-bash 对于 zsh 非常排斥，可视为 wontfix。虽然有新的 tree-sitter-zsh，但还没集成进 zed。&lt;/li&gt;
&lt;li&gt;Linter/Formatter 方面倒是没太大问题，shellcheck 能用，只是有很多误报，shfmt-3.13.0+ 已经初步支持 zsh，未来可期。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;C/C++: 之前在 VSC 装了 CodeLLDB，但这么多年我 GDB 都只用过一两回，LLDB 装了也没用，迁移时直接卸载了……&lt;/li&gt;
&lt;li&gt;Lua: 和 C/C++ 类似，从没用过 VSC 的 Lua Debug 插件，这里就不装了，配置 StyLua 为 external formatter&lt;/li&gt;
&lt;li&gt;Markdown
&lt;ul&gt;
&lt;li&gt;默认使用战五渣 prettier，external formatter 配置 markdownlint-cli2 和 autocorrect 两个&lt;/li&gt;
&lt;li&gt;markdownlint-cli2 负责规范 Markdown 格式，AutoCorrect 负责 CJK 空格和规范专有词&lt;/li&gt;
&lt;li&gt;Zed 的 Markdown 支持目前只能说够用，但预览效果也在渐渐改善，假以时日想必还是能和 VSC 的 Markdown All in One 分庭抗礼&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;languages&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Markdown&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;formatter&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;external&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;markdownlint-cli2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;arguments&amp;#34;&lt;/span&gt;: [ &lt;span style="color:#e6db74"&gt;&amp;#34;--format&amp;#34;&lt;/span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;external&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;autocorrect&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;arguments&amp;#34;&lt;/span&gt;: [ &lt;span style="color:#e6db74"&gt;&amp;#34;--quiet&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;--fix&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;--stdin&amp;#34;&lt;/span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;language_servers&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;autocorrect&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;!oxfmt&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;!prettier&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Nginx: 很少需要写 Nginx 配置，gixy 自然用得少，暂时没配置&lt;/li&gt;
&lt;li&gt;Nix: nixfmt 强制一行一个软件包并且不支持使用 &lt;code&gt;nolint:on&lt;/code&gt;, &lt;code&gt;nolint:off&lt;/code&gt; 动态开关，我显然不可能用，只安装插件提供基本的高亮&lt;/li&gt;
&lt;li&gt;Nushell: 因为 nu-lint 不支持 XDG，而且 Zed 解析 settings.json 不支持 &lt;code&gt;~&lt;/code&gt; 和 &lt;code&gt;$HOME&lt;/code&gt; 这样的环境变量，也没有类似 VSC &lt;code&gt;${userHome}&lt;/code&gt; 的变量，只能在 nu-lint LSP 配置丑陋的绝对路径&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;lsp&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;nu-lint&amp;#34;&lt;/span&gt;: { &lt;span style="color:#f92672"&gt;&amp;#34;binary&amp;#34;&lt;/span&gt;: { &lt;span style="color:#f92672"&gt;&amp;#34;arguments&amp;#34;&lt;/span&gt;: [ &lt;span style="color:#e6db74"&gt;&amp;#34;--config&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;/home/aaron/.config/nu-lint/config.toml&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;--lsp&amp;#34;&lt;/span&gt; ] } }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Powershell: 很少写，只装了高亮，凑合用&lt;/li&gt;
&lt;li&gt;Python
&lt;ul&gt;
&lt;li&gt;LSP: Zed 虽然支持 ty，但为了兼容性默认会安装 ty, basedpyright, pyright, pylsp 四个 language servers，我直呼有病病？在配置里禁用 ty 之外的 LSP 并禁止自动安装对应插件 &lt;sup id="fnref:5"&gt;&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref"&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Formatter: 默认 ruff（总算有个正常的），额外配置 &lt;code&gt;source.organizeImports.ruff&lt;/code&gt; 和 &lt;code&gt;source.fixAll.ruff&lt;/code&gt; 两个 code_actions_on_format&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;R
&lt;ul&gt;
&lt;li&gt;除了 Zed 方面需要安装 R 插件，也要安装 languageserver 和 lintr 两个 R 包。&lt;/li&gt;
&lt;li&gt;styler 是 languageserver 自带的 formatter，配合 lintr 够用。很少写 R，暂时没兴趣尝试 Posit（RStudio 开发公司）做的 air。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SQL: 配置 sqlfluff 为 external formatter&lt;/li&gt;
&lt;li&gt;SystemD: 不是 typo，除了 ini 本体，zed-ini 真的支持 EditorConfig, SystemD Unit , Podman Quadlet 等一堆格式。和 Nginx 类似，很少写 SystemD 配置，systemdlint 也很少用，暂不配置。&lt;/li&gt;
&lt;li&gt;TOML: 之前用的 taplo 很少维护，插件被 Zed 移除了，我无语……好在测试下来 tombi 确实更实用，直接迁移&lt;/li&gt;
&lt;li&gt;Typst: 体验比不了 LaTeX Workshop，凑合用。CJK 支持不完美，但编译够快，额外配置 typstyle 为 external formatter&lt;/li&gt;
&lt;li&gt;XML: Linux 几乎必装的 libxml2 依赖自带 xmllint，根本不需要 prettier，配置为 external formatter&lt;/li&gt;
&lt;li&gt;YAML
&lt;ul&gt;
&lt;li&gt;虽然装了 yamllint，但因为我很讨厌 YAML 又不用 Docker，基本只用于 GitHub Action，和 zizmor 一起用&lt;/li&gt;
&lt;li&gt;Formatter 默认使用 prettier，好在 yaml-language-server 也能格式化&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="prettier"&gt;Prettier&lt;/h3&gt;
&lt;div class="admonition admonition-warning"&gt;
&lt;div class="admonition-heading"&gt;
⚠️
Warning
&lt;/div&gt;
&lt;div class="admonition-content"&gt;
&lt;p&gt;JavaScript/TypeScript 已改用 biome + oxlint。经过艰苦卓绝的努力，成功实现全局禁用 prettier，下面的繁琐配置不再适用。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;单独一节专门 fuck prettier🖕biome 也有点 opinionated，但态度比 prettier 好太多，而且可以通过配置关闭。&lt;/p&gt;
&lt;p&gt;&lt;del&gt;现在 oxc (oxfmt/oxlint) 似乎也能替代 biome，有空试试。&lt;/del&gt; oxlint 只支持 JavaScript/TypeScript、JSX/TSX 和前端框架配置的 &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; 部分，无法彻底替代 biome。oxfmt 因为不支持为不同语言配置不同格式（又是被 prettier 荼毒的后遗症），不考虑。因为 oxc-zed 提供 oxfmt/oxlint 两个 LSP，我这种只用 oxlint 彻底禁用 oxfmt 的用法配置起来非常繁琐，没有写进下文。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JavaScript: zed 默认用杀千刀的 prettier，必须禁用，这里将 biome 作为 LSP 使用，配置起来更简单。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;languages&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;JavaScript&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;formatter&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;language_server&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;language_servers&amp;#34;&lt;/span&gt;: [ &lt;span style="color:#e6db74"&gt;&amp;#34;biome&amp;#34;&lt;/span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;code_actions_on_format&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;source.fixAll.biome&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;source.organizeImports.biome&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;…&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;TypeScript/TSX: 和 JavaScript 类似，但保留默认 language server&lt;/li&gt;
&lt;li&gt;CSS/HTML: biome 虽然支持 LSP，一样保留默认 language server，只当作 linter/formatter，配置起来也简单。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;languages&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;CSS&amp;#34;&lt;/span&gt;: { &lt;span style="color:#f92672"&gt;&amp;#34;formatter&amp;#34;&lt;/span&gt;: { &lt;span style="color:#f92672"&gt;&amp;#34;language_server&amp;#34;&lt;/span&gt;: { &lt;span style="color:#f92672"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;biome&amp;#34;&lt;/span&gt; } } }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;JSON/JSONC: 配置非常蛋疼，只有将 biome 配置为 external formatter 才能彻底覆盖掉人人喊打的 prettier，补充几行 argument 确保和 biome 全局配置一致，并且不影响 format on save&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;JSON&amp;#34;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;formatter&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;external&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;biome&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;arguments&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;format&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;--trailing-newline=false&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;--files-ignore-unknown=true&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;--stdin-file-path&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;{buffer_path}&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;-&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;prettier&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;allowed&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;language_servers&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;json-language-server&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;ensure_final_newline_on_save&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="其他"&gt;其他&lt;/h3&gt;
&lt;div class="admonition admonition-tip"&gt;
&lt;div class="admonition-heading"&gt;
💡
Tip
&lt;/div&gt;
&lt;div class="admonition-content"&gt;
&lt;p&gt;该部分统一使用扩展名作为命名。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;ahk: 只支持 v1 格式，不支持 v2，而且只支持 Windows，我就不能 Linux 写 + Windows 测试吗……&lt;/li&gt;
&lt;li&gt;beancount: beancount-language-server 误报太多，只用作高亮和格式化&lt;/li&gt;
&lt;li&gt;git-firefly: .gitignore 支持&lt;/li&gt;
&lt;li&gt;rainbow-csv: 维护 VNDB-Calendar 和 game-stats 必备&lt;/li&gt;
&lt;li&gt;log: 看似很有用其实没卵用，看日志一般 SSH 过去直接 less/moor，根本没机会用 GUI，更别提还要特地装个 Zed……&lt;/li&gt;
&lt;li&gt;make: 已迁移到 mise，直接不安装&lt;/li&gt;
&lt;li&gt;go/rust/zig: 自带 formatter，没啥好写的&lt;/li&gt;
&lt;li&gt;用到再安装: lean4, graphiviz, mermaid&lt;/li&gt;
&lt;li&gt;禁止安装，防止污染环境: basedpyright, docker-compose, dockerfile, eslint, prettier, pylsp, pyright&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="todo"&gt;TODO&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Code Snippet: Zed 文档写着支持，格式也和 VSC 几乎一样，实测并不能使用，由于 snippet 以别扭的 JSON 格式储存，直接复制也没卵用，只能手动管理……&lt;/li&gt;
&lt;li&gt;IaC: 搞定了 zizmor，betterleaks/trufflehog/trivy 待解决&lt;/li&gt;
&lt;li&gt;mise: VSC Mise 插件还挺有用，不过功能很基础，后面可能搓一个 Zed 版本或者为 &lt;code&gt;mise.toml&lt;/code&gt; 添加 runnables&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;软件内置更新程序是劫持重灾区，火绒更新程序也曾被劫持，好在我因为手动配置代理幸免于难……&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;为了避免这种情况，我写过 &lt;a href="https://github.com/Vinfall/UserScripts#github-release-highlight"&gt;GitHub Release Highlight&lt;/a&gt;，预设关键词，在指定 repo 自动高亮对应 asset。不过现在基本都是 mise/scoop/appman/更新脚本，很少用到。&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;这命名其实有点讽刺，说没有 workspace 但是数据库里储存 project 的 table 就叫 workspace……&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;看到我最后才考虑破文档中的命名，想必你也能稍稍理解这难以忍受的 inconsistency……&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:5"&gt;
&lt;p&gt;别以为这样就结束了，Zed 随时可能添加新的 language server 并静默安装。因为默认禁用，不手动检查 &lt;code&gt;~/.local/share/zed/languages&lt;/code&gt; 或者磁盘检测你甚至根本发现不了……PyLSP 就是某次更新后自动下载安装的……&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category domain="/tags/">Vsc</category><category domain="/tags/">Dev</category><category domain="/tags/">Plugin</category></item><item><title>Am I XDG Yet?</title><link>https://blog.vinfall.com/posts/2022/10/xdg-base-dir/</link><pubDate>2026-08-26</pubDate><author>Vinfall</author><guid>https://blog.vinfall.com/posts/2022/10/xdg-base-dir/</guid><summary>XDG Violation Ground.</summary><description>&lt;h2 id="what"&gt;What&lt;/h2&gt;
&lt;p&gt;Historically, this serves as a reminder of how to make &lt;code&gt;$HOME&lt;/code&gt; (mostly) clutter-free, to manage dotfiles easier.&lt;/p&gt;
&lt;p&gt;Nowadays I use this index to track the XDG support status of programs that &lt;em&gt;I&lt;/em&gt; use, hence the title.&lt;/p&gt;
&lt;h2 id="tldr"&gt;TLDR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;For TLDR, see &lt;a href="https://xdgbasedirectoryspecification.com/"&gt;Use the XDG Base Directory Specification!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;For specs, see &lt;a href="https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html"&gt;XDG Base Directory Specification&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Show, don&amp;rsquo;t tell:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Use the XDG Base Directory Specification&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# TLDR: https://xdgbasedirectoryspecification.com/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Spec: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export XDG_CONFIG_HOME&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$HOME&lt;span style="color:#e6db74"&gt;/.config&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export XDG_DATA_HOME&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$HOME&lt;span style="color:#e6db74"&gt;/.local/share&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export XDG_STATE_HOME&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$HOME&lt;span style="color:#e6db74"&gt;/.local/state&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export XDG_CACHE_HOME&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$HOME&lt;span style="color:#e6db74"&gt;/.cache&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Most solutions are available in &lt;a href="https://wiki.archlinux.org/title/XDG_Base_Directory"&gt;XDG Base Directory&lt;/a&gt; entry on Arch Wiki.
You can also use &lt;a href="https://github.com/b3nj5m1n/xdg-ninja"&gt;xdg-ninja&lt;/a&gt; for the initial setup.&lt;/p&gt;
&lt;h2 id="who"&gt;Who&lt;/h2&gt;
&lt;p&gt;Many softwares live long enough to arrogantly ignore XDG and get away with it. A recent example is &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=259356"&gt;xdg-basedir enhancement&lt;/a&gt; on Bugzilla, which finally got closed in Firefox 147, 21 years later.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; ADB &amp;amp; Android Studio (would look for &lt;code&gt;ADB_VENDOR_KEYS&lt;/code&gt; as well, but &lt;code&gt;~/.android&lt;/code&gt; would ALWAYS get generated…)&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Bash&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Cargo (&lt;code&gt;CARGO_HOME&lt;/code&gt; means config + data, silly idea)&lt;/li&gt;
&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; &lt;a href="https://issues.chromium.org/issues/40666379"&gt;Chromium&lt;/a&gt; (fixed in 146)
&lt;ul&gt;
&lt;li&gt;endless CEF/Electron/NW.js/QtWebEngine projects…&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=259356"&gt;Firefox&lt;/a&gt; (fixed in 147 and ESR 153)
&lt;ul&gt;
&lt;li&gt;Thunderbird and &lt;a href="https://github.com/zotero/zotero/issues/1203"&gt;Zotero&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;a href="https://github.com/leanprover/elan/issues/75"&gt;Lean&lt;/a&gt; (same as Cargo)&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;a href="https://github.com/mamedev/mame/issues/12508"&gt;MAME&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;a href="https://github.com/dotnet/sdk/issues/10390"&gt;.NET&lt;/a&gt; (&lt;a href="https://github.com/b3nj5m1n/xdg-ninja/issues/349"&gt;old solution&lt;/a&gt; and &lt;a href="https://github.com/dotnet/runtime/issues/98276"&gt;runtime discussion&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; nim, nimble&lt;/li&gt;
&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; &lt;a href="https://github.com/ollama/ollama/issues/228"&gt;Ollama&lt;/a&gt; (just models, config &amp;amp; ssh key are not supported)&lt;/li&gt;
&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; &lt;a href="https://blog.vinfall.com/posts/2022/10/xdg-base-dir/#python"&gt;Python&lt;/a&gt; (&lt;code&gt;PYTHON_HISTORY&lt;/code&gt; works for Python 3.13+)&lt;/li&gt;
&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; &lt;a href="https://github.com/renpy/renpy/issues/1377#issuecomment-370118555"&gt;Ren&amp;rsquo;Py&lt;/a&gt; (&lt;code&gt;RENPY_PATH_TO_SAVES&lt;/code&gt; works on Ren&amp;rsquo;Py 7.5+ games)&lt;/li&gt;
&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; &lt;a href="https://blog.vinfall.com/posts/2022/10/xdg-base-dir/#r"&gt;R&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; &lt;a href="https://github.com/vim/vim/issues/19399#issuecomment-3923305031"&gt;Vim&lt;/a&gt; (fully supported since 9.2.0019. Simply add &lt;code&gt;source $VIMRUNTIME/xdg.vim&lt;/code&gt; in your vimrc.)&lt;/li&gt;
&lt;li&gt;&lt;del&gt;VSCode and VSCodium (&lt;code&gt;--extensions-dir&lt;/code&gt; is not enough as &lt;code&gt;.vscode-oss/argv.json&lt;/code&gt; is still needed)&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; Zsh (via &lt;code&gt;$ZDOTDIR&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how"&gt;How&lt;/h2&gt;
&lt;h3 id="python"&gt;Python&lt;/h3&gt;
&lt;div class="admonition admonition-warning"&gt;
&lt;div class="admonition-heading"&gt;
⚠️
Warning
&lt;/div&gt;
&lt;div class="admonition-content"&gt;
&lt;p&gt;OUTDATED! For Python 3.13+, simply set &lt;code&gt;PYTHON_HISTORY&lt;/code&gt; should suffice.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add these in &lt;code&gt;$HOME/.profile&lt;/code&gt;(&lt;code&gt;.bashrc&lt;/code&gt; or &lt;code&gt;.zshrc&lt;/code&gt; works too):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export PYTHONPYCACHEPREFIX&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$XDG_CACHE_HOME&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;/python
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export PYTHONUSERBASE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$XDG_DATA_HOME&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;/python
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export PYTHONSTARTUP&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$XDG_CONFIG_HOME&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;/python/pythonrc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create &lt;code&gt;&amp;quot;$XDG_CONFIG_HOME&amp;quot;/python/pythonrc&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; readline
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;readline&lt;span style="color:#f92672"&gt;.&lt;/span&gt;write_history_file &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;lambda&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;args: &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Source &lt;code&gt;$HOME/.profile&lt;/code&gt; by &lt;code&gt;exec zsh&lt;/code&gt;, done.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="r"&gt;R&lt;/h3&gt;
&lt;p&gt;While R is configurable, my setup makes it a bit hard to follow XDG base dir spec:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;R is installed via mise-r, aka. asdf-r, and located in a weird place&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ which R
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;~/.local/share/mise/shims/R
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ mise which Rscript
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;~/.local/share/mise/installs/r/latest/bin/Rscript
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;I use &lt;a href="https://github.com/eitsupi/arf"&gt;arf&lt;/a&gt; as R console, installed via mise GitHub backend&lt;/li&gt;
&lt;li&gt;I have custom &lt;code&gt;libPaths&lt;/code&gt; to avoid unnecessary reinstall between minor/patch updates.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Makevars&lt;/code&gt; set to cache/speedup library compilation&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;arf
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;R &lt;span style="color:#ae81ff"&gt;4.6.1&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;R.home&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[1] &lt;span style="color:#e6db74"&gt;&amp;#34;~/.local/share/mise/installs/r/4.6.1/lib64/R&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;R &lt;span style="color:#ae81ff"&gt;4.6.1&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;.libPaths&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[1] &lt;span style="color:#e6db74"&gt;&amp;#34;~/.local/share/R/library&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[2] &lt;span style="color:#e6db74"&gt;&amp;#34;~/.local/share/mise/installs/r/4.6.1/lib64/R/library&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;R &lt;span style="color:#ae81ff"&gt;4.6.1&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; tools&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;makevars_user&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[1] &lt;span style="color:#e6db74"&gt;&amp;#34;~/.config/R/Makevars&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course, it&amp;rsquo;s still possible and quite easy.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.profile&lt;/code&gt; (you can also set in shell rc):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# R&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# https://cran.r-project.org/doc/manuals/r-devel/R-exts.html#Package-subdirectories&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export R_PROFILE_USER&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$XDG_CONFIG_HOME&lt;span style="color:#e6db74"&gt;/R/profile&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export R_MAKEVARS_USER&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$XDG_CONFIG_HOME&lt;span style="color:#e6db74"&gt;/R/Makevars&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export R_HISTFILE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$XDG_STATE_HOME&lt;span style="color:#e6db74"&gt;/R/history&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;$XDG_CONFIG_HOME/R/profile&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.libPaths&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;~/.local/share/R/library&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;.libPaths&lt;/span&gt;()))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The only annoyance is I can&amp;rsquo;t simply set &lt;code&gt;R_HOME_USER&lt;/code&gt; due to &lt;code&gt;.libPaths()&lt;/code&gt; located in another place. Anyway, it still works better than outdated &lt;code&gt;r-base&lt;/code&gt; package in many distros.&lt;/p&gt;
&lt;h2 id="why"&gt;Why&lt;/h2&gt;
&lt;p&gt;To have a simple life like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls -1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;projects/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls -a1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.cache/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.config/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.local/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.profile
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.ssh/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;projects/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;OCD Gospel!&lt;/p&gt;</description><category domain="/tags/">Dev</category><category domain="/tags/">File</category><category domain="/tags/">Cli</category><category domain="/tags/">Spec</category><category domain="/tags/">Index</category></item><item><title>浏览器调教指南 - 插件篇</title><link>https://blog.vinfall.com/posts/2024/08/useless-plugin/</link><pubDate>2026-08-21</pubDate><author>Vinfall</author><guid>https://blog.vinfall.com/posts/2024/08/useless-plugin/</guid><summary>兼谈你不需要的浏览器插件</summary><description>&lt;h2 id="引言"&gt;引言&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://blog.vinfall.com/posts/2024/08/browser-customize-firefox/#%E6%8F%92%E4%BB%B6"&gt;浏览器调教指南 - Firefox 篇#插件&lt;/a&gt; 提到的插件&lt;del&gt;檄文&lt;/del&gt;先行，&lt;a href="https://blog.vinfall.com/posts/2024/08/browser-customize-chromium/"&gt;浏览器调教指南 - Chromium 篇&lt;/a&gt; 也已经到位。
这两篇里我没有涉及 Firefox Container 或者通用的多 profile 方案，因为这本质上并不算「调教」，
影响不到默认的设置，只能说是「隔离」，而且是最基础也最废物的本机环境隔离。&lt;/p&gt;
&lt;p&gt;由于我启用 private browsing，退出后删除除了网站设置的全部数据，虚拟机也是 immutable disk，
一直对多 profile 方案不屑一顾，写本文搜索各种无用列表的时候才想起来还有这种方法。
简单提一句，不再多说。&lt;/p&gt;
&lt;p&gt;在前文注释我曾提到，本篇会喷各种插件推荐，并且给出更加「原生」或可靠的方案。&lt;/p&gt;
&lt;h2 id="不需要的"&gt;不需要的&lt;/h2&gt;
&lt;div class="admonition admonition-note"&gt;
&lt;div class="admonition-heading"&gt;
ℹ️
Note
&lt;/div&gt;
&lt;div class="admonition-content"&gt;
&lt;p&gt;对本节中各种插件的反面态度，前提是完全掌握『&lt;a href="https://blog.vinfall.com/categories/%E6%B5%8F%E8%A7%88%E5%99%A8%E8%B0%83%E6%95%99%E6%8C%87%E5%8D%97/"&gt;浏览器调教指南&lt;/a&gt;』，高屋建瓴。
走路都还走不顺，就想着跑马拉松，甚至盲目修炼水上漂，大概率会死得很彻底😜。
哪怕这么说，整个列表的个人色彩恐怕还是非常浓厚，我只能先送上四个字&lt;span class="hover-change"&gt;&lt;span class="hover-before"&gt;求同存异&lt;/span&gt;&lt;span class="hover-after"&gt;党同伐异&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;不知道会列多少，形式还是采取简单的 bullet list：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;HTTPS Everywhere，步入 6202 年，哪还有多少 HTTP 网站，Tor Browser 都不再预装，普通人完全可以 HTTPS-only。如果出于特殊需要不得不访问，建议单独配置白名单，忽略警告。&lt;/li&gt;
&lt;li&gt;NoScript
&lt;ul&gt;
&lt;li&gt;不需要 NoScript 并不意味着时刻启用 JavaScript，事实上你完全可以用 uBlock Origin 的 &lt;a href="https://github.com/gorhill/uBlock/wiki/Blocking-mode:-hard-mode"&gt;hard mode&lt;/a&gt; 替换 NoScript。如果你连初次配置都不想，无所谓 JavaScript，一样可以用 ubo 的 &lt;a href="https://github.com/gorhill/uBlock/wiki/Blocking-mode:-medium-mode"&gt;medium mode&lt;/a&gt; 或 &lt;a href="https://github.com/gorhill/uBlock/wiki/Blocking-mode:-easy-mode"&gt;easy mode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;为什么 ubo 是更好的选择？因为它的颗粒度更细，使用 NoScript 你无法只允许 &lt;code&gt;a.blahblah.xyz&lt;/code&gt; 而保持对于 &lt;code&gt;blahblah.xyz&lt;/code&gt; 的封锁，允许图片、视频、JavaScript 等操作也要比 ubo 繁琐。&lt;a href="https://github.com/gorhill/uMatrix"&gt;uMatrix&lt;/a&gt; 曾经是另一个替代方案，但停更多年，还是 ubo 活得最好&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Canvas Blocker，Firefox 自带这一功能（RFP, Resist Fingerprinting），Chromium 禁用 WebGL 即可。相信我，一个需要启用 WebGL 的网站可能依然是个正常网站（比如 itch.io 的很多 Unity for Web 游戏），手动放行即可，但要禁用 RFP 才能访问的网站，你大概率也不需要。&lt;/li&gt;
&lt;li&gt;WebRTC Leak Prevent，Chromium/Firefox 均可配置（&lt;code&gt;chrome://flags&lt;/code&gt; v.s. &lt;code&gt;about:config&lt;/code&gt;），不需要插件。有的人可能反驳说浏览器实现不够彻底，但 IP 是不会泄漏的，如果你的 threat model 已经到了考虑浏览器指纹 &lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt; 的程度，建议直接 Tor Browser 或者 I2P&lt;/li&gt;
&lt;li&gt;Cookie AutoDelete
&lt;ul&gt;
&lt;li&gt;都不需要 policy-templates，设置里就能配置自动删除，美中不足就是不支持 Cookie AutoDelete 那种定时删除，但我本来就设置的默认启用 private browsing + 退出删除所有 cookies，毫无影响&lt;/li&gt;
&lt;li&gt;说到 cookies，我更推荐通过 &lt;a href="https://github.com/Moustachauve/cookie-editor"&gt;cookie-editor&lt;/a&gt; 管理，可以只允许插件获取单个网站的 cookies。本来也没有多少账号需要保持登录状态，在小部分网站允许 cookies 权限之后导出即可，登录状态掉了重新登录 renew 即可&lt;/li&gt;
&lt;li&gt;引申开来，你也可以在虚拟机 A 登录并导出 cookies，然后在虚拟机 B 导入 &lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;
&lt;ul&gt;
&lt;li&gt;如此一来，连输入环节都省了，虚拟机 B 根本不可能&lt;em&gt;在浏览器层面&lt;/em&gt;获取对应账号的密码&lt;/li&gt;
&lt;li&gt;密码管理器 + 插件毕竟需要传输密码到浏览器，还需要将数据库导入虚拟机 B，平添风险&lt;/li&gt;
&lt;li&gt;何况有的网站不允许这么操作，只能自动填充，这安全性只能说比手动输入强一点🤏&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &amp;amp; Clean，同上，设置即可配置，装个插件纯属多此一举&lt;/li&gt;
&lt;li&gt;Proxy Switchy Omega/ZeroOmega
&lt;ul&gt;
&lt;li&gt;是的，99% 的情况下你&lt;mark&gt;不需要&lt;/mark&gt;额外的代理配置插件，现有的 GeoIP/GeoSite 库和路由规则足以涵盖绝大部分使用场景，仅需几行 DIY 规则，这东西作用非常局限，我都想不通这大规模滥用的局面是怎么造成的&lt;/li&gt;
&lt;li&gt;先不说 Edge 商店满天飞的带毒版本，Chromium 也已经停止支持 ManifestV2 扩展，基于 MV3 的 fork &lt;a href="https://github.com/zero-peak/ZeroOmega"&gt;ZeroOmega&lt;/a&gt; 也是 bug 一大堆&lt;/li&gt;
&lt;li&gt;如果你还&lt;span class="hover-change"&gt;&lt;span class="hover-before"&gt;保持怀疑&lt;/span&gt;&lt;span class="hover-after"&gt;坚持嘴硬&lt;/span&gt;&lt;/span&gt;，有个简单粗暴的判断方法：Kali, WireShark, Fiddler, PAC, privoxy, Selenium, Playwright 如果你一个都不认识，那就肯定不需要🤷&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Tampermonkey，&lt;a href="https://github.com/violentmonkey/violentmonkey"&gt;violentmonkey&lt;/a&gt;，你不需要闭源插件&lt;/li&gt;
&lt;li&gt;搜索引擎插件，通过 policy-templates 同样可以设置，不要相信搜索引擎说的「更安全、更多功能」，锁定默认搜索引擎和所谓「优化」的本质和我前文的调教手段殊途同归，大可不必&lt;/li&gt;
&lt;li&gt;Flash 插件，&lt;a href="https://www.palemoon.org"&gt;Pale Moon&lt;/a&gt; + &lt;a href="https://gitlab.com/cleanflash/installer"&gt;CleanFlashinstaller&lt;/a&gt; + &lt;a href="https://github.com/darktohka/clean-flash-builds"&gt;clean-flash-builds&lt;/a&gt; 默秒全，详见 &lt;a href="https://blog.vinfall.com/posts/2023/09/zen-of-windows/#%E6%B5%8F%E8%A7%88%E5%99%A8"&gt;我的 Windows 软件之道#浏览器&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;大部分下载插件（下载辅助、资源嗅探等等）
&lt;ul&gt;
&lt;li&gt;首先是 HLS/M3U8 类型的视频流，毕竟这种可能最难下载 &lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;，用户脚本注入能解决 99% 的网站，剩下那 1%，我相信下载插件也搞不定，需要手动逆向。&lt;/li&gt;
&lt;li&gt;其次，对于常见的图片/视频站，已经有足够成熟的命令行解决方案，浏览器插件完全是更弱的下级替代。&lt;a href="https://github.com/mikf/gallery-dl"&gt;gallery-dl&lt;/a&gt;, &lt;a href="https://github.com/yt-dlp/yt-dlp"&gt;yt-dlp&lt;/a&gt; 和 &lt;a href="https://github.com/soimort/you-get"&gt;you-get&lt;/a&gt; 足以解决大部分网站，如果不行，就配上登录账号的 cookies。&lt;/li&gt;
&lt;li&gt;再者，对于上面三驾马车也搞不定的网站，一般就是套用各种模板的视频/图包站，网页资源的链接基本都包含在源码中，写个爬虫解析网页批量抓取也不是什么难事。&lt;/li&gt;
&lt;li&gt;如果连爬虫都懒得写，也有更简单的方法：W3M + wget
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;w3m $URL&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Shift + L（显示网页上的全部链接），另存为文件，比如 &lt;code&gt;links.txt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;手动筛选一下需要下载的链接，如果 URL 使用相对路径，三句话让 LLM 写个拼接脚本&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wget -i links.txt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;结束&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Stylus 和所有特定网站的定制化插件，它能做到的，用户脚本和 &lt;a href="https://blog.vinfall.com/posts/2024/08/browser-customize-firefox/#css"&gt;Firefox userContent.css&lt;/a&gt; 一样能做到，它做不到的，policy-templates 和 Firefox userChrome.css 还是能做到&lt;/li&gt;
&lt;li&gt;「工具箱」类型的插件 &lt;sup id="fnref:4"&gt;&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref"&gt;4&lt;/a&gt;&lt;/sup&gt;
&lt;ul&gt;
&lt;li&gt;这些工具完全可以从浏览器中剥离出来独立运行，何必安装插件徒增风险，现成脚本或者自行部署的开源替代，一抓一大把。&lt;/li&gt;
&lt;li&gt;何况很多「工具箱」、「脚手架」确实不干净，源码一目了然却盗取 cookies 的脚本都一大把，权限更大的插件更是劣迹斑斑。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;所有需要登录才能使用的插件 &lt;sup id="fnref:5"&gt;&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref"&gt;5&lt;/a&gt;&lt;/sup&gt;，原因同上&lt;/li&gt;
&lt;li&gt;密码生成器（不是管理器配套插件），没审查过代码你压根不知道这个「随机」有多随机，更别提人家会不会顺手把 URL 和账号密码传到自家服务器，这种活还是交给&lt;strong&gt;离线&lt;/strong&gt;的密码管理器 &lt;sup id="fnref:6"&gt;&lt;a href="#fn:6" class="footnote-ref" role="doc-noteref"&gt;6&lt;/a&gt;&lt;/sup&gt; 才靠谱&lt;/li&gt;
&lt;li&gt;单独的两步验证（2FA）插件 &lt;sup id="fnref:7"&gt;&lt;a href="#fn:7" class="footnote-ref" role="doc-noteref"&gt;7&lt;/a&gt;&lt;/sup&gt;
&lt;ul&gt;
&lt;li&gt;不局限于浏览器插件，我认为 2FA 本身就应该和密码管理放在一个篮子里。如果密码管理器连 2FA 功能都不提供，还是早点弃用比较好&lt;/li&gt;
&lt;li&gt;这点非常有争议，但个人是这么认为的，稍微解释一下
&lt;ul&gt;
&lt;li&gt;理论上，通过分离账号密码和 2FA，可以保证 &lt;a href="https://wikipedia.org/wiki/Alice_and_Bob"&gt;邪恶的 Eve&lt;/a&gt; 在获取你的账号密码之后不能直接登录，相当于上了额外一道锁&lt;/li&gt;
&lt;li&gt;事实上，更有可能发生的是 &lt;a href="https://zh.wikipedia.org/wiki/%E5%8D%95%E7%82%B9%E6%95%85%E9%9A%9C"&gt;单点故障&lt;/a&gt;，密码管理器或 2FA 应用，任何一个炸了都会导致你失去开启 2FA 的全部账号 &lt;sup id="fnref:8"&gt;&lt;a href="#fn:8" class="footnote-ref" role="doc-noteref"&gt;8&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;而且借助密码管理器 + 浏览器插件，你也可以自动填充 2FA，操作步骤和分离是差不多的&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;所有的比价插件，脚本不香吗？&lt;/li&gt;
&lt;li&gt;所有的钱包插件，把金融账号/虚拟货币交给一天成千上万个网络请求，一年几十个 0day 的浏览器？&lt;/li&gt;
&lt;li&gt;所有的同步插件，我不需要连备份/恢复功能都没有的插件，而设置全都可以定制化，密码使用密码管理器，同步和账号功能毫无存在价值&lt;/li&gt;
&lt;li&gt;所有的标签、主页、启动器插件，如果你有标签管理障碍，先解决的应该是自己而不是标签🙄&lt;/li&gt;
&lt;li&gt;插件管理插件，如果完全遵守本文，符合要求，功能还不重合的插件只有个位数，管理也无从说起&lt;/li&gt;
&lt;li&gt;所有的书签插件
&lt;ul&gt;
&lt;li&gt;浏览器书签只能在 GUI 使用，对于活在命令行的人，&lt;a href="https://github.com/jarun/buku"&gt;buku&lt;/a&gt; 要更合适&lt;/li&gt;
&lt;li&gt;哪怕不使用命令行，一个简单的 bookmarks.html 也能秒杀所有书签插件……&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="插件标准"&gt;插件标准&lt;/h2&gt;
&lt;p&gt;上面的列表七七八八已经说得差不多了，这里就随便列几点，我也不一定严格遵守，最终还是得看实用性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;开源，最好是自由软件&lt;/li&gt;
&lt;li&gt;用户足够多，这样才能及时发现潜在问题，具体数目得根据插件的使用场景判断，小众领域 100 stars 就非常之多，而烂大街的广告过滤，还是得 uBlock Origin 这种数量级才算得上可靠&lt;/li&gt;
&lt;li&gt;维护超过 2 年，很多插件更新不到三个版本就弃坑，没有长期支持，出了 bug 也没人管，新兴领域这点会适当宽容&lt;/li&gt;
&lt;li&gt;提供备份/恢复配置的功能，WebDAV 同步等等只能算 bonus&lt;/li&gt;
&lt;li&gt;无广告，并且不需要账号即可体验完整功能&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="我使用的插件"&gt;我使用的插件&lt;/h2&gt;
&lt;p&gt;「&lt;a href="https://blog.vinfall.com/categories/%E6%B5%8F%E8%A7%88%E5%99%A8%E8%B0%83%E6%95%99%E6%8C%87%E5%8D%97/"&gt;浏览器调教指南&lt;/a&gt;」系列三篇文章透露了不少，其实都能推测出来：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cookie-Editor，跨 VM 登录&lt;/li&gt;
&lt;li&gt;Dark Reader，其实可以用用户脚本或 &lt;a href="https://blog.vinfall.com/posts/2024/08/browser-customize-firefox/#css"&gt;CSS&lt;/a&gt; 解决，但是我懒&lt;/li&gt;
&lt;li&gt;KeePassXC-Browser，只在「登录机」使用，其他机器导入 cookie 即可&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.localcdn.org"&gt;LocalCDN&lt;/a&gt;，源自停更多年的 Decentraleyes，用本地资源替换 CDN，减少请求加快网页加载，这款插件也是假冒伪劣高发区，安装时注意辨别&lt;/li&gt;
&lt;li&gt;uBlock Origin&lt;/li&gt;
&lt;li&gt;Violentmonkey&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/gildas-lormeau/SingleFile"&gt;SingleFile&lt;/a&gt;，保存&lt;strong&gt;完整网页&lt;/strong&gt;（包括图片、CSS、字体等资源）为单 HTML，用作离线归档，有些网站需要 &lt;a href="https://github.com/gildas-lormeau/SingleFile/blob/master/faq.md#why-arent-images-saved-on-sites-like-sspaicom-or-weibocom"&gt;设置 referer&lt;/a&gt;，也有 MV3 版本，另有 &lt;a href="https://github.com/gildas-lormeau/single-file-cli"&gt;single-file-cli&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Zotero Connector，联动 Zotero，不做研究就不常用&lt;/li&gt;
&lt;li&gt;其他一些特定网站的增强插件，其实可以通过用户脚本解决，上面喷了那么多这里我就不举反例了&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="我使用的脚本"&gt;我使用的脚本&lt;/h2&gt;
&lt;p&gt;由于安装时会弹出确认框，源码不加混淆则一览无余，建议哪怕完全不懂代码也要塞给 LLM 问问漏洞。
以及脚本如果出现用下面这种方式匹配的，99.99% 的情况你需要重新考虑使用价值和作者的开发水平：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// @match *://*/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;前几个月进行基础设施迁移的时候大幅重构过，现在基本只用自己写的，使用场景很局限，不足为外人道，简单列一下略微通用的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/vinta/pangu.js"&gt;pangu.js&lt;/a&gt;，参考停更的 user.js 自己搓了脚本，不需要插件&lt;/li&gt;
&lt;li&gt;参考 &lt;a href="https://libredirect.manerakai.com"&gt;LibRedirect&lt;/a&gt; 写的脚本，当然功能性要差得多，也没有均衡负载，实在懒得写也可以装插件&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/OldPanda/Open-the-F-king-URL-Right-Now"&gt;Open-the-F-king-URL-Right-Now&lt;/a&gt;，外链跳转，由于用户脚本权限不足，体验没有插件好，够用&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codeberg.org/Amm0ni4/bypass-all-shortlinks-debloated"&gt;Bypass All Shortlinks Debloated&lt;/a&gt;，外链跳转，针对国外网站&lt;/li&gt;
&lt;li&gt;Skip Redirect Inplace，上面两个需要实际点击才能跳转外链，我写的这个直接替换文内链接，避开了愚蠢的外链提醒，只作为上面两个脚本的补充&lt;/li&gt;
&lt;li&gt;CNM.R18 和 COK.R18，通过模拟网页点击、补全验证参数和注入 cookie 绕过年龄验证。可能有的人会质疑这种脚本的合规性，但我的理解是用户在点击安装脚本弹窗的确认按钮时，就事先同意了所有支持网站的年龄验证，而且随时可以通过卸载脚本的方式撤销同意，合理合法&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cilxe/JavaScriptProjects/blob/main/Clean-Tracking-URLs.js"&gt;Clean-Tracking-URLs&lt;/a&gt; 或者 &lt;a href="https://dmscode.github.io/Link-cleaner/"&gt;链接地址洗白白&lt;/a&gt;，去除追踪参数，由于功能性质都用了 &lt;code&gt;// @match *://*/*&lt;/code&gt; 这种匹配，是否属于那 0.01% 的特殊情况看个人需求&lt;/li&gt;
&lt;li&gt;Show Original Picture，打开图片时自动跳转高清原图，数量多了还是 gallery-dl 方便&lt;/li&gt;
&lt;li&gt;上文提到的 M3U8、图片批量下载用户脚本&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;还有一些特定网站的，CnGal/VNDB 就不介绍了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;京东
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://greasyfork.org/zh-CN/scripts/486915-%E4%BA%AC%E4%B8%9C%E5%95%86%E5%93%81%E5%8F%82%E6%95%B0%E5%AF%B9%E6%AF%94%E5%B7%A5%E5%85%B7"&gt;京东商品参数对比工具&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Vinfall/UserScripts#jd-to-beancount"&gt;Beancount 账单生成&lt;/a&gt;，我基于前人脚本修改的版本，太过小众，等哪天想写 Beancount 系列再详细说说&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;BiliBili，&lt;a href="https://github.com/the1812/Bilibili-Evolved"&gt;Bilibili-Evolved&lt;/a&gt;，也有类似 Steam 评价过滤的用户/评论过滤脚本，但是不登录叔叔连倍速和评论都不舍得让你用，本来用得少也无所谓&lt;/li&gt;
&lt;li&gt;Steam 增强
&lt;ul&gt;
&lt;li&gt;Steam 评价过滤，基于关键词匹配，隐藏求中文摸猫猫买头像等无脑评论&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sffxzzp/SteamChineseChecker"&gt;SteamChineseChecker&lt;/a&gt;，在商店页面显示汉化补丁情况&lt;/li&gt;
&lt;li&gt;&lt;a href="https://greasyfork.org/zh-CN/scripts/432190-fast-add-cart"&gt;Steam 快速添加购物车&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://greasyfork.org/en/scripts/391546-steambundlepricesassistant"&gt;SteamBundlePricesAssistant&lt;/a&gt;，部分支持补齐的捆绑包，单独购买其中一部再补齐价格会更低，用于在捆绑包界面计算折扣，判断这种情况&lt;/li&gt;
&lt;li&gt;&lt;a href="https://greasyfork.org/en/scripts/456166-vndb-steam-enhancer"&gt;VNDB Steam Enhancer&lt;/a&gt;，Steam 显示 VNDB 数据，我也照猫画虎写过 CnGal2Steam&lt;/li&gt;
&lt;li&gt;Steam EA Date，游戏脱离抢先体验后会优先显示正式发行日期，而最早的抢先体验日期塞在页面的隐蔽角落，脚本会并行显示两个日期，便于识别有欺诈嫌疑的开发商&lt;/li&gt;
&lt;li&gt;&lt;a href="https://greasyfork.org/zh-CN/scripts/368597-steam-wishlist-copy"&gt;Steam Wishlist Copy&lt;/a&gt;，要说有用其实也没什么用，我只用作新号初始化愿望单&lt;/li&gt;
&lt;li&gt;&lt;a href="https://greasyfork.org/zh-CN/scripts/490371-steam%E8%B5%9B%E5%8D%9A%E7%88%B6%E5%AD%90%E9%89%B4%E5%AE%9A-%E6%B8%B8%E6%88%8F%E5%BA%93%E8%93%9D%E7%BB%BF-%E4%B8%80%E9%94%AE%E7%A7%81%E5%AF%86-%E5%BA%93%E5%AD%98%E4%BB%B7%E5%80%BC%E7%BB%9F%E8%AE%A1"&gt;Steam 赛博父子鉴定 (游戏库蓝绿 | 一键私密 | 库存价值统计)&lt;/a&gt;，家庭组专用&lt;/li&gt;
&lt;li&gt;折扣换算、一键卖卡、卡牌匹配等不再一一列举&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="结语"&gt;结语&lt;/h2&gt;
&lt;p&gt;至此本系列就告一段落，虽然早就习惯用各种企业批量部署的方式对浏览器进行调教，但写一个系列的想法还是源自 Chromium 使用 policy-templates 允许 ManifestV2 扩展。&lt;/p&gt;
&lt;p&gt;&lt;del&gt;一个人的命运虽然要考虑历史的进程，但势必少不了自我奋斗，浏览器的调教也是如此。&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;各种标准和浏览器本身都在随着互联网在不断发展，本系列介绍的方法只能说适用于当前的环境。
Netscape Navigator 和 Internet Explorer 互搏如今看来已经是遥远的历史，
&lt;a href="http://xanadu.com/"&gt;Project Xanadu®&lt;/a&gt;、&lt;a href="https://wikipedia.org/wiki/Gopher_%28protocol%29"&gt;Gopher&lt;/a&gt; 更是无人问津。不知道今天的互联网形式还能存在多久，且行且珍惜。&lt;/p&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;说句题外话，浏览器指纹这东西很多时候就是图一乐，特征明显只能让人分析出「谁是谁」，并不能直接反推得出「你是你」。独特的浏览器指纹也就是「安装 ubo、常看 HN、使用 Matrix 的网民 A」、「安装十款比价插件、常逛 OnlyFans、天天用 Tinder/Instagram 的网民 B」这种程度。由于浏览器指纹本身很容易修改，「指纹」一词颇具误导意味。毕竟一般人类对于指纹/虹膜这类生物识别信息的泄漏毫无办法，总不能砍手指戳眼睛（又不是 yakuza），网民 A/B 可能只是同一个浏览器的不同 profile……&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;由于本文旨在吐槽不必要的浏览器插件，这里不做深入探讨，感兴趣可以自行阅读 &lt;a href="https://program-think.blogspot.com/2016/12/howto-prevent-hacker-attack-8.html"&gt;如何防止黑客入侵 (8)：物理隔离的几种玩法&lt;/a&gt;，该操作（文中的「招数 4」）已经优化为物理隔离 3 型（导出 cookies 后传输并不需要交换存储介质）&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;「难」也只是相对的，下载几百个 TS 片段本身毫无难度（哪怕采用 AES 加密也是如此），难的永远都是合并&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;这里说的是与「浏览器」本身关联不紧密的插件，像网页调试、请求模拟之类的开发辅助插件，脱离浏览器就是无稽之谈（换成 headless 肯定不算脱离= =），「不需要」也无从说起&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:5"&gt;
&lt;p&gt;SteamDB 这种功能拓展类型的算半个，不过插件的大部分功能用户脚本确实也能实现╮(￣▽￣)╭&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:6"&gt;
&lt;p&gt;密码管理器最好还会定期委托第三方进行代码审计，当然只要开源理论上谁都能检查，但密码学毕竟不是前端，不是什么阿猫阿狗都能学会&amp;#160;&lt;a href="#fnref:6" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:7"&gt;
&lt;p&gt;顺带一提，Steam 的令牌手机验证器，其实就是魔改 &lt;a href="https://en.wikipedia.org/wiki/Time-based_one-time_password"&gt;TOTP&lt;/a&gt;（即 &lt;a href="https://datatracker.ietf.org/doc/html/rfc6238"&gt;RFC 6238&lt;/a&gt;），但实际安全性并没有比原始 TOTP 更强= =恰恰相反，由于 Steam 的缓存机制和傲慢（不积极回复漏洞提交），盗号方式五花八门，建议早死早超生。当然，不管怎么样都比在 4202 年还坚持只能用邮箱当两步验证的 GOG 要好得多……&amp;#160;&lt;a href="#fnref:7" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:8"&gt;
&lt;p&gt;这里默认没有单独保存恢复代码。一些文章中可能推荐你把它们打印出来，但我感觉这保管起来也挺麻烦= =而且账号多的话时不时要更新，每次都得撕碎 + 化学浸泡 + 焚烧想想都累&amp;#160;&lt;a href="#fnref:8" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category domain="/tags/">Browser</category><category domain="/tags/">Firefox</category><category domain="/tags/">Chrome</category><category domain="/tags/">Customize</category><category domain="/tags/">Plugin</category><category domain="/tags/">Dev</category><category domain="/tags/">Js</category></item><item><title>浏览器调教指南 - Firefox 篇</title><link>https://blog.vinfall.com/posts/2024/08/browser-customize-firefox/</link><pubDate>2026-08-21</pubDate><author>Vinfall</author><guid>https://blog.vinfall.com/posts/2024/08/browser-customize-firefox/</guid><summary>Firefox 调教日记，从火狐到火化</summary><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;前几天写 &lt;a href="https://blog.vinfall.com/posts/2024/08/text-editor/"&gt;文本编辑器的基础方程式&lt;/a&gt; 顺带更新了 &lt;a href="https://blog.vinfall.com/posts/2023/09/zen-of-windows/#%E6%8E%A8%E8%8D%90"&gt;我的 Windows 软件之道#推荐&lt;/a&gt; 部分内容，介绍使用 Flash 插件的现代方案以及浏览器的调教大纲，这篇文章会略微详细地讲讲这部分内容。&lt;/p&gt;
&lt;h2 id="定义"&gt;定义&lt;/h2&gt;
&lt;p&gt;这里的「浏览器」特指桌面端，移动端、TV、车机系统等等各凭本事，不予介绍。
同样，本文仅介绍主流浏览器（&lt;a href="https://gs.statcounter.com/browser-market-share/desktop/worldwide"&gt;Statcounter&lt;/a&gt; 市场占有率数据高于 5%），即 Chrome/Chromium, MSEdge, Firefox ESR&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;p&gt;由于 Safari 就是 Apple 写着玩的，完全不考虑企业市场，「调教」也无从说起。
Opera 曾经使用 Presto 还能聊一聊，如今已经是 Blink (Chromium) 的形状就没什么意思。
Vivaldi, Brave, Yandex 之类的套壳就更没有讨论的必要，自行替换代入关键词即可。&lt;/p&gt;
&lt;p&gt;大致方案已经记录在 &lt;a href="https://blog.vinfall.com/posts/2023/09/zen-of-windows/#%E6%8E%A8%E8%8D%90"&gt;我的 Windows 软件之道#推荐&lt;/a&gt;，这里不再赘述，直接上内容。
由于每个人的需求都不一样，我就不贴自己的定制化配置了。&lt;/p&gt;
&lt;p&gt;考虑到全文长度，先分割出一篇 Firefox，后续再补 Chrome/Chromium 和 MSEdge。&lt;/p&gt;
&lt;h2 id="firefox-esr"&gt;Firefox ESR&lt;/h2&gt;
&lt;p&gt;为什么特地指定 ESR，因为 policy-templates 部分策略仅适用于 ESR。&lt;/p&gt;
&lt;p&gt;虽然名叫 Extended Support Release，其实根据 &lt;a href="https://whattrainisitnow.com/release/?version=esr"&gt;发行时间&lt;/a&gt; ESR 大版本一年更新一次，并不至于像 Debian stable 的软件包那样普遍落后 2 年。&lt;/p&gt;
&lt;p&gt;另一方面，常规版本无法运行未签名扩展，哪怕是你自己开发，并不上架商店仅私人使用也要注册 Mozilla 账号并提交申请……而 Beta/Developer 版本太新，不适合日常使用，&lt;a href="https://wiki.mozilla.org/Add-ons/Extension_Signing#Unbranded_Builds"&gt;Unbranded Builds&lt;/a&gt; 则只是允许未签名扩展。&lt;/p&gt;
&lt;h2 id="hotkey"&gt;Hotkey&lt;/h2&gt;
&lt;p&gt;Firefox 147.0.2+ 和 ESR 153+ 都实验性支持通过 &lt;code&gt;about:keyboard&lt;/code&gt; 自定义快捷键，比此前通过 Autoconfig 配置简化很多，很适合当开胃菜。&lt;/p&gt;
&lt;p&gt;点开后搜索 Download，将 Ctrl + Shift + Y 修改为正常的 Ctrl + J，解决因 &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=374189#c17"&gt;17 年前的&lt;em&gt;解决&lt;/em&gt;方案&lt;/a&gt; 引入的奇葩默认值，&lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1551057"&gt;相关 bug&lt;/a&gt; 也已经存活 7 年……&lt;/p&gt;
&lt;h2 id="userjs"&gt;user.js&lt;/h2&gt;
&lt;p&gt;如果尝试定制过 Firefox，或多或少都会接触到 &lt;code&gt;about:config&lt;/code&gt; 这个 URL，在这里可以调节成百上千个浏览器的细节，当然，每次重装都需要手动调整费时费力，肯定有个自动化的工具。在 Firefox 中，这个工具就是 user.js。&lt;/p&gt;
&lt;p&gt;详细的使用就不介绍了，本文的重点仅在方法论，关联阅读：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://program-think.blogspot.com/2019/07/Customize-Firefox.html"&gt;扫盲 Firefox 定制——从“user.js”到“omni.ja”&lt;/a&gt;&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/arkenfox/user.js/wiki/1.1-to-arkenfox-or-not"&gt;To Arkenfox or Not&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;目前使用 &lt;a href="https://github.com/arkenfox/user.js"&gt;arkenfox/user.js&lt;/a&gt;，第一次将大部分内容检查一遍后，把自定义的部分写到 &lt;code&gt;user-overrides.js&lt;/code&gt; ，部署、更新、备份和清理失效配置都很方便。未来可能转换到 &lt;a href="https://github.com/yokoffing/Betterfox"&gt;Betterfox&lt;/a&gt;，但万变不离其宗，原理都是一样的。&lt;/p&gt;
&lt;p&gt;有多简单？下面是我目前的 user.js 更新流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;查看 release note 里的 diffs&lt;/li&gt;
&lt;li&gt;（可选）手动增删 &lt;code&gt;user-overrides.js&lt;/code&gt; 里的配置&lt;/li&gt;
&lt;li&gt;在 profile 目录运行 &lt;code&gt;updater.bat&lt;/code&gt;/&lt;code&gt;updater.sh&lt;/code&gt;，随后运行 &lt;code&gt;pref-cleaner.sh&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;（可选）备份 &lt;code&gt;user-overrides.js&lt;/code&gt; 配置到 backup 文件夹&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;2 和 4 都是可选的，甚至整个流程都可以通过脚本自动化，更新一遍半分钟都不到。
参考上文提到的发行时间，基本一个月一次，初始化之后一年只需要泡两杯泡面的时间，
即可保证 &lt;code&gt;about:config&lt;/code&gt; 的完全定制化。&lt;/p&gt;
&lt;p&gt;user.js 虽然好用，但 Mozilla 三天两头作妖，时不时偷偷在新版本塞点东西。当然这种无法提前预知的情况没什么办法，但对于更新修改默认设置的情况，可以通过 autoconfig 锁定/清空默认配置。上面 program-think 的那篇文章也有介绍，不再赘述。&lt;/p&gt;
&lt;h2 id="css"&gt;CSS&lt;/h2&gt;
&lt;p&gt;除了 user.js，Firefox 还支持通过 CSS 定制 UI。
首先需要在 &lt;code&gt;about:config&lt;/code&gt; 或者 user.js / autoconfig 中启用 &lt;code&gt;toolkit.legacyUserProfileCustomizations.stylesheets&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;userChrome.css 定制 Firefox 自身，注意这里的 &lt;code&gt;Chrome&lt;/code&gt; 一词起源其实比 Chrome 浏览器还要久远，先来后到也是人家先来的= =&lt;/li&gt;
&lt;li&gt;userContent.css 定制浏览网站的界面，就和各种冠名「净化」、「清理」的用户脚本（UserScript，也叫 user.js，注意和上文配置 &lt;code&gt;about:config&lt;/code&gt; 的同名文件进行区分）一样&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;同样，详细使用就不介绍了，自行阅读 &lt;a href="https://program-think.blogspot.com/2016/10/custom-firefox-theme-without-extension.html"&gt;无需任何插件或扩展，定制 Firefox 外观&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;简单列几个参考资源：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;del&gt;&lt;a href="https://github.com/Timvde/UserChrome-Tweaks"&gt;UserChrome-Tweaks&lt;/a&gt;&lt;/del&gt; 多年没更新，有一部分至今仍可用&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/MrOtherGuy/firefox-csshacks"&gt;firefox-csshacks&lt;/a&gt;，仍在更新，另有 &lt;a href="https://mrotherguy.github.io/firefox-csshacks/"&gt;网页版筛选器&lt;/a&gt;，查看更方便&lt;/li&gt;
&lt;li&gt;&lt;a href="https://old.reddit.com/r/FirefoxCSS/"&gt;r/FirefoxCSS&lt;/a&gt;，Reddit 板块&lt;/li&gt;
&lt;li&gt;&lt;a href="https://userstyles.org/"&gt;Userstyles.org&lt;/a&gt;，Stylish 之类的插件用的就是这种，Firefox 直接就能定制，复制到 CSS 重启即可，少装一个插件&lt;/li&gt;
&lt;li&gt;上文提到的各种用户脚本，使用 CSS 就能少装几个脚本&lt;/li&gt;
&lt;li&gt;uBlock Origin，这是我目前 CSS 的主要来源，虽然 ubo 更通用，但很多网站我根本不会用 Chromium 打开，直接写进 CSS 未尝不可，还能简化 ubo 规则。像我 Firefox ubo 自定义规则只有寥寥 20+（当然，订阅规则有很多）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此外，为了便于管理，建议参考 &lt;a href="https://github.com/MrOtherGuy/firefox-csshacks#usage"&gt;firefox-csshacks#Usage&lt;/a&gt; 的做法，将不同规则分离成单独的文件，然后统一在 CSS 中导入：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* userChrome.css */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#f92672"&gt;url&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;chrome&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;tab_close_button_always_on_hover&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;css&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#f92672"&gt;url&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;chrome&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;tab_loading_progress_throbber&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;css&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#f92672"&gt;url&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;chrome&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;button_effect_scale_onclick&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;css&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;理所当然，导入顺序也会影响效果，详细内容请自行了解。&lt;/p&gt;
&lt;h2 id="policy-templates"&gt;Policy Templates&lt;/h2&gt;
&lt;p&gt;终于聊到 &lt;a href="https://firefox-admin-docs.mozilla.org/reference/policies/"&gt;policy-templates&lt;/a&gt;，为什么不叫「策略模板」，因为人家只有英文网站&lt;del&gt;这都看不懂就别配置了&lt;/del&gt;。Firefox 这方面基本就是照抄 Chrome，不过配置项要少得多。但你能通过设置配置的东西，policy-templates 基本都有涉及，不需要每次重装都点点点。&lt;/p&gt;
&lt;p&gt;这东西的目标群体大多是企业用户，感觉付费支持的多，所以网上介绍的文章也不多，简单提几点，后文在 Chrome policy template 还会介绍。&lt;/p&gt;
&lt;p&gt;Firefox 的 policy-templates 相比于 Chrome 有一点非常好，就是跨平台，一个 &lt;code&gt;policies.json&lt;/code&gt; 可以通用，Linux 配置到 &lt;code&gt;/etc/firefox/policies&lt;/code&gt;&lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;，Windows 在 &lt;code&gt;firefox.exe&lt;/code&gt; 同级目录创建 &lt;code&gt;distribution&lt;/code&gt; 即可。&lt;/p&gt;
&lt;p&gt;不像 Chrome，Linux 用 JSON，Windows 用注册表或组策略 &lt;sup id="fnref:4"&gt;&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref"&gt;4&lt;/a&gt;&lt;/sup&gt;，macOS 又用 plist，不够通用，牵一发而动全身。&lt;/p&gt;
&lt;p&gt;注意 &lt;code&gt;policies.json&lt;/code&gt; 的 EOL 需要设置为 CRLF，哪怕在 GNU/Linux 也是一样= =
配置结果可以在 about:policies 查看，无报错即一切正常。
此外 JSON 不能写注释，这点比较坑，Chrome 是可以的。&lt;/p&gt;
&lt;h2 id="示例"&gt;示例&lt;/h2&gt;
&lt;p&gt;下面根据我的部分配置文件举几个🌰🌰🌰，介绍一下 policy-templates 的用法。&lt;/p&gt;
&lt;p&gt;先来个简单的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;由于我始终启用 HTTPS-only 模式，HTTP 网站（虽然这里只是懒得配置 SSL 的内网 mDNS 设备）会弹警告，配置策略绕过，普通网站不写端口当然也可以 &lt;sup id="fnref:5"&gt;&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref"&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;禁止导入默认的 Mozilla 书签&lt;/li&gt;
&lt;li&gt;禁用搜索建议（就是在&lt;em&gt;搜索框&lt;/em&gt;输入就会自动发送文本内容，然后返回结果），不影响在&lt;em&gt;搜索引擎页面&lt;/em&gt;的搜索建议功能（二者不一样，你细品）&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;policies&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;HttpAllowlist&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;http://redump.org&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;http://rpi.local:3000/&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;http://rpi.local:8000/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;NoDefaultBookmarks&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;SearchSuggestEnabled&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后搞点复杂的，通过 &lt;a href="https://firefox-admin-docs.mozilla.org/reference/policies/extensionsettings/"&gt;ExtensionSettings&lt;/a&gt; 配置插件 &lt;sup id="fnref:6"&gt;&lt;a href="#fn:6" class="footnote-ref" role="doc-noteref"&gt;6&lt;/a&gt;&lt;/sup&gt;，一点说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;卸载自带的 DuckDuckGo&lt;/li&gt;
&lt;li&gt;强制安装 uBlock Origin，并且不能卸载不能禁用（可以在具体网站上停用）&lt;/li&gt;
&lt;li&gt;&lt;del&gt;注意如果访问 add-ons for Firefox，会发现插件下载地址是带版本的 URL (e.g. &lt;code&gt;https://addons.mozilla.org/firefox/downloads/file/4328681/ublock_origin-1.59.0.xpi&lt;/code&gt;)，但其实可以用最新版本插件的直链 (&lt;code&gt;https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi&lt;/code&gt;)，具体的 URI 可以访问插件页面获取&lt;/del&gt; 153+ 安装官方插件可以只写 Addon ID 不写 &lt;code&gt;install_url&lt;/code&gt;，第三方还是要写的&lt;/li&gt;
&lt;li&gt;部分地区的商店（e.g. 谋智中国）不提供 uBlock Origin，可以使用 GitHub release 的 URL 安装（e.g. &lt;code&gt;https://github.com/gorhill/uBlock/releases/download/1.59.0/uBlock0_1.59.0.firefox.signed.xpi&lt;/code&gt;），但是这样就是静态 URL，需要安装后手动更新，或者时不时更新 &lt;code&gt;policies.json&lt;/code&gt; 中的版本，不推荐&lt;/li&gt;
&lt;li&gt;Addon ID 见 &lt;code&gt;about:support&lt;/code&gt; 页面的 Add-ons，这里特地用 LocalCDN 举例，说明不一定都是正常的邮箱名，开发者可以自己配置，或者使用随机生成的 UUID&lt;/li&gt;
&lt;li&gt;从第三方安装插件也是可以的，这里是 Zotero Connector&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;policies&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;ExtensionSettings&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;ddg@search.mozilla.org&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;installation_mode&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;blocked&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;uBlock0@raymondhill.net&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;installation_mode&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;force_installed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;zotero@chnm.gmu.edu&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;install_url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;https://download.zotero.org/connector/firefox/release/Zotero_Connector-5.0.144.xpi&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;installation_mode&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;normal_installed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;{b86e4813-687a-43e6-ab65-0bde4ab75758}&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;install_url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;https://addons.mozilla.org/firefox/downloads/latest/localcdn-fork-of-decentraleyes/latest.xpi&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;installation_mode&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;force_installed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着来个亿点点复杂的，通过 &lt;a href="https://firefox-admin-docs.mozilla.org/reference/policies/searchengines/"&gt;SearchEngines&lt;/a&gt; 配置搜索引擎：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;移除自带的搜索引擎 &lt;sup id="fnref:7"&gt;&lt;a href="#fn:7" class="footnote-ref" role="doc-noteref"&gt;7&lt;/a&gt;&lt;/sup&gt;，配置默认搜索引擎为自定义的 DuckDuckGoLite&lt;/li&gt;
&lt;li&gt;对于大部分有搜索功能的网站（不说人话就是，适配了 OpenSearch 的网站），Firefox 本就支持添加为搜索引擎，这点比 Chrome 好用很多，但定制要配置的参数也比 Chrome 多得多&lt;/li&gt;
&lt;li&gt;所以这些 technical 的信息怎么来的呢，其实都保存在 &lt;code&gt;~/.config/mozilla/firefox/xxx.default/search.json.mozlz4&lt;/code&gt;，然鹅这是压缩包，不能直接打开，经过这样那样的搜索，找到 &lt;a href="https://github.com/jusw85/mozlz4"&gt;mozlz4&lt;/a&gt;，下载二进制，解压打开，然后复制粘贴即可&lt;/li&gt;
&lt;li&gt;当然也有正常的方式，就是在网站的 sitemap 寻找上面提到的 &lt;code&gt;opensearch.xml&lt;/code&gt;（e.g. &lt;a href="https://vndb.org/opensearch.xml"&gt;VNDB&lt;/a&gt;, &lt;a href="https://github.com/benbusby/whoogle-search/blob/main/app/templates/opensearch.xml"&gt;Whoogle&lt;/a&gt;），相关信息都在里面&lt;/li&gt;
&lt;li&gt;请求方法分为 GET/POST，大部分都是 GET，POST 配置略复杂，建议直接看 &lt;code&gt;opensearch.xml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IconURL&lt;/code&gt; 不建议修改为网站 favicon 的动态 URL&lt;sup id="fnref:8"&gt;&lt;a href="#fn:8" class="footnote-ref" role="doc-noteref"&gt;8&lt;/a&gt;&lt;/sup&gt;，这样&lt;strong&gt;每次启动&lt;/strong&gt;（不限于第一次启动）Firefox 都会挨个请求一遍图标，增加不必要的网络流量。当然如果看图标不爽也可以不填或者用自定义图标。&lt;/li&gt;
&lt;li&gt;Merriam-Webster 和汉典这种字典类网站的 URL 结构固定，也可以直接构造 URL，避免跳转。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;policies&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;SearchEngines&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Add&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Alias&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;vn, gal&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Description&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Search visual novels on VNDB.org&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;IconURL&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;data:image/x-icon;base64,后略&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Method&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;VNDB&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;URLTemplate&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;https://vndb.org/v?q={searchTerms}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Alias&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;mw, dict&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Description&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Dictionary by Merriam-Webster&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;IconURL&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Method&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Dictionary&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;URLTemplate&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;https://www.merriam-webster.com/dictionary/{searchTerms}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Alias&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;moe&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Description&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;泛 ACGN 向 Wiki（百科）站点，主要收录 Anime（动画）、Comic（漫画）、Game（游戏）、Novel（轻小说）及相关网络文化。&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;IconURL&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;data:image/png;base64后略&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Method&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;萌娘百科&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;URLTemplate&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;https://moegirl.icu/index.php?title=Special:%E6%90%9C%E7%B4%A2&amp;amp;search={searchTerms}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Alias&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;ddg&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Description&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Search DuckDuckGo (NoAI)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;IconURL&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;data:image/x-icon;base64后略&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Method&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;DuckDuckGoLite&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;PostData&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;q={searchTerms}&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;URLTemplate&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;https://noai.duckduckgo.com/html/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Default&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;DuckDuckGoLite&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Remove&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Amazon.com&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;DuckDuckGo&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Google&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;仅仅三个例子显然没办法覆盖全部内容，但麻烦的部分基本都有所涉及，其他配置项照猫画虎，看报错信息修补即可。还有一些很有用的配置，例如 &lt;a href="https://firefox-admin-docs.mozilla.org/reference/policies/handlers/"&gt;Handlers&lt;/a&gt;（比如默认在 Firefox 中打开 RSS……）和 &lt;a href="https://firefox-admin-docs.mozilla.org/reference/policies/websitefilter/"&gt;WebsiteFilter&lt;/a&gt;（网站的屏蔽/允许名单），没有配置，有缘再说。&lt;/p&gt;
&lt;h2 id="插件"&gt;插件&lt;/h2&gt;
&lt;p&gt;这东西没什么好说的，过于烂大街，看到那些装一百多个插件，时刻开几十个页面的人大放厥词我常常感到无奈，因为很多内容不需要插件就能实现。只要完全掌握上面提到的内容，你已经比地球上绝大部分人更能掌控浏览器的方方面面。工具始终就是工具，不要沦为工具控（aka. 工具的奴隶），而要当工具的奴隶主，亲自调教浏览器能让你对浏览器内部有更深刻的了解。&lt;/p&gt;
&lt;p&gt;为什么我看不上 LibreWolf，一个是不基于 Firefox ESR，另一个是没有自动更新，最后就是它单纯 = Firefox + user.js + uBlock Origin + 杂七杂八会导致&lt;strong&gt;更多&lt;/strong&gt;问题的 patch。实在要说审美也比 Mozilla 略微在线，仅此而已。它甚至没用上 CSS 和 policy-templates，而你在享受虚假的 &lt;sup id="fnref:9"&gt;&lt;a href="#fn:9" class="footnote-ref" role="doc-noteref"&gt;9&lt;/a&gt;&lt;/sup&gt; 隐私保护的同时，也面临所有下游项目都无法避免的一点——更新延迟。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不用 ESR = 更新更频繁 = 忽略更新的风险加大&lt;/li&gt;
&lt;li&gt;采用第三方 user.js = 存在浏览器更新，而 user.js 尚未更新的窗口期（个人可以通过及时自定义弥补）&lt;/li&gt;
&lt;li&gt;绑定 uBlock Origin 的用户潜在预期是一有更新就要发版&lt;/li&gt;
&lt;li&gt;patch = 上游一更新相关文件就要修改 patch，这个工作一般很简单但也很琐碎&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;后面会单独出一篇介绍浏览器插件 &lt;sup id="fnref:10"&gt;&lt;a href="#fn:10" class="footnote-ref" role="doc-noteref"&gt;10&lt;/a&gt;&lt;/sup&gt;，这里先按下不表。&lt;/p&gt;
&lt;h2 id="吐槽"&gt;吐槽&lt;/h2&gt;
&lt;p&gt;Firefox 的 policy-templates 数量级就比 Chromium 系要小，这点还可以用海量的 user.js 和 autoconfig 配置项来解释。匪夷所思的是 Cookies 配置功能比 Chromium 弱很多，不支持通配符，也不能设置 A 网站只能读取 B 网站的 cookies，而是 all or nothing。举例：不能允许淘宝只获取天猫的 cookies，如果允许读取第三方 cookies，就会一并接收广告联盟、追踪脚本、用户行为分析等垃圾第三方，颗粒度不够细。&lt;/p&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;本文仅介绍 Firefox ESR，Firefox/LibreWolf 等自行类推&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;注意，文中&lt;strong&gt;通过修改 omni.ja 定制按键的方法是错误的&lt;/strong&gt;。在 99.9% 的情况下（剩下那 0.1% 是 LibreWolf, Tor Browser 等套娃浏览器定制打包，虽然个人&lt;strong&gt;可以&lt;/strong&gt;做得比这些浏览器更好，但过于耗费精力，不建议轻易尝试），你都不需要修改 omni.ja，延伸阅读 &lt;a href="https://mike.kaply.com/2013/05/06/dont-unpack-and-repack-omni-jar/"&gt;Don’t Unpack and Repack omni.ja&lt;/a&gt;&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;这个路径视发行版和安装源的情况而定，可能会有所变动，像 Snap/Flatpak 的路径不一样&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;使用组策略配置需要加入域，这点对纯离线环境很不友好&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:5"&gt;
&lt;p&gt;这里有一点非常坑，由于 Firefox 的实现问题，指定同一个域名的多个端口时，必须加上结尾的 &lt;code&gt;/&lt;/code&gt;，不然只有第一个端口会生效……&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:6"&gt;
&lt;p&gt;目前尚可以通过 &lt;a href="https://firefox-admin-docs.mozilla.org/reference/policies/extensions/"&gt;Extensions&lt;/a&gt; 配置，但这东西早晚要弃用，功能不如 ExtensionSettings，而且后者实际上和 Chrome 的对应配置类似，反正都要写还是早点写了吧&amp;#160;&lt;a href="#fnref:6" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:7"&gt;
&lt;p&gt;注意这里我又移除了 DuckDuckGo，实际上它在上一步的 ExtensionSettings 已经被移除了，写进这里就是为了说明卸载的两种方法，也说明了 Firefox 自带的搜索引擎其实就是 extension，这也是它们能够自动更新的原因。再扩展一下，其实你不需要这么麻烦地配置搜索引擎，也可以借助 ExtensionSettings 安装，但我秉持着少装一个是一个、多折腾一点是一点的理念，刻意选择 learn it the hard way&amp;#160;&lt;a href="#fnref:7" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:8"&gt;
&lt;p&gt;这里需要手动将网站图标，即 favicon (ICO)，转换为 Data URI &lt;code&gt;data:content/type;base64&lt;/code&gt; 格式，实在不会可以用 &lt;a href="https://base64.guru/converter/encode/image/ico"&gt;ICO to Base64&lt;/a&gt; 等在线工具&amp;#160;&lt;a href="#fnref:8" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:9"&gt;
&lt;p&gt;这可能说得有点过，更好的说法是「不彻底的」&amp;#160;&lt;a href="#fnref:9" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:10"&gt;
&lt;p&gt;预告一下，我大概会在这篇里喷各种插件推荐列表，并且给出更加「原生」或可靠的方案&amp;#160;&lt;a href="#fnref:10" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category domain="/tags/">Browser</category><category domain="/tags/">Firefox</category><category domain="/tags/">Customize</category><category domain="/tags/">Dev</category><category domain="/tags/">Js</category><category domain="/tags/">Css</category></item><item><title>浏览器调教指南 - Chromium 篇 (Chrome/MSEdge)</title><link>https://blog.vinfall.com/posts/2024/08/browser-customize-chromium/</link><pubDate>2026-08-21</pubDate><author>Vinfall</author><guid>https://blog.vinfall.com/posts/2024/08/browser-customize-chromium/</guid><summary>铬之炼金术士，从入釜到入土</summary><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;接着昨天的 &lt;a href="https://blog.vinfall.com/posts/2024/08/browser-customize-firefox/"&gt;浏览器调教指南 - Firefox 篇&lt;/a&gt;，今天介绍 Chromium 系浏览器的调教方法。
前文已经给出定义，不再赘述，本篇的重点显然是 Chrome/Chromium 和 MSEdge。
其他套壳浏览器不够「主流」，特性也不吸引我，绝大部分还没原版安全，自行解决。
不过文中的方法大概率通用，就是替换一下关键词的事儿。&lt;/p&gt;
&lt;h2 id="flags"&gt;Flags&lt;/h2&gt;
&lt;p&gt;在连篇累牍介绍 policy-templates 之前，先上点开胃菜。
提到调教 Chromium，首先肯定是 chrome://flags&lt;/p&gt;
&lt;p&gt;随便举几个例子 &lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Anonymize local IPs exposed by WebRTC，隐私设置，但会影响 mDNS&lt;/li&gt;
&lt;li&gt;Block scripts loaded via document.write，防范 PDF 中的脚本攻击&lt;/li&gt;
&lt;li&gt;Parallel downloading，多线程下载&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;值得一提的是很多 flags 都有对应的命令行参数，可以写在快捷方式 / Linux Desktop File 里，避免重装后手动设置，具体列表参见 &lt;a href="https://peter.sh/experiments/chromium-command-line-switches/"&gt;List of Chromium Command Line Switches&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;考虑到部分 flags（QUIC、ECH&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt; 等）可以通过 policy-templates 设定，不多讲。
况且 flags 本质还是测试中的功能，保不准哪天就删了。
而 policy-templates 面向企业用户，得罪金主自砸饭碗的事要少得多。&lt;/p&gt;
&lt;h2 id="policy-template"&gt;Policy Template&lt;/h2&gt;
&lt;p&gt;在 Firefox 篇的对应小节我曾提到，Chromium 系的 &lt;a href="https://www.chromium.org/administrators/policy-templates/"&gt;policy-templates&lt;/a&gt; 方法不够通用，详细解释一下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;不同浏览器 policy-templates 存放路径不一样（废话），而 Chromium 套壳满地都是，企业部署方案的修改牵一发而动全身
&lt;ul&gt;
&lt;li&gt;Chrome 存放在 &lt;code&gt;/etc/opt/chrome/policies&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Chromium 存放在 &lt;code&gt;/etc/chromium/policies&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;MSEdge、Vivaldi、Brave、Arc、Yandex 各有各的地盘……&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;同一个浏览器，安装源（发行版的软件包管理器、Snap、Flatpak 等）不同，存放路径也可能不同。前文已经提及，不再赘述。&lt;/li&gt;
&lt;li&gt;同一个浏览器在不同平台的部署方式不一样（虽然也是废话，但人家 Firefox 就一样）
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.chromium.org/administrators/linux-quick-start/"&gt;Linux&lt;/a&gt; 用 JSON&lt;/li&gt;
&lt;li&gt;Windows 用注册表或者组策略 &lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.chromium.org/administrators/mac-quick-start/"&gt;macOS&lt;/a&gt; 又用 profile manager，并且使用 Apple 莫名其妙的 plist 格式&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;同一个浏览器，不同更新通道，可用策略不一样（废话），所以使用的模板也不一样
&lt;ul&gt;
&lt;li&gt;以 Chrome 为例，Stable/Beta/Dev，各有各的模板&lt;/li&gt;
&lt;li&gt;这听起来可能没什么，主要 Chrome/Chromium 的 policy-templates 是一个 &lt;a href="https://dl.google.com/dl/edgedl/chrome/policy/policy_templates.zip"&gt;超大压缩包&lt;/a&gt;，虽然也有网页版，但使用体验远不如前者，而且还没有翻译（压缩包版本有），也没有更新日志 &lt;sup id="fnref:4"&gt;&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref"&gt;4&lt;/a&gt;&lt;/sup&gt;，多通道并存的情况下很容易陷入版本管理地狱&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;由于 Chromium 系浏览器在很多系统都有大量用户，像 Chrome OS 乃至 Android 都有独立的解决方案，此外还支持分级配置，复杂场景的解决方案很复杂，当然，个人使用基本碰不到这类问题&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="分级配置"&gt;分级配置&lt;/h2&gt;
&lt;p&gt;简单来说分为两种，Managed v.s. Recommended：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;前者会强制锁定某一设置，用户不能修改&lt;/li&gt;
&lt;li&gt;后者则仅设置推荐的默认值，允许用户修改，但修改后会提醒与组织要求冲突&lt;/li&gt;
&lt;li&gt;此外，有的策略只能配置为强制实施，不能推荐……&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;听起来是不是很麻烦？在 Firefox 通过 &lt;a href="https://blog.vinfall.com/posts/2024/08/browser-customize-firefox/#userjs"&gt;user.js&lt;/a&gt;（等同于推荐）和 autoconfig（等同于强制）实现，类似烦恼会大大减少╮(╯_╰)╭&lt;/p&gt;
&lt;h2 id="示例"&gt;示例&lt;/h2&gt;
&lt;p&gt;实话实说我觉得讲到这里就可以了，点到为止，后面的示例也就是画龙点睛。&lt;/p&gt;
&lt;h3 id="坑"&gt;坑&lt;/h3&gt;
&lt;p&gt;讲解示例之前先说几个坑：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用注册表配置 Windows 上的 Chromium 系浏览器时要注意，&lt;code&gt;.reg&lt;/code&gt; 文件的编码是 UTF-16-LE&lt;/li&gt;
&lt;li&gt;如果通过 git 管理 policy-templates，不能通过 &lt;code&gt;.gitattibutes&lt;/code&gt; 自动设置 EOL，不然注册表大概率会炸&lt;/li&gt;
&lt;li&gt;Linux 要注意配置文件的权限，我在部署脚本最后移除了目录的写入权限&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Setup Google Chrome/Chromium policies on GNU/Linux&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Configure path&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;POLICY_PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;/etc/chromium/policies&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# POLICY_PATH=&amp;#34;/etc/opt/chrome/policies&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Restrict permission&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo chmod -w &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;POLICY_PATH&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/managed
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo chmod -w &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;POLICY_PATH&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/recommended
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;配置结果可以在 chrome://policy 查看，Status 都是 &lt;code&gt;OK&lt;/code&gt; 就 OK 了&lt;/li&gt;
&lt;li&gt;最后这个不算坑，不如说是 Firefox 的坑：Chromium 系的 policy-templates 可以写注释！&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="禁用-gemini"&gt;禁用 Gemini&lt;/h3&gt;
&lt;p&gt;先来个实用的，Chrome 144 开始逐步集成 Gemini，会自动下载几 GB 的 LLM 模型，还默认上传隐私数据用于数据训练。我想用自然会另外用付费 API&lt;sup id="fnref:5"&gt;&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref"&gt;5&lt;/a&gt;&lt;/sup&gt;，浏览器不想用则直接禁止，以绝后患。&lt;/p&gt;
&lt;p&gt;Linux Chromium，禁用 Gemini、禁止自动下载模型（配置前下载的会自动删除）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// /etc/chromium/policies/managed/managed-policies.json
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;AIModeSettings&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;GeminiSettings&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;GenAILocalFoundationalModelSettings&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Windows Chrome/Chromium/MSEdge 的注册表（看这前缀就知道麻烦了吧，一样的内容要写三遍），保存为 &lt;code&gt;ChromeNoGenAI.reg&lt;/code&gt;，导入即可：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-reg" data-lang="reg"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Windows Registry Editor Version 5.00
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;[&lt;/span&gt;HKEY_LOCAL_MACHINE&lt;span style="color:#66d9ef"&gt;\SOFTWARE\Policies\Google\Chrome]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;AIModeSettings&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;dword:&lt;span style="color:#ae81ff"&gt;00000001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;GeminiSettings&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;dword:&lt;span style="color:#ae81ff"&gt;00000001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;GenAILocalFoundationalModelSettings&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;dword:&lt;span style="color:#ae81ff"&gt;00000001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;[&lt;/span&gt;HKEY_LOCAL_MACHINE&lt;span style="color:#66d9ef"&gt;\SOFTWARE\Policies\Chromium]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;AIModeSettings&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;dword:&lt;span style="color:#ae81ff"&gt;00000001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;GeminiSettings&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;dword:&lt;span style="color:#ae81ff"&gt;00000001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;GenAILocalFoundationalModelSettings&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;dword:&lt;span style="color:#ae81ff"&gt;00000001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;[&lt;/span&gt;HKEY_LOCAL_MACHINE&lt;span style="color:#66d9ef"&gt;\SOFTWARE\Policies\Microsoft\Edge]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;AIModeSettings&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;dword:&lt;span style="color:#ae81ff"&gt;00000001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;GeminiSettings&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;dword:&lt;span style="color:#ae81ff"&gt;00000001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;GenAILocalFoundationalModelSettings&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;dword:&lt;span style="color:#ae81ff"&gt;00000001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="配置插件"&gt;配置插件&lt;/h3&gt;
&lt;p&gt;第二个示例和 &lt;a href="https://blog.vinfall.com/posts/2024/08/browser-customize-firefox/#%E7%A4%BA%E4%BE%8B"&gt;Firefox 篇&lt;/a&gt;一样，通过 &lt;a href="https://chromeenterprise.google/policies/?policy=ExtensionAllowedTypes"&gt;ExtensionAllowedTypes&lt;/a&gt; 和 &lt;a href="https://chromeenterprise.google/policies/?policy=ExtensionInstallForcelist"&gt;ExtensionInstallForcelist&lt;/a&gt; 配置插件：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;ExtensionAllowedTypes&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;extension&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// &amp;#34;theme&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;user_script&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;hosted_app&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;legacy_packaged_app&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;platform_app&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;ExtensionInstallForcelist&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;ddkjiahejlhfcafbddmgiahcphecmpfh&amp;#34;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// uBlock Origin Lite
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;jaehimmlecjmebpekkipmpmbpfhdacom&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;//ScriptCat Beta
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;3rdparty&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;extensions&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;ddkjiahejlhfcafbddmgiahcphecmpfh&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;defaultFiltering&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;complete&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;noFiltering&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;cashiersa128.alipay.com&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这部分和 Firefox 差不多，没什么好说的，知道可以写注释即可。
这里只简单配置了允许的扩展类型并强制安装 2 个扩展。
uBOL 也支持浏览器策略，感兴趣可以参考上面的例子和官方 &lt;a href="https://github.com/uBlockOrigin/uBOL-home/wiki/Managed-settings"&gt;wiki&lt;/a&gt; 配置。&lt;/p&gt;
&lt;p&gt;Windows 注册表写法略微不同，但也是一目了然，同样支持注释：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-reg" data-lang="reg"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Windows Registry Editor Version 5.00
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;; chrome version: 150&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;[&lt;/span&gt;HKEY_LOCAL_MACHINE&lt;span style="color:#66d9ef"&gt;\Software\Policies\Chromium\ExtensionAllowedTypes]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;extension&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;; &amp;#34;2&amp;#34;=&amp;#34;theme&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;user_script&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;3&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;hosted_app&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;4&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;legacy_packaged_app&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;5&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;platform_app&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;[&lt;/span&gt;HKEY_LOCAL_MACHINE&lt;span style="color:#66d9ef"&gt;\Software\Policies\Chromium\ExtensionInstallForcelist]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;ddkjiahejlhfcafbddmgiahcphecmpfh&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;ndcooeababalnlpkfedmmbbbgkljhpjf&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;[&lt;/span&gt;HKEY_LOCAL_MACHINE&lt;span style="color:#66d9ef"&gt;\SOFTWARE\Policies\Chromium\3rdparty\extensions\ddkjiahejlhfcafbddmgiahcphecmpfh\policy]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;defaultFiltering&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;noFiltering&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;[&amp;#34;cashiersa128.alipay.com&amp;#34;]&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;需要注意，部分应用程序基于浏览器框架构建，配置 &lt;code&gt;ExtensionAllowedTypes&lt;/code&gt; 可能会影响运行。&lt;/p&gt;
&lt;p&gt;比如烂大街的 RPG Maker、&lt;a href="https://store.steampowered.com/app/345370"&gt;TyranoScript&lt;/a&gt; 和新兴 gal 引擎 &lt;a href="https://www.openwebgal.com/zh-cn/"&gt;WebGal&lt;/a&gt;，底层是 Electron/NW.js，导出时可能没有附带 runtime，默认调用系统浏览器，自然也受 policy-templates 制约 &lt;sup id="fnref:6"&gt;&lt;a href="#fn:6" class="footnote-ref" role="doc-noteref"&gt;6&lt;/a&gt;&lt;/sup&gt;。可以写个批处理删除对应注册表，临时放行，结束之后再重新导入，或者干脆不配置这一项。&lt;/p&gt;
&lt;p&gt;随手写的脚本，保存为 &lt;code&gt;allow-nwjs-game.bat&lt;/code&gt; 使用管理员权限运行即可：&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;allow-nwjs-game.bat&lt;/summary&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-batch" data-lang="batch"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; off
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Delete reg to allow Electron/NW.js…&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;reg delete &lt;span style="color:#e6db74"&gt;&amp;#34;HKEY_LOCAL_MACHINE\Software\Policies\Chromium\ExtensionAllowedTypes&amp;#34;&lt;/span&gt; /f
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;reg delete &lt;span style="color:#e6db74"&gt;&amp;#34;HKEY_LOCAL_MACHINE\Software\Policies\Google\Chrome\ExtensionAllowedTypes&amp;#34;&lt;/span&gt; /f
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;reg delete &lt;span style="color:#e6db74"&gt;&amp;#34;HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge\ExtensionAllowedTypes&amp;#34;&lt;/span&gt; /f
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; %errorlevel%&lt;span style="color:#f92672"&gt;==&lt;/span&gt;0 (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; ExtensionAllowedTypes policy deleted.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; ExtensionAllowedTypes policy deletion failed!
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pause&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;
&lt;h3 id="搜索引擎"&gt;搜索引擎&lt;/h3&gt;
&lt;p&gt;「搜索引擎」在 Chromium 中其实叫 Site search，应该配置 &lt;a href="https://chromeenterprise.google/policies/?policy=SiteSearchSettings"&gt;SiteSearchSettings&lt;/a&gt;，而不是 DefaultSearchProvider（策略组，包含有搜索引擎相关的一系列策略）。&lt;/p&gt;
&lt;p&gt;如果搞定了 Firefox ESR 的搜索引擎配置，Chromium 不要太简单，就是高考难度降级到小学生看图写话。
唯一的潜在难点就是 Windows 用注册表配置的情况，但根据 &lt;a href="https://www.chromium.org/administrators/complex-policies-on-windows/"&gt;Complex policies on Windows&lt;/a&gt;，实际上 Chromium 已经支持直接读取注册表中的 JSON，所以不这么写也无所谓，照样可以导入。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-reg" data-lang="reg"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;[&lt;/span&gt;HKEY_LOCAL_MACHINE&lt;span style="color:#66d9ef"&gt;\Software\Policies\Chromium\SiteSearchSettings\1]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;featured&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;dword:&lt;span style="color:#ae81ff"&gt;00000001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;DuckDuckGo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;shortcut&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;d&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://noai.duckduckgo.com/html?q={searchTerms}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;[&lt;/span&gt;HKEY_LOCAL_MACHINE&lt;span style="color:#66d9ef"&gt;\Software\Policies\Chromium\SiteSearchSettings\2]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;ピクシブ百科事典&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;shortcut&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;pixiv&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://dic.pixiv.net/search?query={searchTerms}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;顺带一提，&lt;code&gt;featured&lt;/code&gt; 只是额外支持通过 &lt;code&gt;@d&lt;/code&gt; 触发搜索，但限制三个，而且其实直接 &lt;code&gt;d&lt;/code&gt; + Tab 更快……&lt;/p&gt;
&lt;p&gt;另外，MSEdge 不支持配置 site search，由于已经卸载 Edge，没验证是不是故意阉割以便强推 Copilot。&lt;/p&gt;
&lt;h3 id="cookies"&gt;Cookies&lt;/h3&gt;
&lt;p&gt;最后介绍 Cookies 的 Linux Chromium 配置。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;recommended-policies.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;BlockThirdPartyCookies&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里特地把屏蔽第三方 cookies 写成推荐，防止你读到这里忘了还有 &lt;a href="https://blog.vinfall.com/posts/2024/08/browser-customize-chromium/#%e5%88%86%e7%ba%a7%e9%85%8d%e7%bd%ae"&gt;#分级配置&lt;/a&gt; 的设定。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;managed-policies.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;CookiesAllowedForUrls&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;*,https://drive.google.com&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;https://steampowered.com,https://steamcommunity.com&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;*,https://*.sharepoint.com&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;*,https://[*.]live.com&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;https://[*.]dlsite.com,https://www.nijiyome.jp&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;DefaultCookiesSetting&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="https://chromeenterprise.google/policies/?policy=DefaultCookiesSetting"&gt;DefaultCookiesSetting&lt;/a&gt; 的 &lt;code&gt;4&lt;/code&gt; 代表浏览器窗口关闭即失效，cookies 不会一直保存。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://chromeenterprise.google/policies/?policy=CookiesAllowedForUrls"&gt;CookiesAllowedForUrls&lt;/a&gt; 略复杂，但比 Firefox 的 SearchEngines 简单多了。
这里需要填两个 URL，允许前者 cookies 在后者使用。&lt;/p&gt;
&lt;p&gt;结合上面的例子详细讲一下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;*,https://drive.google.com&amp;quot;&lt;/code&gt;，最常用的一种，在 Google Drive 允许第三方 cookies，可以用通配符&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;https://steampowered.com,https://steamcommunity.com&amp;quot;&lt;/code&gt;，比上面一种复杂，在 Steam 社区允许 Steam 商店的 cookies，从而解决 V 社十多年一直懒得搞的 CORS 跨域问题……不需要因为默认屏蔽第三方 cookies 而重新登录一次&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;*,https://*.sharepoint.com&amp;quot;&lt;/code&gt;，可以同时用通配符匹配各种 SharePoint 二级域名，但显然不能 &lt;code&gt;*,*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;*,https://[*.]live.com&amp;quot;&lt;/code&gt;，也可以使用 &lt;code&gt;[*.]&lt;/code&gt; 来同时匹配 &lt;code&gt;*.live.com&lt;/code&gt; 和 &lt;code&gt;live.com&lt;/code&gt;，解决一级/二级域名混用的网站&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;https://[*.]dlsite.com,https://www.nijiyome.jp&amp;quot;&lt;/code&gt;（不要瞎点，&lt;strong&gt;NSFW 警告&lt;/strong&gt;）在 DLsite 姊妹站にじ GAME 允许来自 DLsite 的 cookies，和 Steam/OneDrive 的例子差不多，但是这里 &lt;code&gt;[*.]&lt;/code&gt; 通配符用在第一个 URL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;看到这里，你大概能理解 &lt;a href="https://blog.vinfall.com/posts/2024/08/browser-customize-firefox/#%E5%90%90%E6%A7%BD"&gt;Firefox 篇#吐槽&lt;/a&gt; 的内容。&lt;/p&gt;
&lt;h2 id="msedge"&gt;MSEdge&lt;/h2&gt;
&lt;p&gt;由于 MSEdge 越更越烂 &lt;sup id="fnref:7"&gt;&lt;a href="#fn:7" class="footnote-ref" role="doc-noteref"&gt;7&lt;/a&gt;&lt;/sup&gt;，塞了一堆有的没的功能，我已经弃用，以下内容仅供参考。
其实 MSEdge 和 Chromium 在定制化层面差不多，多了几个 flags，少了几个 policy-templates。&lt;/p&gt;
&lt;h3 id="flags-1"&gt;Flags&lt;/h3&gt;
&lt;p&gt;大差不差，随便写几个：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Boost screen refresh rate when scrolling，动态刷新率（即 VRR），需要显示器支持&lt;/li&gt;
&lt;li&gt;Omnibox UI Hide Steady-State URL Trivial Subdomains，禁用之后就能恢复正常的地址栏完整 URL&lt;/li&gt;
&lt;li&gt;Show block option in autoplay settings，为数不多的好东西，可以屏蔽自动播放，Firefox/Chromium 默认的「屏蔽」只针对有声音的视频……&lt;/li&gt;
&lt;li&gt;PlayReady DRM for Windows 和 Widevine DRM，解锁高清流媒体，其他浏览器默认只能 720p/1080p，也不是不能看，但肯定比不了 4K 双杜比&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="policy-template-1"&gt;Policy Template&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;文档
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/DeployEdge/microsoft-edge-policies"&gt;Microsoft Edge - Policies&lt;/a&gt;，&lt;a href="https://learn.microsoft.com/zh-CN/DeployEdge/microsoft-edge-policies"&gt;Microsoft Edge - 策略&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/DeployEdge/microsoft-edge-update-policies"&gt;Microsoft Edge - Update policies&lt;/a&gt;，&lt;a href="https://learn.microsoft.com/zh-CN/DeployEdge/microsoft-edge-update-policies"&gt;Microsoft Edge - 更新策略&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://admx.help/?Category=EdgeChromium&amp;amp;Language=zh-cn"&gt;Microsoft Edge 商业版 管理模板&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;注册表路径
&lt;ul&gt;
&lt;li&gt;强制：&lt;code&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;推荐：&lt;code&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge\Recommended&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;更新：&lt;code&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\EdgeUpdate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;注意路径，HKLM 下面还有 &lt;code&gt;Policies\Microsoft\MicrosoftEdge&lt;/code&gt;，这个路径是&lt;strong&gt;错误&lt;/strong&gt;的！&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实际配置真差不多，有两点可以表扬：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/zh-cn/deployedge/microsoft-edge-channels#extended-stable-channel"&gt;扩展稳定渠道&lt;/a&gt;，类似 Firefox ESR，偶数为功能更新，奇数为安全更新&lt;/li&gt;
&lt;li&gt;可以设置单独的 &lt;a href="https://learn.microsoft.com/zh-CN/DeployEdge/microsoft-edge-update-policies"&gt;Microsoft Edge - 更新策略&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;好话言尽于此，可以开始骂了。&lt;/p&gt;
&lt;p&gt;EdgeUpdate 这东西本身体验就一言难尽，对于不能手动触发的 &lt;em&gt;bug&lt;/em&gt;，开发者明确表示就只能通过计划任务触发你敢信？再加上永远有残留安装包和多版本并存死活不肯卸载旧版的 EdgeWebView，整个 Edge 生态在我看来非常畸形。这都可以用脚本解决，关键切换到 Chromium 内核还把我最爱的 PDF 阅读器砍了🙄&lt;/p&gt;
&lt;p&gt;此外 M$ 还喜欢掩耳盗铃，Microsoft Edge - 策略的 &lt;a href="https://learn.microsoft.com/zh-CN/DeployEdge/microsoft-edge-policies#additional"&gt;附加部分&lt;/a&gt; 多列了许多配置项，给人感觉好像比 Chromium 多做了很多工作，其实是混淆视听，大多数在 Chromium 存在的内容被刻意挪到这里。由于 Edge 策略是分组的，不像 Firefox 那样直接按字母排序，看到最后这部分很容易被诱导。&lt;/p&gt;
&lt;p&gt;很多 Edge 特有的无用功能也都被特地放到这部分，比如必应搜索结果的广告 &lt;sup id="fnref:8"&gt;&lt;a href="#fn:8" class="footnote-ref" role="doc-noteref"&gt;8&lt;/a&gt;&lt;/sup&gt;、Copilot、集锦、没卵用的电子钱包、钱包捐赠和更没卵用的 E-tree🤬各种遥测更是防不胜防……&lt;/p&gt;
&lt;p&gt;跑题了，浏览器扩展可以从 Edge 商店安装，也可以 Chrome 商店安装，具体可以参考 &lt;a href="https://learn.microsoft.com/zh-cn/deployedge/microsoft-edge-manage-extensions"&gt;在企业中管理 Microsoft Edge 扩展&lt;/a&gt;，不过坑也不少：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;指定从 Chrome 商店安装扩展，始终会报错，企业用户也吐槽好多回，但是死不悔改&lt;/li&gt;
&lt;li&gt;UpdateURL
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;https://edge.microsoft.com/extensionwebstorebase/v1/crx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://clients2.google.com/service/update2/crx&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="结语"&gt;结语&lt;/h2&gt;
&lt;p&gt;受限于 Google 的广告业务，Chromium 系调教手段着实有限。做到文中这些虽然不至于是杯水车薪，但也只能略微改善浏览器体验。随着 Manifest V2 的彻底废弃，Chromium 扩展完全沦为 Firefox 的下级替代。建议早日投入 Firefox ESR 的怀抱，享受极致的调教体验。&lt;/p&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Flags 会经常变动，这里列举的仅保证在 Chromium 146 有效&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Encrypted ClientHello，Mozilla/Cloudflare 等发布的 TLS1.3 扩展，可以简单理解为（但不等同于）加密的 SNI，详见 &lt;a href="https://wiki.mozilla.org/Security/Encrypted_Client_Hello"&gt;MozillaWiki&lt;/a&gt;&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;前文同样提及了使用组策略（GPO）需要加入域的问题，对纯离线环境很不友好，个人使用（而非企业批量部署）建议还是注册表，简单粗暴&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;MSEdge 会在 &lt;a href="https://techcommunity.microsoft.com/t5/microsoft-security-baselines/bg-p/Microsoft-Security-Baselines"&gt;Microsoft Security Baselines Blog&lt;/a&gt; 定期发布日志， &lt;del&gt;但一样得单独下载  &lt;a href="https://www.microsoft.com/download/details.aspx?id=55319"&gt;Microsoft Security Compliance Toolkit&lt;/a&gt; 才能查看具体的新增内容，GPO 全是 XML 格式，更新表格同时还用的 Excel&lt;/del&gt; 现在策略页面直接就会显示新策略和过时策略，很棒的改动👍&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:5"&gt;
&lt;p&gt;顺带一提，AI Studio 的免费 API 会拿对话数据训练，rate limit 也严格得多，考虑到 Gemini 本身定价就不贵，这免费羊毛还是不薅为好。&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:6"&gt;
&lt;p&gt;话虽如此，但归根结底还是游戏引擎没有考虑到这种情况，policy-templates 本身并没有问题&amp;#160;&lt;a href="#fnref:6" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:7"&gt;
&lt;p&gt;这点在 Windows Server 2022 LTSC 上尤为显著，预装的 MSEdge 86 还是挺好用的，升级到 127 之后页面就塞满各路妖魔鬼怪&amp;#160;&lt;a href="#fnref:7" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:8"&gt;
&lt;p&gt;&lt;a href="https://learn.microsoft.com/zh-CN/DeployEdge/microsoft-edge-policies#bingadssuppression"&gt;BingAdsSuppression&lt;/a&gt; 更是厚颜无耻，无广告搜索的前提是强制安全搜索设置为「严格」&amp;#160;&lt;a href="#fnref:8" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category domain="/tags/">Browser</category><category domain="/tags/">Chrome</category><category domain="/tags/">Customize</category><category domain="/tags/">Gpo</category><category domain="/tags/">Reg</category><category domain="/tags/">Dev</category></item><item><title>Awesome One-liner</title><link>https://blog.vinfall.com/posts/2022/09/awesome-oneliner/</link><pubDate>2026-08-17</pubDate><author>Vinfall</author><guid>https://blog.vinfall.com/posts/2022/09/awesome-oneliner/</guid><summary>Collection of awesome one-liners in shells.</summary><description>
&lt;div class="admonition admonition-note"&gt;
&lt;div class="admonition-heading"&gt;
ℹ️
Note
&lt;/div&gt;
&lt;div class="admonition-content"&gt;
&lt;p&gt;All commands here assumed Bash execution, unless noted as Zsh.
Full POSIX compatibility is not guranteed.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="fun"&gt;Fun&lt;/h2&gt;
&lt;p&gt;Get current BTC price (without demicals) using rate.sx API:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -s &lt;span style="color:#e6db74"&gt;&amp;#39;rate.sx/1btc?format=qT&amp;#39;&lt;/span&gt; | cut -f1 -d&lt;span style="color:#ae81ff"&gt;\.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Start one-off bukuserver with &lt;code&gt;uvx&lt;/code&gt; aka. &lt;code&gt;uv tool run&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;uvx --from &lt;span style="color:#e6db74"&gt;&amp;#34;buku[server]&amp;#34;&lt;/span&gt; bukuserver run --host 127.0.0.1 --port &lt;span style="color:#ae81ff"&gt;5001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Check running time (run at the end of script, mainly to avoid prevent COND &amp;amp;&amp;amp; COMMAND bug in &lt;a href="http://redsymbol.net/articles/unofficial-bash-strict-mode/"&gt;Bash Strict Mode&lt;/a&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# most bashism, but not working in Bash Strict Mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;timing&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Task finished in &lt;/span&gt;$SECONDS&lt;span style="color:#e6db74"&gt; &lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$((&lt;/span&gt; SECONDS &amp;lt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; ? &lt;span style="color:#e6db74"&gt;&amp;#34;second&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;seconds&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;))&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.&amp;#34;&lt;/span&gt;; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# boring, but working with &amp;#34;set -u&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;timing&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Task finished in &lt;/span&gt;$SECONDS&lt;span style="color:#e6db74"&gt; &lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt; &lt;span style="color:#f92672"&gt;((&lt;/span&gt; SECONDS &amp;lt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;) &amp;amp;&amp;amp; echo second || echo seconds ).&amp;#34;&lt;/span&gt;; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# a bit hacky, but works&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;timing&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; units&lt;span style="color:#f92672"&gt;=(&lt;/span&gt;seconds second&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Task finished in &lt;/span&gt;$SECONDS&lt;span style="color:#e6db74"&gt; &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;units[SECONDS &amp;lt;= 1 ? 1 : 0]&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.&amp;#34;&lt;/span&gt;; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# awesome one-liner&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;timing&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; local s&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;SECONDS&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;0&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; u&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;seconds&amp;#34;&lt;/span&gt;; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; $s -le &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;]]&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; u&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;second&amp;#34;&lt;/span&gt;; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Task finished in &lt;/span&gt;$s&lt;span style="color:#e6db74"&gt; &lt;/span&gt;$u&lt;span style="color:#e6db74"&gt;.&amp;#34;&lt;/span&gt;; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="ip"&gt;IP&lt;/h2&gt;
&lt;p&gt;Get internal WSL IP:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ip route | awk &lt;span style="color:#e6db74"&gt;&amp;#39;/^default/{print $3}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Get Windows host IP from WSL (if &lt;code&gt;generateHosts&lt;/code&gt; isn&amp;rsquo;t set to &lt;code&gt;False&lt;/code&gt; in &lt;code&gt;/etc/wsl.conf&lt;/code&gt;)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;host &lt;span style="color:#e6db74"&gt;`&lt;/span&gt;hostname&lt;span style="color:#e6db74"&gt;`&lt;/span&gt; | grep -oP &lt;span style="color:#e6db74"&gt;&amp;#39;(\s)\d+(\.\d+){3}&amp;#39;&lt;/span&gt; | tail -1 | awk &lt;span style="color:#e6db74"&gt;&amp;#39;{ print $NF }&amp;#39;&lt;/span&gt; | tr -d &lt;span style="color:#e6db74"&gt;&amp;#39;\r&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Get inet IP:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# BSD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ifconfig | awk &lt;span style="color:#e6db74"&gt;&amp;#39;/inet/ { sub(/%.*/, &amp;#34;&amp;#34;, $2); print $2 }&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Linux&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ip a | awk &lt;span style="color:#e6db74"&gt;&amp;#39;/inet/ { sub(/\/.*/, &amp;#34;&amp;#34;, $2); print $2 }&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# IPv4 only&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ip a | awk &lt;span style="color:#e6db74"&gt;&amp;#39;/inet / { sub(/\/.*/, &amp;#34;&amp;#34;, $2); print $2 }&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# IPv6 only&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ip a | awk &lt;span style="color:#e6db74"&gt;&amp;#39;/inet6/ { sub(/\/.*/, &amp;#34;&amp;#34;, $2); print $2 }&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="git"&gt;Git&lt;/h2&gt;
&lt;p&gt;Create a full git bundle using repo name:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;gbc&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; git bundle create &lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;basename &lt;span style="color:#e6db74"&gt;`&lt;/span&gt;git rev-parse --show-toplevel&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;.bundle --all
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pull all git repo in sub-folders (change &lt;code&gt;3&lt;/code&gt; to dig deeper) in parallel:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;find . -maxdepth &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; -name .git -type d -printf &lt;span style="color:#e6db74"&gt;&amp;#34;%h\0&amp;#34;&lt;/span&gt; | parallel -0 -k --line-buffer --tag git -c color.ui&lt;span style="color:#f92672"&gt;=&lt;/span&gt;always -C &lt;span style="color:#f92672"&gt;{}&lt;/span&gt; pull
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Get nightly or any selected release file on GitHub (inspired by &lt;a href="https://fabianlee.org/2021/02/16/bash-determining-latest-github-release-tag-and-version/" title="Bash: Determining latest github release tag and version"&gt;Bash: Determining latest GitHub release tag and version&lt;/a&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Get Citra Nightly Download URL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GITHUB_URL&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;curl --silent --location https://api.github.com/repos/citra-emu/citra-nightly/releases/latest | jq --raw-output &lt;span style="color:#e6db74"&gt;&amp;#34;.assets[].browser_download_url&amp;#34;&lt;/span&gt; | grep --extended-regexp &lt;span style="color:#e6db74"&gt;&amp;#34;citra-linux-.*?.tar.xz&amp;#34;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# A more advanced (read: wicked) one&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Download Sophia-Script Selected Release&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl --silent --location https://api.github.com/repos/farag2/Sophia-Script-for-Windows/releases/latest | jq --raw-output &lt;span style="color:#e6db74"&gt;&amp;#34;.assets[].browser_download_url&amp;#34;&lt;/span&gt; | grep --extended-regexp &lt;span style="color:#e6db74"&gt;&amp;#34;10.LTSC.2021|11.v&amp;#34;&lt;/span&gt; | xargs wget --quiet --input-file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;GitHub Action custom filter:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;on&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;push&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;branches&lt;/span&gt;: [&lt;span style="color:#e6db74"&gt;&amp;#39;main&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Only run when foo is changed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;paths&lt;/span&gt;: [&lt;span style="color:#e6db74"&gt;&amp;#39;a-path/foo&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;jobs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;build-that-can-skip&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;runs-on&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ubuntu-latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Skip build with [ci skip] in last commit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;! contains(github.event.head_commit.message, &amp;#39;[ci skip]&amp;#39;)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;sensitive-build&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;runs-on&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ubuntu-latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Only run on commits with [build]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;contains(toJSON(github.event.head_commit.message), &amp;#39;[build]&amp;#39;)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="file"&gt;File&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/en/linux/a-fast-way-to-remove-huge-number-of-files.html"&gt;Delete huge number of files using rsync&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir empty &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rsync -r --delete empty/ some-dir &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rmdir some-dir
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sort, filter, redirect a file using only &lt;code&gt;sort&lt;/code&gt;:&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-diff" data-lang="diff"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rookie
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-cat en.utf-8.add | sort | uniq &amp;gt; 1.add; mv 1.add en.utf-8.add
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;normie
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-cat en.utf-8.add | sort | uniq | sponge en.utf-8.add
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cool, but not enough
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-cat en.utf-8.add | sort -u | sponge en.utf-8.add
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cooler, still not enough
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-sort -u &amp;lt; en.utf-8.add | sponge en.utf-8.add
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nerdy
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;+sort -u en.utf-8.add -o en.utf-8.add
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="format"&gt;Format&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/4695695/convert-pdf-to-jpg-or-png-using-c-sharp-or-command-line"&gt;Convert PDF to PNG using command line&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# requires ghostscript&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;gs -dBATCH -dNOPAUSE -sDEVICE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;pnggray -r300 -dUseCropBox -sOutputFile&lt;span style="color:#f92672"&gt;=&lt;/span&gt;item-%03d.png examples.pdf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Convert SQL to formatted single line JSON in zsh (used in datasette-dashboards):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-zsh" data-lang="zsh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# lib/format.zsh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sql2json&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Usage:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# sql2json 1.sql&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# cat 1.sql | sql2json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# echo &amp;#39;SELECT * FROM public&amp;#39; | sql2json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sed &lt;span style="color:#e6db74"&gt;&amp;#39;s/--.*$//&amp;#39;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;1&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;/dev/stdin&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; | tr &lt;span style="color:#e6db74"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39; &amp;#39;&lt;/span&gt; | sed &lt;span style="color:#e6db74"&gt;&amp;#39;s/^ *//;s/ *$//;s/ */ /g&amp;#39;&lt;/span&gt; | jq -R &lt;span style="color:#e6db74"&gt;&amp;#39;{query: .}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Convert ROMs in CUE+BIN to CHD:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cue2chd&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# use cue file name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# find . -maxdepth 2 -name &amp;#39;*.cue&amp;#39; -type f -exec bash -c &amp;#39;chdman createcd -i &amp;#34;$0&amp;#34; -o &amp;#34;../${0%.*}.chd&amp;#34;&amp;#39; {} \;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# use subdirectory name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; find . -maxdepth &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; -name &lt;span style="color:#e6db74"&gt;&amp;#39;*.cue&amp;#39;&lt;/span&gt; -type f -exec bash -c &lt;span style="color:#e6db74"&gt;&amp;#39;chdman createcd -i &amp;#34;$0&amp;#34; -o &amp;#34;$(basename &amp;#34;$(dirname &amp;#34;$0&amp;#34;)&amp;#34;).chd&amp;#34;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;{}&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="zsh"&gt;Zsh&lt;/h2&gt;
&lt;p&gt;print &lt;code&gt;$PATH&lt;/code&gt; using zsh built-in parameter expansion:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;path&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# echo $PATH | sed &amp;#39;s/:/\n/g&amp;#39; # not cool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;PATH//:/&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;# cool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Use latest installed version of python/lua as alias (failsafe of distro specific method like dpkg-reconfigure, xbps-alternatives, or stow):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-zsh" data-lang="zsh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# lib/dev.zsh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Python&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; cmd in python3.&lt;span style="color:#f92672"&gt;{&lt;/span&gt;14..11&lt;span style="color:#f92672"&gt;}&lt;/span&gt; python3 python; &lt;span style="color:#f92672"&gt;((&lt;/span&gt; $+commands&lt;span style="color:#f92672"&gt;[&lt;/span&gt;$cmd&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;))&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; alias py&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$cmd; alias python&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$cmd; break &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Lua, prioritize mise-lua shim&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; ! -L $HOME/.local/share/mise/shims/lua &lt;span style="color:#f92672"&gt;]]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; cmd in lua5.&lt;span style="color:#f92672"&gt;{&lt;/span&gt;5..2&lt;span style="color:#f92672"&gt;}&lt;/span&gt;; &lt;span style="color:#f92672"&gt;((&lt;/span&gt; $+commands&lt;span style="color:#f92672"&gt;[&lt;/span&gt;$cmd&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;))&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; alias lua&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$cmd; break &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# luarocks is manually installed and updated&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# for cmd in luarocks-5.{5..2}; (( $+commands[$cmd] )) &amp;amp;&amp;amp; { alias lua=$cmd; break }&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="misc"&gt;Misc&lt;/h2&gt;
&lt;p&gt;Determine glibc or musl-libc:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; -e /usr/lib/ld-musl-x86_64.so &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; echo musl; &lt;span style="color:#66d9ef"&gt;elif&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; -e /usr/lib/ld-linux-x86-64.so &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; echo glibc; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; echo unknown; &lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# long version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;check_musl&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; local libdir&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/lib
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ls &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$libdir&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;/ld-musl* 1&amp;gt;/dev/null 2&amp;gt;&amp;amp;1; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo musl
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exit &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ls &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$libdir&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;/ld-linux* 1&amp;gt;/dev/null 2&amp;gt;&amp;amp;1; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo glibc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exit &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo unknown
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ask for explicit confirmation before proceeding (useful in hashsum check, dry run preview):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# just press y, without enter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;confirm&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; read -n &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; -rp &lt;span style="color:#e6db74"&gt;&amp;#34;Looking good? [y/N] &amp;#34;&lt;/span&gt; m &amp;lt; /dev/tty; echo; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;m,,&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;y&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]]&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; exit 1; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# or if you like hitting enter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;confirm&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; read -rp &lt;span style="color:#e6db74"&gt;&amp;#34;Looking good? [y/N] &amp;#34;&lt;/span&gt; m &amp;lt; /dev/tty; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;m,,&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; y* &lt;span style="color:#f92672"&gt;]]&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; exit 1; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# standard version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;confirm&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; read -rp &lt;span style="color:#e6db74"&gt;&amp;#34;Looking good? [y/N] &amp;#34;&lt;/span&gt; m &amp;lt; /dev/tty; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;m,,&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt;~ ^&lt;span style="color:#f92672"&gt;(&lt;/span&gt;y|yes&lt;span style="color:#f92672"&gt;)&lt;/span&gt;$&lt;span style="color:#f92672"&gt;]]&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Canceled.&amp;#34;&lt;/span&gt;; exit 1; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Proceeding.&amp;#34;&lt;/span&gt;; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# long (boring) version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;confirm&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; local match
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; read -r -p &lt;span style="color:#e6db74"&gt;&amp;#34;Looking good? [y/N]&amp;#34;&lt;/span&gt; match &amp;lt; /dev/tty
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;match,,&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; in &lt;span style="color:#75715e"&gt;# convert to lower case, bash 4.0+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; y|yes&lt;span style="color:#f92672"&gt;)&lt;/span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Proceeding.&amp;#34;&lt;/span&gt; ;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; *&lt;span style="color:#f92672"&gt;)&lt;/span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Canceled.&amp;#34;&lt;/span&gt;; exit &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; ;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;esac&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Show size of installed packages in descending order on Linux, from my ultimate backup() which works everywhere:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# apk-tools on Alpine, requires gawk and coreutils/uutils-coreutils&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;apk query --fields name,installed-size --installed &lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;apk info&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt; | awk &lt;span style="color:#e6db74"&gt;&amp;#39;/^Name:/{pkg=$2} /^Installed-Size:/{print $2 &amp;#34;\t&amp;#34; pkg}&amp;#39;&lt;/span&gt; | sort -rn | numfmt --to&lt;span style="color:#f92672"&gt;=&lt;/span&gt;iec --field&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; --delimiter&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$&amp;#39;\t&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# pacman on Arch/Artix/CachyOS/Manjaro, requires expac&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;expac &lt;span style="color:#e6db74"&gt;&amp;#34;%m\t%n&amp;#34;&lt;/span&gt; | sort -rn | numfmt --to&lt;span style="color:#f92672"&gt;=&lt;/span&gt;iec --field&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# apt/dpkg on Debian/Devuan/Termux/Ubuntu&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dpkg-query -Wf &lt;span style="color:#e6db74"&gt;&amp;#39;${Installed-Size}\t${Package}\n&amp;#39;&lt;/span&gt; | sort -rn | numfmt --from-unit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt; --to&lt;span style="color:#f92672"&gt;=&lt;/span&gt;iec --field&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; --delimiter&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$&amp;#39;\t&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# emerge/portage on Gentoo, requires app-portage/portage-utils (aka. qtools)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;qsize --sum
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# yum/dnf on Alma/CentOS/Fedora/RHEL/Rocky&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rpm -qa --queryformat &lt;span style="color:#e6db74"&gt;&amp;#39;%{size}\t%{name}\n&amp;#39;&lt;/span&gt; | sort -rn | numfmt --to&lt;span style="color:#f92672"&gt;=&lt;/span&gt;iec --field&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# xbps on Void, requires xtools-minimal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xhog
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# slackpkg on Slackware&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; f in /var/lib/pkgtools/packages/*; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; awk &lt;span style="color:#e6db74"&gt;&amp;#39;/^PACKAGE NAME:/{name=$3} /^UNCOMPRESSED PACKAGE SIZE:/{size=$4} END{print size, name}&amp;#39;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$f&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt; | sort -rh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;&lt;code&gt;-o&lt;/code&gt; is used here because &lt;code&gt;sort&lt;/code&gt; supports inplace redirect. You CAN NOT use it for any command! For GNU grep you have to write &lt;code&gt;grep -v '^#' cities.txt | sponge cities.txt&lt;/code&gt;, or just use &lt;code&gt;sed -i '/^#/d' cities.txt&lt;/code&gt;.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category domain="/tags/">Dev</category><category domain="/tags/">Linux</category><category domain="/tags/">Wsl</category><category domain="/tags/">Git</category><category domain="/tags/">Ip</category><category domain="/tags/">Mime</category><category domain="/tags/">Zsh</category><category domain="/tags/">Cli</category></item><item><title>Blog Signing Key 2026 Update</title><link>https://blog.vinfall.com/posts/2026/07/pubkey-update/</link><pubDate>2026-07-08</pubDate><author>Vinfall</author><guid>https://blog.vinfall.com/posts/2026/07/pubkey-update/</guid><summary>Not invented here syndrome 2nd edition</summary><description>&lt;h2 id="tldr"&gt;TLDR&lt;/h2&gt;
&lt;p&gt;Similar to &lt;a href="https://blog.vinfall.com/posts/2024/06/pubkey-update/"&gt;2024 Update&lt;/a&gt;, my blog signing key (&lt;code&gt;58222FDBCBFB1D0D51AE0088C20D48DA42BADC2E&lt;/code&gt;) is again expired last month as expected. &lt;a href="https://blog.vinfall.com/pubkey.asc"&gt;The new one&lt;/a&gt; is &lt;code&gt;4161C5B1A0C1CD50F47EF18D9593A536E370368B&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="intro"&gt;Intro&lt;/h2&gt;
&lt;p&gt;After playing Xbox for two months, and one extra week in &lt;em&gt;Assassin&amp;rsquo;s Creed Shadow&lt;/em&gt; thanks to the free Ubisoft+ Premium in Dragon Boat Festival giveaway, I&amp;rsquo;m been busy clearing the last pile of Switch games lately before switching to Switch 2 (pun intended). And while I dislike the smart (i.e. &lt;a href="https://en.wikipedia.org/wiki/Shamate"&gt;Shamate&lt;/a&gt;) style of &lt;em&gt;Fire Emblem Engage&lt;/em&gt;&amp;rsquo;s MC in the past, I&amp;rsquo;m addicted to it after really playing the game.&lt;/p&gt;
&lt;p&gt;Getting back to the point, this time I use alpine-make-vm-image instead of void-mklive to creat a minimal QCOW2 image to generate the perfect GPG keychain in an offline Alpine Edge KVM.&lt;/p&gt;
&lt;p&gt;For details, check &lt;a href="https://blog.vinfall.com/posts/2024/06/pubkey-update/#how-to"&gt;previous post&lt;/a&gt;. I&amp;rsquo;ll only leave brief commands this time.&lt;/p&gt;
&lt;p&gt;Build the image, &lt;code&gt;configure-min.sh&lt;/code&gt; is used to pre-configure the system:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/alpinelinux/alpine-make-vm-image &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cd alpine-make-vm-image
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo ./alpine-make-vm-image &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --arch x86_64 &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --branch edge &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --image-format qcow2 &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --image-size 200M &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --rootfs ext4 &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --packages &lt;span style="color:#e6db74"&gt;&amp;#34;ca-certificates doas fuse gnupg merge-usr openssh pinentry-tty shadow vim&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --script-chroot &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;alpine-min-&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;date +%Y-%m-%d&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.qcow2&amp;#34;&lt;/span&gt; -- ./custom/configure-min.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Boot the image, generate GPG keychain then mount it in another offline VM and transfer the GPG keychain.&lt;/p&gt;</description><category domain="/tags/">Dev</category></item><item><title>Rime 配置备忘录</title><link>https://blog.vinfall.com/posts/2022/06/rime/</link><pubDate>2026-07-07</pubDate><author/><guid>https://blog.vinfall.com/posts/2022/06/rime/</guid><summary>Rime 配置个人备忘</summary><description>&lt;h2 id="输入"&gt;输入&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Linux test suite: mousepad/ghostty (GTK4), okular/vbox (Qt6), keepassxc (Qt5), firefox-esr/zotero, chromium/electron/cef, SDL&lt;/li&gt;
&lt;li&gt;模糊音: 不再自定义，使用雾凇默认方案&lt;/li&gt;
&lt;li&gt;Emoji: 雾凇已整合 rime-emoji&lt;/li&gt;
&lt;li&gt;特殊符号输入: 带声调汉语拼音使用雾凇 V 模式的 &lt;code&gt;vpy&lt;/code&gt;，其他配置自定义短语&lt;/li&gt;
&lt;li&gt;切换输入方案: Ctrl + ` 或 F4&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;雾凇常用模式备忘（完整列表见 &lt;code&gt;rime_ice.schema.yaml&lt;/code&gt; 和 &lt;code&gt;symbols_v.yaml&lt;/code&gt;）&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;输入&lt;/th&gt;
&lt;th&gt;模式&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;vpy&lt;/td&gt;
&lt;td&gt;拼音&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;vhb&lt;/td&gt;
&lt;td&gt;货币&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;vrq, vsj, vxq&lt;/td&gt;
&lt;td&gt;日期, 时间, 星期&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;vnl&lt;/td&gt;
&lt;td&gt;农历&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;vjm&lt;/td&gt;
&lt;td&gt;假名&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="词库"&gt;词库&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;文档
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rime/home/wiki/UserGuide#%E5%B0%8E%E5%87%BA%E5%8F%8A%E5%B0%8E%E5%85%A5%E6%96%87%E6%9C%AC%E7%A2%BC%E8%A1%A8"&gt;导入码表说明&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/lotem/5443073"&gt;导入码表示例&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;转换
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/studyzy/imewlconverter"&gt;深蓝词库转换&lt;/a&gt;，其他输入法词库转换成 Rime 用户词典&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/outloudvi/mw2fcitx"&gt;mw2fcitx&lt;/a&gt;，MediaWiki 转 Fcitx 词库，关联阅读 &lt;a href="https://sspai.com/post/90068"&gt;让 RIME 体验更上一层楼：如何用 MediaWiki 扩展词库&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;词库
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/iDvel/rime-ice/releases"&gt;雾凇拼音&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;腾讯向量用处不大，直接关闭&lt;/li&gt;
&lt;li&gt;关联阅读 &lt;a href="https://sspai.com/post/89281"&gt;RIME + 雾凇拼音，打造绝佳的开源文字输入体验&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/outloudvi/mw2fcitx/releases"&gt;mw2citix&lt;/a&gt;，萌娘词库&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/felixonmars/fcitx5-pinyin-zhwiki/releases"&gt;fcitx5-pinyin-zhwiki&lt;/a&gt;，维基词库
&lt;ul&gt;
&lt;li&gt;下载 web-slang 和 zhwiktionary，默认只启用前者，后者用萌娘词库替代&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;私人词库: &lt;code&gt;cn_dicts/private.dict.yaml&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="定制"&gt;定制&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rime/home/wiki/CustomizationGuide#rime-%E5%AE%9A%E8%A3%BD%E6%8C%87%E5%8D%97"&gt;Rime 定制指南&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rime/rime-prelude/blob/master/key_bindings.yaml"&gt;自定义快捷键&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/lotem/5440677"&gt;自定义短语&lt;/a&gt;，基于雾凇拼音修改
&lt;ul&gt;
&lt;li&gt;私人词库虽好用，但限制在拼音的框架中，而自定义短语大大拓展了可能性，随便举几例🌰&lt;/li&gt;
&lt;li&gt;链接，是的，只用词库你绝对想不到自定义短语还能这样，比如输入 &lt;code&gt;tuna&lt;/code&gt; 触发 &lt;code&gt;https://mirrors.tuna.tsinghua.edu.cn&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;颜文字，比如输入 &lt;code&gt;ciallo&lt;/code&gt; 触发 Ciallo～(∠・ω&amp;lt; )⌒☆&lt;/li&gt;
&lt;li&gt;特殊符号，极简 LaTeX，输入 &lt;code&gt;forall&lt;/code&gt; 触发 &lt;code&gt;∀&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;双语映射/规范输出，再也不会出现「都是片假名鬼记得住啊」的情况
&lt;ul&gt;
&lt;li&gt;例 1: 输入 &lt;code&gt;shizuku&lt;/code&gt; 触发 &lt;code&gt;雫&lt;/code&gt; 和 &lt;code&gt;しずく&lt;/code&gt; &lt;del&gt;比『日本汉字的汉语读音规范（草案）』的 &lt;code&gt;xià&lt;/code&gt; 更好记&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;例 2: 输入 &lt;code&gt;escude&lt;/code&gt; 触发 &lt;code&gt;Escu:de&lt;/code&gt; 和 &lt;code&gt;エスクード&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;例 3: 输入 &lt;code&gt;luolishen&lt;/code&gt; 触发 &lt;code&gt;粛聖！！ロリ神レクイエム☆&lt;/code&gt; 和 &lt;code&gt;肃圣！！萝莉神的安魂曲☆&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;虽然私人词库也可以实现类似（但更弱）的功能，但这里的输入词和触发词可以无限拓展，而词库不行&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;示例对应的 custom_phrase.txt 节选&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 词汇&amp;lt;Tab&amp;gt;编码&amp;lt;Tab&amp;gt;权重&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;https://mirrors.tuna.tsinghua.edu.cn tuna&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Ciallo～(∠・ω&amp;lt; )⌒☆ ciallo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;∀ forall 10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;雫 shizuku&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;しずく shizuku&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Escu:de escude&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;エスクード escude&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;粛聖！！ロリ神レクイエム☆ luolishen&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;肃圣！！萝莉神的安魂曲☆ luolishen&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/hchunhui/librime-lua/wiki/Scripting"&gt;Lua 脚本&lt;/a&gt;: 自定义短语是低配 espanso，librime-lua 则是真正的 espanso 平替&lt;/li&gt;
&lt;li&gt;Fcitx5 主题
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/btstream/fcitx5-skin-base16-material-darker"&gt;fcitx5-skin-base16-material-darker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/hosxy/fcitx5-dark-transparent"&gt;fcitx5-dark-transparent&lt;/a&gt;，修改自 &lt;a href="https://github.com/evansan/fcitx5-dark"&gt;fcitx5-dark&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.coelacanthus.moe/posts/tech/welcome-to-fcitx5/#%E4%B8%BB%E9%A2%98%E7%BE%8E%E5%8C%96"&gt;拥抱 Fcitx5&lt;/a&gt; 一文附有许多预览图，可以逐一尝试感兴趣的主题&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/fkxxyz/ssfconv"&gt;ssfconv&lt;/a&gt;，搜狗输入法皮肤转 Fcitx 主题，未实际尝试&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="同步"&gt;同步&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rime/home/wiki/UserGuide#%E8%A8%AD%E5%AE%9A%E5%90%8C%E6%AD%A5%E4%BD%8D%E7%BD%AE"&gt;自定义 sync 文件夹&lt;/a&gt;: 修改用户文件夹的 &lt;code&gt;installation.yaml&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yml" data-lang="yml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;installation_id&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;void&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;sync_dir&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;/path/to/RimeSync&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;fcitx5-rime 配置备份: 不像 ibus-rime 使用反人类的 dconf，直接备份 &lt;code&gt;~/.config/fcitx5&lt;/code&gt; 即可&lt;/li&gt;
&lt;li&gt;换机：复制同步文件夹，配置新机的 &lt;code&gt;installation.yaml&lt;/code&gt;，部署 -&amp;gt; 同步 -&amp;gt; 部署&lt;/li&gt;
&lt;li&gt;文件夹默认位置&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;文件夹&lt;/th&gt;
&lt;th&gt;fcitx5-rime&lt;/th&gt;
&lt;th&gt;weasel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;共享&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/usr/share/rime-data/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;安装目录&amp;gt;\data&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;用户&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.local/share/fcitx5/rime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;%APPDATA%\Rime&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;同步&lt;/td&gt;
&lt;td&gt;见 &lt;code&gt;installation.yaml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;同左&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;用户文件夹结构
&lt;ul&gt;
&lt;li&gt;不能直接覆盖更新的: custom_phrase.txt, rime_ice.{dict,schema}.yaml, symbols_v.yaml&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ eza --tree ~/.local/share/fcitx5/rime
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── build &lt;span style="color:#75715e"&gt;# 构建缓存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── cn_dicts &lt;span style="color:#75715e"&gt;# 词库&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── *.dict.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── moegirl.dict.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── private.dict.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── web-slang.dict.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── zhwiktionary.dict.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── en_dicts
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── *.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── *.dict.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── lua &lt;span style="color:#75715e"&gt;# Lua 脚本&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── *.lua
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── opencc &lt;span style="color:#75715e"&gt;# Emoji、繁简转换、字符映射&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── emoji.json
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── emoji.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── others.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── *.userdb &lt;span style="color:#75715e"&gt;# 用户词典, e.g. rime_ice.userdb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── custom_phrase.txt &lt;span style="color:#75715e"&gt;# 自定义短语&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── default.yaml &lt;span style="color:#75715e"&gt;# 全局配置，不要修改&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── default.custom.yaml &lt;span style="color:#75715e"&gt;# 全局配置补丁&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── *.schema.yaml &lt;span style="color:#75715e"&gt;# 输入方案配置, e.g. rime_ice.schema.yaml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── *.dict.yaml &lt;span style="color:#75715e"&gt;# 词库配置, e.g. rime_ice.dict.yaml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── *.custom.yaml &lt;span style="color:#75715e"&gt;# 补丁, e.g. rime_ice.custom.yaml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── installation.yaml &lt;span style="color:#75715e"&gt;# 安装配置，用于修改同步目录&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── user.yaml &lt;span style="color:#75715e"&gt;# 用户状态&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="迁移"&gt;迁移&lt;/h2&gt;
&lt;div class="admonition admonition-warning"&gt;
&lt;div class="admonition-heading"&gt;
⚠️
Warning
&lt;/div&gt;
&lt;div class="admonition-content"&gt;
&lt;p&gt;下面的方法过于简单粗暴，而且受限于 OpenCC，更建议参考对应输入方案/词库的说明进行迁移。再不济也建议参考 &lt;a href="https://github.com/Mintimate/rime-userdb-maker"&gt;rime-userdb-maker&lt;/a&gt; 写个一次性转换工具，避免后续反复排查用户词典的烦恼。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;del&gt;主要是用户词典迁移，词库只要在 &lt;code&gt;schema.yaml&lt;/code&gt; 改改就能用，以明月拼音简体 -&amp;gt; 雾凇拼音的迁移为例。&lt;/del&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 切换到同步文件夹&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd path/to/sync_dir
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 重命名用户词典&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cp luna_pinyin.userdb.txt rime_ice.userdb.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 更新用户词典名称&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sed &lt;span style="color:#e6db74"&gt;&amp;#39;s/luna_pinyin/rime_ice/&amp;#39;&lt;/span&gt; rime_ice.userdb.txt &amp;gt; raw.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 使用 OpenCC 进行简-&amp;gt;繁转换&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;opencc -c t2s -i raw.txt -o mod.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 检查处理结果&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim mod.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 替换词库，删除中间产物&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cp mod.txt rime_ice.userdb.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rm mod.txt raw.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="trime"&gt;Trime&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/osfans/trime/wiki/UserGuide"&gt;文件夹结构&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;同步文件夹设置见 &lt;code&gt;installation.yaml&lt;/code&gt;，不跟 Trime 设置走&lt;/li&gt;
&lt;li&gt;rime 文件夹: &lt;code&gt;/sdcard/Aka/rime&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;同步文件夹: &lt;code&gt;/sdcard/Aka/backup/trime&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;配置（伪 YAML）&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yml" data-lang="yml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;schemata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;雾凇拼音&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# - 中文九键&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# - 小鹤双拼&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;profile/storage/user directory&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;/sdcard/emulated/0/Aka/rime/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;candidates window/show&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;disable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;keyboard style&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;themes&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;标准&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;colors&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;孤寺改 / Lost Temple Kai&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;clipboard&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;history limit&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;suggestion timeout&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="nimf"&gt;nimf&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/hamonikr/nimf"&gt;nimf&lt;/a&gt; 是韩国人开发的输入法，CJK 开箱即用，另有 nimf-i18n 拓展 100+ 语言的支持。
但是因为过于小众，只有零星的文档提及，写个配置流程，以飨后人。
在 Void 通过 xdeb 安装会吞 libnimf.so，这里使用的是 Kali Live 2025.4。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/hamonikr/nimf/wiki"&gt;wiki&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;下载 &lt;code&gt;nimf_xxx_amd64-debian.trixie.deb&lt;/code&gt;（本体已经附带 librime 在内的 CJK 支持，不需要安装用于追加语言的 &lt;code&gt;nimf-i18n&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;先手动安装依赖再 &lt;code&gt;sudo dpkg -i&lt;/code&gt; 并启动服务&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# kali&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo systemctl enable ssh --now
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# host&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rsync -av ./nimf*.deb kali:~/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ssh kali
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# kali&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt install anthy libanthy1t64 libgtk2.0-0t64 libhangul1 libhangul-data librime1t64 fonts-noto-cjk
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo dpkg -i nimf_*_amd64-debian.trixie.deb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo systemctl enable nimf --now
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim .xprofile
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;参考 &lt;a href="https://github.com/hamonikr/nimf/wiki/Installation-Guide"&gt;Installation Guide&lt;/a&gt; 配置环境变量&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# .xprofile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export XMODIFIERS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;@im&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nimf
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export GTK_IM_MODULE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nimf
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export QT_IM_MODULE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nimf
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export QT_QPA_PLATFORM&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xcb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export QT4_IM_MODULE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xim
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Wayland only, force X11 execution&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# export GDK_BACKEND=x11&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;log out &amp;amp; log in，检测下来环境变量设置都正常&lt;/li&gt;
&lt;li&gt;运行 nimf-settings，不过也没什么好配置的&lt;/li&gt;
&lt;li&gt;Rime 配置文件和 iBus/fcitx5 一样，就是路径换下，复制到 &lt;code&gt;~/.config/nimf/rime&lt;/code&gt; 即可&lt;/li&gt;
&lt;li&gt;部署似乎需要进入 &lt;code&gt;~/.config/nimf/rime&lt;/code&gt; 运行 &lt;code&gt;rime_deployer --build&lt;/code&gt;，保险起见我手动设置了默认 schema&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd ~/.config/nimf/rime
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rime_deployer --build
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rime_deployer --set-active-schema rime_ice
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;再次 log out &amp;amp; log in，可以输入中文&lt;/li&gt;
&lt;li&gt;ldd 看默认没链接 lua，但是 Kali Live 安装 rime 默认会安装 librime-plugin-lua，实际也能触发雾凇的 Lua 脚本，应该没什么问题&lt;/li&gt;
&lt;li&gt;其实在 X11 使用完全凸显不出 nimf 的优势，看 nimf 文档，Wayland 兼容性要比 fcitx5-rime 好，然鹅我还苟在 Xfce4，等 Xfwl4 发布或者迁移到 niri 再测试&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="吐槽"&gt;吐槽&lt;/h2&gt;
&lt;p&gt;很多人对 Rime 架构的理解都存在偏差，容易混淆的内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;输入方案&lt;/li&gt;
&lt;li&gt;词库/自定义短语/用户词典&lt;/li&gt;
&lt;li&gt;键位/皮肤&lt;/li&gt;
&lt;li&gt;OpenCC 转换/emoji/符号映射&lt;/li&gt;
&lt;li&gt;Lua 脚本&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;比如雾凇拼音，输入方案虽然有所涉及，但主要还是词库 + 符号映射 + Lua 脚本，
不少用户都是默默用全拼，就图个「词库」和「符号映射」，
小鹤双拼、小鹤音形、虎码这种才叫「输入方案」。&lt;/p&gt;
&lt;p&gt;很多 Linux 发行版都打包了 fcitx5-rime 和 librime，但 librime-lua 支持比较玄学。
没打包、版本过时、依赖过时都很常见，想要最佳体验还是得自己编译，挺麻烦的……
更不提 Wayland 和 Qt/GTK 等 GUI 框架的破事，有时候 &lt;code&gt;fcitx5-diagnose&lt;/code&gt; 没报错也不代表能用……&lt;/p&gt;
&lt;h2 id="todo"&gt;TODO&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;文档
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/osfans/trime/wiki/Theme-Configuration-%28New%29"&gt;主题配置（新）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mintimate.cc/zh/guide/"&gt;薄荷输入法 配置教程&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;主题
&lt;ul&gt;
&lt;li&gt;Fcitx5 DIY Kali 配色主题&lt;/li&gt;
&lt;li&gt;Trime 配色：孤寺改·改&lt;/li&gt;
&lt;li&gt;Weasel 禁用日志, cmake &lt;code&gt;-DENABLE_LOGGING=OFF&lt;/code&gt;?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;定制
&lt;ul&gt;
&lt;li&gt;迁移特定主题的短语至 V 模式
&lt;ul&gt;
&lt;li&gt;custom_phrase.txt -&amp;gt; symbols_v.yaml&lt;/li&gt;
&lt;li&gt;e.g. vbbc, vhugo, vmd, vlnk, vdio, vgal&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/osfans/trime/wiki/trime.yaml-%E8%A9%B3%E8%A7%A3#%E7%A4%BA%E4%BE%8B%E6%96%B0%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%89%AF%E9%94%AE%E7%9B%98"&gt;副键盘&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;librime-lua
&lt;ul&gt;
&lt;li&gt;Lua 脚本需要在 &lt;code&gt;engine/translators/lua_translator&lt;/code&gt; 注册，可以使用新引入方式&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tumuyan/trime-without-CMake/wiki/%E5%90%8C%E6%96%87%E6%8C%89%E9%94%AE%E9%9F%B3%E6%95%88"&gt;按键音效包&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.bilibili.com/video/av294986768/"&gt;音效包演示&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;💡 Trime 音效包：李云龙、新三国 曹操语气词（大魏摩托）、新三国 键帽 语音版、hentai feat. &lt;a href="https://blog.vinfall.com/posts/2022/09/moegoe/"&gt;MoeGoe&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;输入方案
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://shurufa.app"&gt;宇浩输入法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/gaboolic/rime-shuangpin-fuzhuma"&gt;墨奇音形&lt;/a&gt;，双拼辅助码&lt;/li&gt;
&lt;li&gt;顶功类输入法&lt;/li&gt;
&lt;li&gt;日语输入 via mozc? ref. &lt;a href="https://sspai.com/post/92346"&gt;电脑日语输入简明指南&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;粤拼&lt;/li&gt;
&lt;li&gt;IPA&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;输入法
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Mintimate/oh-my-rime"&gt;oh-my-rime&lt;/a&gt;，薄荷输入法&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/gurecn/YuyanIme"&gt;YuyanIme&lt;/a&gt;，语燕输入法&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/fcitx5-android/fcitx5-android"&gt;fcitx5-android&lt;/a&gt;, 支持自定义按键布局的 &lt;a href="https://github.com/fxliang/fcitx5-android"&gt;fork&lt;/a&gt;, &lt;a href="https://sspai.com/post/108459"&gt;少数派介绍&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;词库
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/amzxyz/rime_wanxiang"&gt;万象拼音&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/gaboolic/rime-frost"&gt;白霜拼音&lt;/a&gt;，基于雾凇拼音重制的词库&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;编译/安装: fcitx5-rime w/ rime-ice on NixOS&lt;/li&gt;
&lt;/ul&gt;</description><category domain="/tags/">Ime</category><category domain="/tags/">Windows</category><category domain="/tags/">Android</category><category domain="/tags/">Linux</category><category domain="/tags/">Lua</category></item><item><title>文本编辑器的基础方程式</title><link>https://blog.vinfall.com/posts/2024/08/text-editor/</link><pubDate>2026-06-01</pubDate><author>Vinfall</author><guid>https://blog.vinfall.com/posts/2024/08/text-editor/</guid><summary>Vim, or emacs evil mode, that is the question.</summary><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;&lt;del&gt;在 &lt;a href="https://blog.vinfall.com/posts/2023/09/zen-of-windows/#%E6%8E%A8%E8%8D%90"&gt;我的 Windows 软件之道#推荐&lt;/a&gt; 我曾提到代码编辑用的是去除遥测并且使用 Open VSX 的 &lt;a href="https://github.com/VSCodium/vscodium"&gt;VSCodium&lt;/a&gt;。&lt;/del&gt; 已改用 Zed，见 &lt;a href="https://blog.vinfall.com/posts/2026/03/vsc2zed/"&gt;VSC -&amp;gt; Zed 迁移&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;实际上我也在使用 Notepad++（下文简称 npp）。由于 npp 作者抱有强烈的政治参与感，三天两头被口诛笔伐。虽然我并不在意&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;，但时不时看到互撕也会心烦，早就有了迁移的想法。可惜试来试去，大多在某些方面差强人意。&lt;/p&gt;
&lt;p&gt;前几天在 &lt;a href="https://news.ycombinator.com/item?id=41297609"&gt;HackerNews&lt;/a&gt; 看到 &lt;a href="https://github.com/pragtical/pragtical"&gt;pragtical&lt;/a&gt;，看 commit 记录一直在更新，SDL + Lua + C 的组合也不错，于是尝试和对比了一番，在官方火速修复 LuaJIT 关于 Windows Unicode 路径的 bug 之后彻底迁移，自此告别 npp。&lt;/p&gt;
&lt;h2 id="要求"&gt;要求&lt;/h2&gt;
&lt;p&gt;前言说了一堆还没点题，npp 迁移之所以耗时几年，是因为我对文本编辑器的选择很挑剔。
下面列举的仅仅是需要满足的 &lt;strong&gt;最基本要求&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;UTF-8/UTF-16-LE 支持，能够打开&lt;strong&gt;并修改&lt;/strong&gt;特定文件编码（至少支持 Shift-JIS / GB-2312 / GBK-5 / CP437&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt; / CP866）&lt;/li&gt;
&lt;li&gt;支持转换 EOL（最好支持移除行首/行末多余空格，以及 Tab/Space 相互转换）&lt;/li&gt;
&lt;li&gt;支持 text wrap 和最最基本的文本补全（最好支持 tokenizer）&lt;/li&gt;
&lt;li&gt;支持正则匹配，可以一次性全部替换&lt;/li&gt;
&lt;li&gt;支持&lt;strong&gt;深色模式&lt;/strong&gt;（最好可以自定义主题/配色，支持/内置 monokai）&lt;/li&gt;
&lt;li&gt;打开 100M 以内文件耗时在合理范围（最好 1G 以上文件 100% 加载时间在半分钟以内）&lt;/li&gt;
&lt;li&gt;提供&lt;strong&gt;便携版&lt;/strong&gt;（除非安装包尺寸在 20M 以内）&lt;/li&gt;
&lt;li&gt;支持批量操作文件后缀名关联（绑定与解绑）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;冷启动速度不超过 3 秒&lt;/strong&gt;（最好是秒启动）&lt;/li&gt;
&lt;li&gt;开源（如果是闭源，必须支持 100 款以上插件）&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="解释"&gt;解释&lt;/h2&gt;
&lt;p&gt;稍微解释一下几个点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UTF-8 支持看似简单，但实际做起来坑也挺多的，更别提 emoji/Unicode/RTL 文字等等，iOS 三天两头爆个无限重启 bug。Pragtical 虽然支持编码/EOL，但默认字体显示不了 CJK 字符和 emoji，手动添加字体即可&lt;/li&gt;
&lt;li&gt;Text wrap (line wrap) 就是如果一行的内容在程序宽度范围写不下，会自动显示成多行，而不用左右拉进度条&lt;/li&gt;
&lt;li&gt;Tokenizer 即标记器，NLP 里一般就是分词或者特殊的标志词（比如 &lt;a href="https://blog.vinfall.com/posts/2022/09/moegoe/#%E6%96%B0%E7%89%88%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95"&gt;MoeGoe&lt;/a&gt; 里的 &lt;code&gt;[ZH]&lt;/code&gt; 等语法标记块），算是 hidden gem
&lt;ul&gt;
&lt;li&gt;比如在排版的时候，很多时候左对齐、右对齐、居中对齐都很丑，如果有 tokenizer 根据语义分行，就不会出现一个词跨&lt;/li&gt;
&lt;li&gt;行这种难受的现象。&lt;/li&gt;
&lt;li&gt;又比如双击文本选中，这个功能看似简单，但在不借助 linter 的情况下，如果没有 tokenizer，双击中文词会把旁边一堆英文也选中（比如双击 &lt;code&gt;GBK-5/Shift-JIS编码&lt;/code&gt; 中的 &lt;code&gt;编码&lt;/code&gt;，会选中整行）；或者想要选中 &lt;code&gt;支持深色模式&lt;/code&gt; 的 &lt;code&gt;深色&lt;/code&gt;，你需要用鼠标准确地选中 &lt;code&gt;深色&lt;/code&gt; 两个字，不能太左，也不能太右。而有了分词器，直接双击 &lt;code&gt;深&lt;/code&gt; 或 &lt;code&gt;色&lt;/code&gt; 字，即可直接选中 &lt;code&gt;深色&lt;/code&gt; 这个词语。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;正则匹配看似寥寥四字，但是正则标准诸多（Perl/POSIX/PCRE/Vim/ECMAScript/Python/Golang/C#/Rust…），一个隐性要求是&lt;strong&gt;正常&lt;/strong&gt;的正则实现，而不是自己做的莫名其妙的标准&lt;/li&gt;
&lt;li&gt;深色模式这点，npp 也花了好多年才做出比较正常的效果，很多开发者自己瞎做的深色模式真是惨不忍睹，对比度低得要死，更别提色弱/色盲模式，乃至多种色弱/盲模式。Pragtical 默认配色比 monokai 和 github-dark-dimmed 都好看，就不折腾了&lt;/li&gt;
&lt;li&gt;100M/1G 文件测试算是很基本的要求，有的奇葩公司（比如 Facebook）能整出 10G 甚至 100G JSON 文件，为什么不用数据库？我也不造啊🤷 Linux 能用 pager，Windows 虽然有 vim/Gvim，但系统自带的 PowerShell 实在是丑，Windows Terminal 在有的环境又无法正常显示，一般这种情况我就上 hex viewer 了，简单粗暴&lt;/li&gt;
&lt;li&gt;便携的需求应该很自然，毕竟文本编辑器满地都是，配置非常琐碎，不像流行的浏览器内核，一只手都数得过来，还能用 policy-templates 一劳永逸。尺寸要求就是针对 Electron，别和我说 UI 和开发难度，满地都是的软件不用 Electron/CEF 就不能做，说出来也没人相信。Pragtical 哪怕是 AppImage 也只有 5M 大小&lt;/li&gt;
&lt;li&gt;文件关联这点也是出于批量部署的考量 &lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;，其实 pragtical 不支持，但其他方面都做得挺好，就放过了&lt;/li&gt;
&lt;li&gt;冷启动速度，嗯，就是针对 Electron 的
&lt;ul&gt;
&lt;li&gt;3s 的限制太过宽松，哪怕收紧到 1s 绝大多数编辑器也都符合要求。当然，绝大多数编辑器 &lt;sup id="fnref:4"&gt;&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref"&gt;4&lt;/a&gt;&lt;/sup&gt; 都不能打开 10G JSON，也不能在 30s 内完全加载 1G JSON（内存 32G，系统内存占用 2G，管够），也可以说都不符合要求= =&lt;/li&gt;
&lt;li&gt;npp 速度不慢，没想到 pragtical 还能更上一层楼。测试方法：&lt;a href="https://www.passmark.com/products/apptimer/"&gt;AppTimer&lt;/a&gt;，检测窗口名称，启动 6 次，间隔 100ms&lt;sup id="fnref:5"&gt;&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref"&gt;5&lt;/a&gt;&lt;/sup&gt;，&lt;code&gt;WM_CLOSE&lt;/code&gt; 方法关闭，取平均值&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;C:\tools\pragtical\pragtical&lt;span style="color:#f92672"&gt;.&lt;/span&gt;exe &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; executions
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0.1965&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0.1853&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0.1850&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0.1975&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0.1955&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0.1774&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;C:\tools\npp\notepad&lt;span style="color:#f92672"&gt;++.&lt;/span&gt;exe &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; executions
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0.2159&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0.2182&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0.2019&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0.2079&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0.2005&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0.2054&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="后记"&gt;后记&lt;/h2&gt;
&lt;p&gt;写完感觉有点虎头蛇尾，anyway 就这样吧。之前没怎么接触 Lua，为数不多的经验就是 Pico-8 和 Godot 开发，但 Pico-8 是自己实现的 Lua，很多标准库不能用，而 Godot 的 LuaAPI 隐约记得不是官方支持，还是 GDScript 为主流。在 pragtical 的 Plugin Manager 看很多插件的源码都很简单，后面可能写几个插件练练手，也算是回馈社区。&lt;/p&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;我多年来对于写作的观点是，文品与人品毫无关联，纯属后人牵强附会。引申出来的广泛观点也让我对各种撕逼/互锤、饭圈文化、影视剧封杀现象冷眼相看。凯恩斯有句话（虽然关于出处一直有各种看法）：&lt;em&gt;When the Facts Change, I Change My Mind. What Do You Do, Sir?&lt;/em&gt; 不能通过上帝视角看待问题，总归是有各种偏见和不客观的地方。乔布斯是个人渣，并不妨碍人们欣赏他做的产品。很多娱乐界的&lt;em&gt;明星&lt;/em&gt;私生活混乱，何必封死现有文化产品的消费，不让产出新的产品即可。同理，小众文化圈地自萌，剑走偏锋都鲜有人管（当然这是有问题的），但大搞殖民主义&lt;span class="hover-change"&gt;&lt;span class="hover-before"&gt;攻城掠地&lt;/span&gt;&lt;span class="hover-after"&gt;侵略领土&lt;/span&gt;&lt;/span&gt;我就看不下去了。&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;用作显示 warez 社区分发软件常用的 .nfo 文件。CP437 即 IBM-PC/DOS 字符集，不同编辑器叫法可能不一样: IBM437, OEM-US, OEM 437……同理，后面的 CP866 则是 DOS Cyrillic Russian，当时苏联用的编码，嗯，这玩意儿遥远到苏联还没解体……当然欧洲也有其他的编码，但是碰到的概率相对小得多。&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;为了方便装机，又搓了个 file-assoc-reg 脚本，根据 &lt;code&gt;config.json&lt;/code&gt; 自动生成文件关联相关的注册表，这又是后话&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;刚需可以使用 EmEditor，&lt;a href="https://zh-cn.emeditor.com/text-editor-features/history/emeditor-free/"&gt;免费版&lt;/a&gt; 足够应对类似场景。EE 据说能打开 TB 级别的文件，但真遇到这种情况，可能文件系统先炸了，都没机会抢救= =&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:5"&gt;
&lt;p&gt;这里间隔设置得太短了，后面根本不是冷启动，但反正怎么测都比 npp 快就没有修正。&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category domain="/tags/">Dev</category><category domain="/tags/">Lua</category></item><item><title>How to Run VNDB Locally</title><link>https://blog.vinfall.com/posts/2026/03/local-vndb/</link><pubDate>2026-05-31</pubDate><author>Vinfall</author><guid>https://blog.vinfall.com/posts/2026/03/local-vndb/</guid><summary>So let us melt, and make no noise, No tear-floods, nor sigh-tempests move; 'Twere profanation of our joys To tell the laity our love.</summary><description>&lt;h2 id="intro"&gt;Intro&lt;/h2&gt;
&lt;p&gt;Yorhel, the founder and soul of VNDB, has died last week🕯.
This post serves as a legacy setup in case vndb.org goes offline someday.&lt;/p&gt;
&lt;p&gt;If you, as a VNDB user, are worried, you can export your list and length votes via My Visual Novel List -&amp;gt; Export -&amp;gt; Download XML export.&lt;/p&gt;
&lt;h2 id="prerequisite"&gt;Prerequisite&lt;/h2&gt;
&lt;p&gt;Before we start, let&amp;rsquo;s define VNDB.&lt;/p&gt;
&lt;p&gt;Most users are familiar with the web interface, but VNDB is not limited to that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Web UI, discussion board, changes history, private list&lt;/li&gt;
&lt;li&gt;VNDB.org API v2 (Kana), fortunately it&amp;rsquo;s bundled with vndb source code so we don&amp;rsquo;t need to set it up separately&lt;/li&gt;
&lt;li&gt;Database Dump&lt;/li&gt;
&lt;li&gt;VNDB Query, aka. SQLBin&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To have a working instance of VNDB locally, we need to make sure everything is ready. Otherwise you&amp;rsquo;ll only find your Dockerfile useless when it really happens.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Source&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;
&lt;ul&gt;
&lt;li&gt;Available as &lt;a href="https://code.blicky.net/yorhel"&gt;forgejo instance&lt;/a&gt; or &lt;a href="https://g.blicky.net"&gt;cgit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;List (per &lt;a href="https://vndb.org/d8"&gt;d8&lt;/a&gt; and SQLBin readme): fu, mithril-vndb, sqlbin, vndb, yhdev&lt;/li&gt;
&lt;li&gt;If you want to setup legacy versions of VNDB, tuwf is also needed&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dl.vndb.org/dump/"&gt;Database Dump&lt;/a&gt;: per &lt;a href="https://vndb.org/d14#5"&gt;d14#5&lt;/a&gt;, download near-complete dump, aka. &lt;code&gt;vndb-db-latest.tar.zst&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Documentation
&lt;ul&gt;
&lt;li&gt;As docs on VNDB are stored seperately, we also need to backup them seperately, which can be easily done via extensions like &lt;a href="https://www.getsinglefile.com"&gt;SingleFile&lt;/a&gt; and is not covered in this post&lt;/li&gt;
&lt;li&gt;List: d2-d20 with d11 excluded (d11 is a redirection to VNDB API v2)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Knowledge
&lt;ul&gt;
&lt;li&gt;Minimum: Linux package manager, Git, PostgreSQL&lt;/li&gt;
&lt;li&gt;Bonus: command line, init service, Vim, Perl, GNU Make&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;PC/VM Spec: 1 CPU Core, 1G RAM, 10G Disk&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="download"&gt;Download&lt;/h2&gt;
&lt;p&gt;Download source and dump:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# download source and dump&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir -p ~/projects &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cd ~/projects
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://code.blicky.net/yorhel/&lt;span style="color:#f92672"&gt;{&lt;/span&gt;fu,mithril-vndb,sqlbin,vndb,yhdev&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# if you plan to setup legacy vndb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# git clone https://code.blicky.net/yorhel/tuwf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# near-complete database: https://vndb.org/d14#5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# development database (NOT working due to schema change): https://vndb.org/d8#3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget https://dl.vndb.org/dump/vndb-db-latest.tar.zst
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# additional querying stuff for vndb query&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# https://query.vndb.org/about&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget https://query.vndb.org/extras.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# companion scripts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget https://gist.vinfall.com/Vinfall/setup-vndb-psql/download/HEAD/setup-vndb-psql.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget https://gist.vinfall.com/Vinfall/sqlbin/download/HEAD/setup-sqlbin.sql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now the file tree should look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ tree -L &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; ./
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── extras.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── fu
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── mithril-vndb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── setup-sqlbin.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── setup-vndb-psql.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── sqlbin
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── tuwf
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── vndb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── vndb-db-latest.tar.zst
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── yhdev
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; directories, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="admonition admonition-tip"&gt;
&lt;div class="admonition-heading"&gt;
💡
Tip
&lt;/div&gt;
&lt;div class="admonition-content"&gt;
&lt;p&gt;As the following commands would make VNDB inaccessible, it&amp;rsquo;s recommended to setup inside VM.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To make absolute sure the setup would work even if vndb.org and blicky.net expire,
now add these lines to &lt;code&gt;/etc/hosts&lt;/code&gt; to intentionally block them:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;127.0.0.1 vndb.org api.vndb.org dl.vndb.org query.vndb.org
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;127.0.0.1 blicky.net code.blicky.net g.blicky.net
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="setup"&gt;Setup&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ll use Alpine Linux Edge as an example to (intentionally) make it more difficult to setup, but it surely works for almost every other up-to-date distro. You might need to change &lt;code&gt;doas&lt;/code&gt; to &lt;code&gt;sudo&lt;/code&gt; and adapt apk-tools/OpenRC related commands to your package manager/init service.&lt;/p&gt;
&lt;p&gt;Also, I assume you&amp;rsquo;ll only run VNDB locally inside VM with a host-only network with only 22/3000/8000 port forwarding enabled, making data breach impossible. As a consequence, database password and salt are kept simple and stupid. You definitely need to change them and do extra hardening if for whatever reason you decide to ignore my warning and host it publicly.&lt;/p&gt;
&lt;h3 id="vndb"&gt;VNDB&lt;/h3&gt;
&lt;p&gt;Install dependencies:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# install general deps&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doas apk add build-base curl git graphviz icu-data-full pandoc uglify-js vips-dev sassc wget zlib-dev
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# install perl modules&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doas apk add perl-algorithm-diff-xs perl-anyevent perl-app-cpanminus perl-crypt-urandom perl-dbd-pg perl-dev perl-json-xs perl-module-build
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doas cpanm -nq AnyEvent::IRC AnyEvent::Pg Crypt::ScryptKDF Text::MultiMarkdown
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# install fu (another perl module)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd ~/projects/fu
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doas cpanm .
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# copy mithril.js to vndb/gen&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;install -pm644 -D ~/projects/mithril-vndb/mithril.js ~/projects/vndb/gen/mithril.js
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Build:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# build vndb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd ~/projects/vndb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make prod
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;util/setup-var.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Setup PostgreSQL Server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# setup psql server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# https://wiki.alpinelinux.org/wiki/Postgresql&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doas apk add postgresql18 postgresql18-contrib postgresql18-dev
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doas rc-update add postgresql
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doas rc-service postgresql start
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# init psql admin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doas passwd postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# su postgres&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pg_config --pkglibdir
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/lib/postgresql18
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# build psql lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make -C sql/c
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make -C sql/c install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Initialize database:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Search cache is disabled by default as the Perl maintenance script is slow &lt;em&gt;by design&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# init database&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;psql -U postgres -f sql/superuser_init.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;psql -U postgres vndb -f sql/vndbid.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;ALTER ROLE vndb LOGIN PASSWORD &amp;#39;pwd1&amp;#39;&amp;#34;&lt;/span&gt; | psql -U postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;ALTER ROLE vndb_site LOGIN PASSWORD &amp;#39;pwd2&amp;#39;&amp;#34;&lt;/span&gt; | psql -U postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;ALTER ROLE vndb_multi LOGIN PASSWORD &amp;#39;pwd3&amp;#39;&amp;#34;&lt;/span&gt; | psql -U postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# create an empty database&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# psql -U vndb -f sql/all.sql&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# OR import near complete database&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# load schema&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doas -u postgres psql -c &lt;span style="color:#e6db74"&gt;&amp;#34;ALTER ROLE vndb SUPERUSER;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;psql -U vndb -d vndb -f sql/all.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doas -u postgres psql -c &lt;span style="color:#e6db74"&gt;&amp;#34;ALTER ROLE vndb NOSUPERUSER;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tar -C var --zstd -xf ../vndb-db-latest.tar.zst
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chmod +x setup-vndb-psql.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./setup-vndb-psql.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Configure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim var/conf.pl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-diff" data-lang="diff"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;form_salt =&amp;gt; &amp;#39;&amp;lt;some unique string&amp;gt;&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scrypt_salt =&amp;gt; &amp;#39;&amp;lt;another unique string&amp;gt;&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_site =&amp;gt; &amp;#39;dbname=vndb user=vndb_site password=pwd2&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db_task =&amp;gt; &amp;#39;dbname=vndb user=vndb password=pwd1&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-cookie_defaults =&amp;gt; { domain =&amp;gt; &amp;#39;localhost&amp;#39;, path =&amp;gt; &amp;#39;/&amp;#39; },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;+cookie_defaults =&amp;gt; { path =&amp;gt; &amp;#39;/&amp;#39; },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# start dev server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;util/vndb-dev-server.pl
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# start prod server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# util/vndb.pl --fcgi=unix:/tmp/vndb-fastcgi.sock --proc=4 --max-reqs=5000:10000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# housekeeping&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# util/task.pl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now head to &lt;a href="http://127.0.0.1:3000"&gt;http://127.0.0.1:3000&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="api"&gt;API&lt;/h3&gt;
&lt;p&gt;We already install pandoc and uglify-js and run &lt;code&gt;make prod&lt;/code&gt; in &lt;a href="https://blog.vinfall.com/posts/2026/03/local-vndb/#vndb"&gt;#VNDB&lt;/a&gt;, so just head to &lt;a href="http://127.0.0.1:3000/api/kana"&gt;http://127.0.0.1:3000/api/kana&lt;/a&gt;. You can&amp;rsquo;t use API button in the homepage as it&amp;rsquo;s hardcoded.&lt;/p&gt;
&lt;h3 id="sqlbin"&gt;SQLBin&lt;/h3&gt;
&lt;p&gt;Compile and Install:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# install deps&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doas apk add autoconf automake crystal libcerf-dev libseccomp-dev shards sqlite-dev
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# build sqlbin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd ~/projects/sqlbin
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;shards
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make release
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# build customized gnuplot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd gnuplot &lt;span style="color:#75715e"&gt;# this IS correct&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./build.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# install&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doas install gnuplot-sqlbin /usr/local/bin/gnuplot-sqlbin
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd ..
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doas install bin/sqlbin /usr/local/bin/sqlbin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Setup read-only PostgreSQL user:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As we only run it locally, there is no need to import yet another database dump for SQLBin, just setup a seperate read-only user&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.postgresql.org/docs/current/runtime-config-client.html"&gt;Runtime Config&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;psql -U postgres -d vndb -f ~/projects/setup-sqlbin.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# psql -U postgres -d vndb -f extras.sql&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-postgresql" data-lang="postgresql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- ~/projects/setup-sqlbin.sql
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ROLE&lt;/span&gt; sqlbin LOGIN &lt;span style="color:#66d9ef"&gt;PASSWORD&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;secure_passwd&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;GRANT&lt;/span&gt; CONNECT &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DATABASE&lt;/span&gt; vndb &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; sqlbin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;GRANT&lt;/span&gt; USAGE &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SCHEMA&lt;/span&gt; public &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; sqlbin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- grant read access to all tables
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;GRANT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ALL&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SCHEMA&lt;/span&gt; public &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; sqlbin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;GRANT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ALL&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SEQUENCES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SCHEMA&lt;/span&gt; public &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; sqlbin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;GRANT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EXECUTE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ALL&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FUNCTIONS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SCHEMA&lt;/span&gt; public &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; sqlbin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- OR grant on a per-table basis
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- GRANT SELECT ON vn, releases, producers, chars, tags TO sqlbin;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- grant access to tables not yet created
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIVILEGES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SCHEMA&lt;/span&gt; public &lt;span style="color:#66d9ef"&gt;GRANT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; sqlbin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIVILEGES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SCHEMA&lt;/span&gt; public &lt;span style="color:#66d9ef"&gt;GRANT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SEQUENCES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; sqlbin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIVILEGES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SCHEMA&lt;/span&gt; public &lt;span style="color:#66d9ef"&gt;GRANT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EXECUTE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FUNCTIONS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; sqlbin;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- defense in depth
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ROLE&lt;/span&gt; sqlbin_user &lt;span style="color:#66d9ef"&gt;SET&lt;/span&gt; timezone &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Asia/Shanghai&amp;#39;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;-- change to your timezone
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ROLE&lt;/span&gt; sqlbin_user &lt;span style="color:#66d9ef"&gt;SET&lt;/span&gt; statement_timeout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;5s&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ROLE&lt;/span&gt; sqlbin_user &lt;span style="color:#66d9ef"&gt;SET&lt;/span&gt; default_transaction_read_only &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Test the newly created &lt;code&gt;sqlbin&lt;/code&gt; user:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# success&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ psql -U sqlbin -d vndb -c &lt;span style="color:#e6db74"&gt;&amp;#34;SELECT count(*) FROM vn;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;count
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;61144&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; row&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# intended failure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ psql -U sqlbin -d vndb -c &lt;span style="color:#e6db74"&gt;&amp;#34;INSERT INTO users (id, username) VALUES (&amp;#39;u999&amp;#39;, &amp;#39;attacker&amp;#39;);&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR: cannot execute INSERT in a read-only transaction
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Configure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir -p ~/.config/sqlbin
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim ~/.config/sqlbin/config.ini
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chmod &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt; ~/.config/sqlbin/config.ini
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;[server]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;db&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;postgresql://sqlbin:secure_passwd@127.0.0.1:5432/vndb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;storage&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;~/.local/share/sqlbin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;tcp://0.0.0.0:8000/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;gnuplot_path&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/usr/local/bin/gnuplot-sqlbin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sqlbin -c ~/.config/sqlbin/config.ini
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now head to &lt;a href="http://127.0.0.1:8000"&gt;http://127.0.0.1:8000&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="misc"&gt;Misc&lt;/h2&gt;
&lt;p&gt;Prune PostgreSQL database to start over/import new dump:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# prune database&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doas rc-service postgresql stop
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doas apk del postgresql18 postgresql18-contrib postgresql18-dev
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doas rm -rf /var/lib/postgresql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Test sqlbin config:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;psql &lt;span style="color:#e6db74"&gt;&amp;#34;postgresql://sqlbin:secure_passwd@127.0.0.1:5432/vndb&amp;#34;&lt;/span&gt; -c &lt;span style="color:#e6db74"&gt;&amp;#34;SELECT 1;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Revoke table access of &lt;code&gt;sqlbin&lt;/code&gt; user:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-postgresql" data-lang="postgresql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;REVOKE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; schema_version, changes &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; sqlbin;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Also, please do NOT upload source code to GitHub. &lt;a href="https://yorhel.nl"&gt;yorhel.nl&lt;/a&gt; explicitly mentions that &lt;em&gt;You will not find me on closed networks such as Discord, Facebook, Github, LinkedIn, Twitter, etc&lt;/em&gt; and I hope you respect that, for the time being at least.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;If you don&amp;rsquo;t cache searches, the required disk space would be significantly smaller (2G-ish), but many things also work slower. This only includes the system, source code, build files and cached database. Images are not counted and would take extra 45G space (which is strongly discouraged to sync, if you have no plan to host it publicly).&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category domain="/tags/">Vndb</category><category domain="/tags/">Setup</category><category domain="/tags/">Sql</category><category domain="/tags/">Psql</category><category domain="/tags/">Perl</category></item></channel></rss>