1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
//! <https://github.com/google/diff-match-patch/wiki/Plain-Text-vs.-Structured-Content>
use diffmatchpatch::*;
pub trait BlockExt {
fn is_block_start(&self) -> bool;
fn block_level_prefix(&self) -> &str;
fn is_whitespace_start(&self) -> bool;
}
impl BlockExt for str {
fn is_block_start(&self) -> bool {
self.starts_with("- ") || self.starts_with("-\n")
}
fn block_level_prefix(&self) -> &str {
&self[..self.find('-').unwrap()]
}
fn is_whitespace_start(&self) -> bool {
let c = self.as_bytes()[0];
c == b'\t' || c == b' ' || c == b'\x09' || c == b'\x0c'
}
}
pub fn split_blocks(page: &str) -> Vec<&str> {
let mut blocks = vec![];
let mut start = 0;
let mut end = 0;
let mut it = page.split_inclusive('\n');
let mut prefix = "";
loop {
match it.next() {
None => {
if start != end {
blocks.push(&page[start..end]);
}
break;
}
Some(line) => {
// cont.
if line.trim().is_empty() {
end += line.len();
} else if line.is_whitespace_start() {
if line.starts_with(prefix) {
let bare_line = line.trim_start_matches(prefix);
if bare_line.is_block_start() {
// new block one the same level
if start != end {
blocks.push(&page[start..end]);
}
start = end;
end = start + line.len();
} else if bare_line.trim_start().is_block_start() {
// new block on sub level
if start != end {
blocks.push(&page[start..end]);
}
start = end;
end = start + line.len();
prefix = line.block_level_prefix()
} else {
end += line.len();
}
} else if line.trim_start().is_block_start() {
// new block on parent level
if start != end {
blocks.push(&page[start..end]);
}
start = end;
end = start + line.len();
prefix = line.block_level_prefix();
} else {
// block cont.
end += line.len();
}
} else if line.is_block_start() {
// new block
if start != end {
blocks.push(&page[start..end]);
}
start = end;
end = start + line.len();
prefix = "";
} else if prefix.is_empty() && line.contains(":: ") {
// global property line
if start != end {
blocks.push(&page[start..end]);
}
start = end;
end = start + line.len();
prefix = "";
} else {
end += line.len();
}
}
}
}
blocks
}
fn diff_blocks<'a>(
base_blocks: &'a [&'a str],
new_blocks: &'a [&'a str],
) -> Vec<Diff<Vec<&'a str>>> {
// diff_blocksToChars then diff_blocksToUniqueId
let dmp = DiffMatchPatch::new();
let (ac, bc, item_array) = dmp.diff_any_to_chars(base_blocks, new_blocks);
let mut diffs = dmp.diff_main(&ac, &bc, false);
let diffs = dmp.diff_chars_to_any(&diffs, &item_array);
diffs
}
fn merge_blocks<'a>(base_blocks: &'a [&'a str], branch_a: &'a [&'a str], branch_b: &'a [&'a str]) {
//let mut diff_pool = vec![];
// step 1, merge diffs
for (i, diff) in diff_blocks(base_blocks, branch_a).into_iter().enumerate() {
todo!();
}
}
fn main() {
let a = r"- Block 1
- Block 2
- Block 2.1
- Block 3
- Block 4
- Block 5";
let b = r"- Block 1
- Block 4
- Block 2.1
- Block 3
- Block 5
- Block 6";
let base = include_str!("base.md");
let a = include_str!("a.md");
let b = include_str!("b.md");
//let ab = split_blocks(a);
//let bb = split_blocks(b);
// let diffs = diff_blocks(&ab, &bb);
// println!("diffs => {:#?}", diffs);
// todo!();
let mut dmp = DiffMatchPatch::new();
//let (ac, bc, item_array) = dmp.diff_any_to_chars(&ab, &bb);
let ac = base.to_chars();
let bc = a.to_chars();
let patches = dmp.patch_make1(&ac, &bc);
println!("patches => {:#?}", patches);
for p in patches {
println!("======");
println!("{}", p);
}
todo!();
// println!("{ac:?} {bc:?}\n{item_array:#?}");
let mut diffs = dmp.diff_main(&ac, &bc, false);
dmp.diff_cleanup_efficiency(&mut diffs);
//let new_diffs = dmp.diff_chars_to_any(&mut diffs, &item_array);
//println!("=> {new_diffs:#?}");
// println!("diffs => {}", new_diffs.len());
}