博客框架迁移:从 Jekyll 到 Hugo

前言 之前的博客基于 Jekyll + Hux Blog 主题,用了快一年,总觉得不太顺手。Jekyll 是 Ruby 生态,本地构建慢,主题样式偏重(大图背景、多栏布局),对我这种只想简洁写文章的人来说有点臃肿。 于是决定迁移。目标是: 🚀 更快的构建速度 🎨 极简的页面风格 —— 无背景图、干净利落 🔧 少折腾 —— 配置简单,开箱即用 📝 保留所有文章和资源 最终选择了 Hugo + PaperMod 主题。 为什么选 Hugo? 特性 Jekyll Hugo 语言 Ruby Go 构建速度 ~5-10 秒 ~250ms 安装 需 Ruby + Gem 单二进制 配置 _config.yml hugo.toml 主题生态 丰富 丰富 Hugo 最大的优势就是快——单二进制文件,没有任何依赖,构建 55 篇文章只要 250ms。PaperMod 主题默认就是白色极简风格,没有大图背景,几乎没有需要改动的地方。 迁移做了什么 1. 文章转换(55 篇) 原来的 Jekyll 文章格式: 1 2 3 4 5 6 7 8 9 --- layout: post title: "Introduction to Linear Programing" date: 2025-09-14 23:54:39 +0800 author: "farmer3-c" header-img: "img/post-bg-2015.jpg" mathjax: true tags: [] --- 转换为 Hugo 格式: ...

June 28, 2026 · 2 min · farmer3-c

wsl2到wsl1

前因 之前想在Windows上使用Linux系统,wsl很方便(为Windows用户提供了Linux环境,不需要装系统什么的)。但是不知道为什么,启动wsl的时间越来越长,从一开始的十几秒到后来的几分钟,实在让我不能忍受。我原来使用的是WSL 2,发现WSL 1 不依赖 Hyper-V 虚拟化,它直接共享 Windows 主机的 IP,启动会很快,所以试试转为 WSL 1。 过程 在 PowerShell 中逐条执行以下命令: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # 1. 备份当前环境 wsl --export Ubuntu-22.04 D:\wsl-backup.tar # 2. 转换为 WSL 1 wsl --set-version Ubuntu-22.04 1 # 3. 彻底重启 WSL wsl --shutdown # 4. 测试启动速度 Measure-Command { wsl -d Ubuntu-22.04 --exec true } # 5. 测试网络 wsl -d Ubuntu-22.04 # 进入 WSL 后,运行: ping baidu.com 结果: ...

June 18, 2026 · 1 min · farmer3-c

本地文件目录推送到GitHub上同名空repository

在 GitHub 建同名、完全空的仓库(不要勾选 README/.gitignore),本地目录用 git init→git add .→git commit→git remote add origin→git push -u origin main 即可一次性推上去。 下面是完整操作(Windows/Mac/Linux 通用): 一、准备工作 安装 Git: 终端输入: 1 git --version 能显示版本就说明已安装;没有就先装 Git。 在 GitHub 建同名空仓库 右上角点 + → New repository Repository name:和你本地文件夹同名 不要勾选:Add a README file、.gitignore、License 点 Create repository 复制仓库地址(HTTPS 或 SSH),例如: 1 https://github.com/你的用户名/仓库名.git 二、本地操作 打开终端(Git Bash / Terminal / PowerShell),进入你要上传的本地目录根目录: 1 cd /path/to/你的本地文件夹 # Windows 示例:cd D:\my-project 1. 初始化为 Git 仓库 1 git init 2. 添加所有文件到暂存区 1 git add . (想忽略某些文件,新建 .gitignore 写规则,比如 node_modules/、*.log) ...

June 12, 2026 · 1 min · farmer3-c

编译实践Lv1.main函数

