8个版本 (4 个重大更改)
0.4.0 | 2024年6月14日 |
---|---|
0.3.0 | 2022年8月29日 |
0.2.2 | 2022年2月1日 |
0.2.1 | 2021年1月27日 |
0.0.0 | 2020年6月8日 |
#49 in 文本处理
每月下载量 186,872
用于 90 个crate (23 直接)
150KB
4K SLoC
diffy
用于查找和操作文件之间差异的工具
许可证
本项目可在Apache 2.0许可证或MIT许可证的条款下使用。
lib.rs
:
用于查找和操作文件之间差异的工具
概述
这个库旨在成为一组工具的集合,用于查找和操作文件之间的差异,这些工具受到了LibXDiff和GNU Diffutils的启发。版本控制系统(如Git和Mercurial)通常使用diff
或patch
来在两个版本的文件之间传递差异。
当前的diff实现基于Myers' diff算法。
UTF-8和非UTF-8
此库支持同时处理utf8和非utf8文本。大多数API有两个不同的变体,一个用于处理utf8 str
文本(例如create_patch
),另一个用于处理字节[u8]
,这些字节可能是utf8,也可能不是(例如create_patch_bytes
)。
创建补丁
可以通过以下方式创建两个文本之间的Patch
use diffy::create_patch;
let original = "The Way of Kings\nWords of Radiance\n";
let modified = "The Way of Kings\nWords of Radiance\nOathbringer\n";
let patch = create_patch(original, modified);
#
#
Patch
可以通过其Display
实现或使用PatchFormatter
来以彩色输出diff。
#
#
#
#
#
// Without color
print!("{}", patch);
// With color
let f = PatchFormatter::new().with_color();
print!("{}", f.fmt_patch(&patch));
--- original
+++ modified
@@ -1,2 +1,3 @@
The Way of Kings
Words of Radiance
+Oathbringer
应用补丁
一旦你有了Patch
,就可以将其应用到基础镜像上以恢复新文本。每个块将按顺序应用到基础镜像上。类似于GNU patch
,此实现可以检测补丁中指定的行号是否错误,并将尝试通过从前向后和从后向前迭代给定位置,直到每个块的上下文行与基础镜像匹配为止,来找到应用每个块的正确位置。
use diffy::{apply, Patch};
let s = "\
--- a/skybreaker-ideals
+++ b/skybreaker-ideals
@@ -10,6 +10,8 @@
First:
Life before death,
strength before weakness,
journey before destination.
Second:
- I will put the law before all else.
+ I swear to seek justice,
+ to let it guide me,
+ until I find a more perfect Ideal.
";
let patch = Patch::from_str(s).unwrap();
let base_image = "\
First:
Life before death,
strength before weakness,
journey before destination.
Second:
I will put the law before all else.
";
let expected = "\
First:
Life before death,
strength before weakness,
journey before destination.
Second:
I swear to seek justice,
to let it guide me,
until I find a more perfect Ideal.
";
assert_eq!(apply(base_image, &patch).unwrap(), expected);
执行三次合并
给定一个共同的祖先或原始文件O
,两个文件A
和B
可以合并在一起以生成一个文件C
,类似于diff3执行三次合并的方式。
--- A ---
/ \
/ \
O C
\ /
\ /
--- B ---
如果文件A
和B
修改了原始文件O
的不同区域(或在相同区域以相同方式),则可以在没有冲突的情况下合并这些文件。
use diffy::merge;
let original = "the final empire\nThe Well of Ascension\nThe hero of ages\n";
let a = "The Final Empire\nThe Well of Ascension\nThe Hero of Ages\n";
let b = "The Final Empire\nThe Well of Ascension\nThe hero of ages\n";
let expected = "\
The Final Empire
The Well of Ascension
The Hero of Ages
";
assert_eq!(merge(original, a, b).unwrap(), expected);
如果文件A
和B
都修改了原始文件O
的相同区域(且这些修改不同),则会导致冲突,因为在合并结果中不清楚应该使用哪些修改。
use diffy::merge;
let original = "The Final Empire\nThe Well of Ascension\nThe hero of ages\n";
let a = "The Final Empire\nThe Well of Ascension\nThe Hero of Ages\nSecret History\n";
let b = "The Final Empire\nThe Well of Ascension\nThe hero of ages\nThe Alloy of Law\n";
let expected = "\
The Final Empire
The Well of Ascension
<<<<<<< ours
The Hero of Ages
Secret History
||||||| original
The hero of ages
=======
The hero of ages
The Alloy of Law
>>>>>>> theirs
";
assert_eq!(merge(original, a, b).unwrap_err(), expected);
依赖关系
~0.1–7MB
~35K SLoC