当你想快速对比两个代码文件的差异,又不想打开 Git 或 VS Code 的时候,一个命令行 diff 工具就派上用场了。今天我们用 OpenCode + Node.js,从零写一个支持彩色输出的文件差异对比工具,类似 git diff 的迷你版。
我先告诉 OpenCode 要做什么:
> "创建一个 Node.js 命令行工具 diff.js,读取两个文件路径作为参数,比较内容差异并输出"
OpenCode 马上生成了基础结构——用 fs.readFileSync 读取文件、按行分割、用 process.argv 获取命令行参数。骨架不到 20 行,省去了手写文件读取和参数解析的琐碎工作。
关键要点:向 OpenCode 描述需求时,先说清楚输入(两个文件路径)、输出(差异对比结果),它生成的基础代码基本不用改。
这是工具的核心。我对 OpenCode 说:
> "用最长公共子序列算法对比两个字符串数组,输出增/删/相同的操作序列"
OpenCode 生成了一段标准的 LCS 动态规划实现:二维 DP 表计算公共子序列长度,然后回溯重建差异操作序列。代码约 30 行,算法正确,直接可用。
function lcsDiff(a, b) {
const m = a.length, n = b.length;
const dp = Array.from({length: m + 1}, () => new Array(n + 1).fill(0));
for (let i = 1; i <= m; i++)
for (let j = 1; j <= n; j++)
dp[i][j] = a[i-1] === b[j-1] ? dp[i-1][j-1] + 1 : Math.max(dp[i-1][j], dp[i][j-1]);
// 回溯构建差异序列...
}
关键要点:OpenCode 擅长实现经典算法,你只需要给出准确的算法名称和输入输出格式,它会生成经过验证的实现。
我对 OpenCode 说:
> "给差异输出加上颜色:新增行用绿色(\x1b[32m),删除行用红色(\x1b[31m),同时输出增删行数统计"
OpenCode 在现有的打印函数中插入了 ANSI 转义码,新增行前缀 + 用绿色,删除行前缀 - 用红色,底部自动追加统计行。一行代码都不用我改。
关键要点:功能叠加是 OpenCode 的强项。先有核心逻辑,再逐步"对话式"添加功能,每一步 OpenCode 都能准确理解上下文。
我对 OpenCode 说:
> "加上参数校验——参数不足时打印用法,文件不存在时报错退出"""
OpenCode 补上了 fs.existsSync 检查,参数不足时输出 用法: node diff.js <文件1> <文件2>。至此工具完整可用。
我用两个测试文件验证:
$ node diff.js a.txt b.txt
--- a.txt
+++ b.txt
hello world
+ console.log("new line")
foo bar
- old deprecated line
end
@@ 共 1 行新增, 1 行删除 @@
完全符合预期。从第一行对话到最终交付,整个过程不到 4 分钟。
#!/usr/bin/env node
const fs = require('fs');
function readLines(path) {
return fs.readFileSync(path, 'utf-8').split('\n');
}
function lcsDiff(a, b) {
const m = a.length, n = b.length;
const dp = Array.from({length: m + 1}, () => new Array(n + 1).fill(0));
for (let i = 1; i <= m; i++)
for (let j = 1; j <= n; j++)
dp[i][j] = a[i-1] === b[j-1] ? dp[i-1][j-1] + 1 : Math.max(dp[i-1][j], dp[i][j-1]);
const result = [];
let i = m, j = n;
while (i > 0 || j > 0) {
if (i > 0 && j > 0 && a[i-1] === b[j-1]) {
result.unshift({type: 'same', text: a[i-1], oldNo: i, newNo: j});
i--; j--;
} else if (j > 0 && (i === 0 || dp[i][j-1] >= dp[i-1][j])) {
result.unshift({type: 'add', text: b[j-1], oldNo: 0, newNo: j});
j--;
} else {
result.unshift({type: 'del', text: a[i-1], oldNo: i, newNo: 0});
i--;
}
}
return result;
}
function printDiff(diffs) {
const R = '\x1b[31m', G = '\x1b[32m', E = '\x1b[0m';
let out = '', addCount = 0, delCount = 0;
for (const d of diffs) {
if (d.type === 'add') {
out += `${G}+ ${d.text}${E}\n`;
addCount++;
} else if (d.type === 'del') {
out += `${R}- ${d.text}${E}\n`;
delCount++;
} else {
out += ` ${d.text}\n`;
}
}
if (addCount === 0 && delCount === 0) out += '两个文件完全相同。\n';
return { out, addCount, delCount };
}
function main() {
const [f1, f2] = process.argv.slice(2);
if (!f1 || !f2) {
console.log('用法: node diff.js <文件1> <文件2>');
process.exit(1);
}
if (!fs.existsSync(f1) || !fs.existsSync(f2)) {
console.log('错误: 文件不存在');
process.exit(1);
}
const a = readLines(f1), b = readLines(f2);
const diffs = lcsDiff(a, b);
const { out, addCount, delCount } = printDiff(diffs);
console.log(`--- ${f1}\n+++ ${f2}`);
console.log(out);
console.log(`@@ 共 ${addCount} 行新增, ${delCount} 行删除 @@`);
}
main();
整个项目 75 行代码,从构思到开发完成不到 4 分钟。OpenCode 承担了全部编码工作——我只需要用自然语言描述每一步需求,它负责翻译成可运行的代码。相比手动写,省去了查文档、调试语法错误的时间,尤其是 LCS 算法这种需要仔细处理边界条件的逻辑,交给 AI 生成又快又准。
这就是 OpenCode 的正确打开方式:你负责"做什么",它负责"怎么做"。