目的 实现一个能处理 main 函数和 return 语句的编译器.编译器可以将如下的 SysY 程序: int main() { // 注释也应该被删掉哦 return 0; } 编译为对应的 Koopa IR: fun @main(): i32 { %entry: ret 0 } 实现 Lv1.2. 词法/语法分析初见 我使用项目提供的c++模板,直接执行: make build/compiler -koopa hello.c -o hello.koopa 输出: int main() { return 0; } 这是因为默认的模板使用string存放ast,所以输出的ast也是string形式: CompUnit : FuncDef { ast = unique_ptr<string>($1); } ; Lv1.3. 解析 main 函数 这里设计一个ast用于输出程序的语法结构,教程写的已经很详细了:写一个头文件来定义AST,对于头文件重复声明的问题,加上#pragma once就可以解决。 我是这样定义基类和子类进行构造的: // 所有 AST 的基类 class BaseAST { public: virtual ~BaseAST() = default; virtual void Dump() const = 0; }; // CompUnit 是 BaseAST class CompUnitAST : public BaseAST { public: // 用智能指针管理对象 std::unique_ptr<BaseAST> func_def; void Dump() const override { std::cout << "CompUnitAST { "; func_def->Dump(); std::cout << " }"; } }; …… 同时,修改参数类型的相关声明:比如%parse-param { std::unique_ptr<string> &ast } 改为%parse-param { std::unique_ptr<BaseAST> &ast } ...

June 10, 2026 · 2 min · farmer3-c

Windows磁盘合并

前因 C盘越来越满,D盘和E盘还有许多空间,磁盘合并理所当然的成为了一个缓解C盘压力的解决方案。 想法 我的想法是将D盘的文件都挪到E盘,然后腾出D盘的空间来分配到C盘和E盘。考虑到我习惯使用D盘存放应用,所以我打算之后将E盘的盘符改成D。 处于方便和迅捷考虑,我使用robocopy "D:\" "E:\D盘备份" /E /J /MT:8 /R:3 /W:1复制D盘文件到E盘的一个文件夹,效果还不错。于是在完成修改后我同样使用robocopy D:\D盘备份 D:\ /E /MIR来将配置带到新的D盘,殊不知这会带来怎么样的灾难😭 过程 我使用MiniTool Partition Wizard进行磁盘操作。由于原来D盘删除后的内存与C盘之间存在恢复分区,C盘只能合并它右侧的空间,所以要move恢复分区,这就为C盘扩容了。 然后是将剩余空间合并到E盘,结果因为BitLocker而合并不了,解密之后顺利合并。 最后,灾难性的一幕发生了,使用robocopy D:\D盘备份 D:\ /E /MIR后,修改后D盘空了。 可能的原因是:带 /MIR 的 robocopy 命令在执行时,先清空了 D 盘根目录,再尝试复制备份文件,但中途因为 $RECYCLE.BIN 报错中断,导致备份文件也被系统误删了。 数据恢复工具需要的时间太长了,被删除的数据也没有很重要的,我就先配置了日常要用的工具草草了结了,剩下的日后再说。

June 9, 2026 · 1 min · farmer3-c

Flex 和 Bison 教程

说明:本篇内容译自 Santa Clara University COEN 259 编译原理课程讲义,用于学习 Flex 和 Bison 编译器工具。 本篇内容为个人学习,不构成任何商业用途。 Flex Flex 是一个用于词法分析的扫描器生成工具,它基于有限状态机 (FSM)。输入是一组正则表达式,输出是根据输入规则实现扫描器的代码。 为了实现计算器的一个扫描器,我们可以将文件 “cal1.l” 编写如下: /* this is only for scanner, not link with parser yet */ %{ int lineNum = 0; %} %% "(" { printf("(\n"); } ")" { printf(")\n"); } "+" { printf("+\n"); } "*" { printf("*\n"); } \n { lineNum++; } [ \t]+ { } [0-9]+ { printf("%s\n", yytext); } %% int yywrap() { return 1; } int main () { yylex(); return 0; } 这是用于构建扫描器的 Makefile: ...

May 23, 2026 · 3 min · farmer3-c

博客优化问题与解决方案总结

博客优化问题与解决方案总结 最近对博客进行了多次优化,遇到了各种问题,现在总结一下遇到的问题及解决方案,供大家参考。 1. Service Worker 自动刷新问题 问题描述 博客添加了 Service Worker 后,每次检测到更新都会显示 “Content updated. REFRESH” 按钮,需要手动点击刷新。 解决方案 修改 js/sw-registration.js,移除手动刷新提示,直接使用 location.reload()。 1 2 3 4 5 if(data.command == "UPDATE_FOUND"){ console.log("UPDATE_FOUND_BY_SW", data); // 自动刷新页面,无需手动点击 location.reload(); } 后续问题 启用自动刷新后,网站出现了无限刷新循环的问题,用户体验极差。 最终解决方案 移除 Service Worker 的自动刷新机制,改用 Stale-While-Revalidate 缓存策略: 优先显示缓存内容 后台更新缓存 用户下次访问时自然看到新内容 2. 导航栏显示文章标题问题 问题描述 导航栏突然显示了文章标题 “编译实践Lv1. main 函数”,而不是正常的页面链接。 根本原因 之前误将一篇博客文章放到了 css/ 文件夹,Jekyll 将其当作页面处理,导致导航栏循环显示所有有 title 的页面。 解决方案 彻底解决方案: 硬编码导航栏,只显示固定页面。 修改 _includes/nav.html: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <ul class="nav navbar-nav navbar-right"> <li> <a href="{{ site.baseurl }}/">Home</a> </li> <li> <a href="{{ site.baseurl }}/about/">About</a> </li> <li> <a href="{{ site.baseurl }}/archive/">Archive</a> </li> <li class="search-icon"> <a href="javascript:void(0)"> <i class="fa fa-search"></i> </a> </li> </ul> 同时从 git 历史中彻底移除误放的文章。 ...

May 16, 2026 · 3 min · farmer3-c

VScode断点使用

前因 今天遇到了一个问题,c++编程解决问题时不能正确输出,于是我想使用断点调试来找出问题所在。此前很少使用断点调试,对于调试的几个按钮仅仅认为向下的箭头是向下运行一步、向上的箭头是回退一步、方框是退出调试。 于是:出现 (1) 本应长度为3的数组b却是std::vector of length -1198221809, capacity 2069355498。 继续点击向下的箭头;结果在几个头文件中来回转跳 (2) 回退到(1)的状态,再点击step over符号,数组b的长度恢复正常: (3) 不知道其中原因,我查了下断点用法。 断点使用 操作 描述 继续 / 暂停 F5 继续:恢复程序/脚本的正常执行(直到下一个断点)。 暂停:检查当前行正在执行的代码并逐行进行调试。 单步跳过 F10 将下一行代码作为一个整体执行,而不进入该方法的内部步骤。 单步调试 F11 进入下一行代码的方法,以便逐行跟踪其执行过程。 单步跳出 Shift+F11 在方法或子程序内部时,完成当前方法的剩余行并返回到之前的执行上下文,就像将其作为一个命令执行一样。 重启 Ctrl+Shift+F5 终止当前程序执行并使用当前的运行配置再次开始调试。 停止 Shift+F5 终止当前程序执行。 单步调试: 进入下一行代码的方法,以便逐行跟踪其执行过程。意思是说要把最基础的编译文件显示出来,单步跳过封装了执行单步调试的所有过程,可以一直按 F11 达到 F10 所完成的任务。 之前以为按f11是在几个头文件中来回转跳,其实不是。 参考 使用 Visual Studio Code 调试代码

April 21, 2026 · 1 min · farmer3-c

3290. 最高乘法得分

3290. 最高乘法得分 给你一个大小为 4 的整数数组 a 和一个大小 至少为 4 的整数数组 b。 你需要从数组 b 中选择四个下标 i0, i1, i2, 和 i3,并满足 i0 < i1 < i2 < i3。你的得分将是 a[0] * b[i0] + a[1] * b[i1] + a[2] * b[i2] + a[3] * b[i3] 的值。 返回你能够获得的 最大 得分。 提示: $a.length == 4$ $4 <= b.length <= 10^5$ $-10^5 <= a[i], b[i] <= 10^5$ 思路 用dp来做,从后往前选取a[i]、b[j]相乘,考虑2种状态: 选当前a[i]、b[j]相乘,继续考虑a[i-1]、b[j-1] 不选选当前a[i]、b[j]相乘,继续考虑a[i]、b[j-1] 状态转换: dfs(i,j)=max(dfs(i-1,j-1)+a[i]*b[j],dfs(i,j-1)) 点击展开/折叠 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution { public: long long maxScore(vector<int>& a, vector<int>& b) { int n=b.size(); vector<array<long long,4>>memo(n); for(auto&row:memo){ ranges::fill(row,LLONG_MIN); } auto dfs=[&](auto&&dfs,int i,int j)->long long{ if(j<0)return 0; if(i<0){ return LLONG_MIN/2; } auto &res=memo[i][j]; if(res==LLONG_MIN){ res=max(dfs(dfs,i-1,j),dfs(dfs,i-1,j-1)+(long long)a[j]*b[i]); } return res; }; return dfs(dfs,n-1,3); } }; 参考 ...

March 22, 2026 · 1 min · farmer3-c

474. 一和零

474. 一和零 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 。 如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。 提示: 1 <= strs.length <= 600 1 <= strs[i].length <= 100 strs[i] 仅由 '0' 和 '1' 组成 1 <= m, n <= 100 思路 首先,这是一个二维0-1背包问题,可以使用三维数组解决。 f[i][j][k]:i代表0~i的选取结果,j代表不超过j个零,k同理。 f[i][j][k]=max(dp[i−1][j][k],dp[i−1][j−当前字符串使用0的个数][k−当前字符串使用1的个数]+1) dp[i−1][j][k] 不选择当前考虑的字符串i dp[i−1][j−当前字符串使用0的个数][k−当前字符串使用1的个数]+1 选择当前考虑的字符串​ 初始化:为了避免分类讨论,通常多设置一行。这里可以认为,第 0 个字符串是空串。 点击展开/折叠 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Solution { public: int findMaxForm(vector<string>& strs, int m, int n) { int len = strs.size(); vector<vector<vector<int>>> dp(len + 1, vector<vector<int>>(m + 1, vector<int>(n + 1, 0))); for (int i = 1; i <= len; i++) { int x1 = cnum(strs[i - 1]); int x0 = strs[i - 1].size() - x1; for (int j = 0; j <= m; j++) { for (int k = 0; k <= n; k++) { dp[i][j][k] = dp[i - 1][j][k]; if (j >= x0 && k >= x1) { dp[i][j][k] = max(dp[i - 1][j][k], dp[i - 1][j - x0][k - x1] + 1); } } } } return dp[len][m][n]; } int cnum(string s) { int cnt = 0; for (auto c : s) { if (c == '1') cnt++; } return cnt; } }; 参考 ...

March 17, 2026 · 2 min · farmer3-c