- 1001
}; - 1002
self.container( - 1003
node, - 1004
Context { - 1005
guard: Some(group), - 1006
..context - 1007
}, - 1008
)?; - 1009
if guard.is_none() { - 1010
self.model.groups[group].end_order = self.next_order(); - 1011
} - 1012
} - 1013
_ => { - 1014
self.fixed(node, Weight::Significant, Spot::After(node)); - 1015
} - 1016
} - 1017
Ok(()) - 1018
} - 1019
- 1020
fn run(&mut self, run: usize, context: Context) -> Result<(), EditError> { - 1021
let tree = self.part.tree; - 1022
let (hidden, white) = run_flags(tree, run); - 1023
let content: Vec<usize> = tree.nodes[run] - 1024
.children - 1025
.iter() - 1026
.copied() - 1027
.filter(|child| { - 1028
let node = &tree.nodes[*child]; - 1029
!node.skipped && node.local() != "rPr" - 1030
}) - 1031
.collect(); - 1032
self.model.run_children.insert(run, content.clone()); - 1033
for (index, &child) in content.iter().enumerate() { - 1034
let before = Spot::InRun { - 1035
run, - 1036
child: index, - 1037
offset: 0, - 1038
}; - 1039
let after = Spot::InRun { - 1040
run, - 1041
child: index + 1, - 1042
offset: 0, - 1043
}; - 1044
let local = tree.nodes[child].local(); - 1045
match local { - 1046
"t" | "delText" | "tab" | "br" | "cr" | "noBreakHyphen" => { - 1047
let text = match local { - 1048
"t" | "delText" => self.decode(child)?, - 1049
"tab" => "\t".to_string(), - 1050
"noBreakHyphen" => "-".to_string(), - 1051
_ => " ".to_string(), - 1052
}; - 1053
if text.is_empty() { - 1054
self.fixed(child, Weight::Neutral, after); - 1055
continue; - 1056
} - 1057
if hidden || (white && !text.trim().is_empty()) { - 1058
self.fixed(child, Weight::Significant, after); - 1059
continue; - 1060
} - 1061
let link = self.link_here(context); - 1062
let (role, stray) = if let Some(group) = self.enclosing_guard(context) { - 1063
(Role::Guarded(group), false) - 1064
} else if context.own_deletion.is_some() { - 1065
(Role::OwnDeleted, false) - 1066
} else if local == "delText" { - 1067
// Deleted text outside a deletion: shown as text, - 1068
// and not this op's to change. - 1069
( - 1070
Role::Guarded(self.group( - 1071
Guard::Element("delText".into()), - 1072
Some(before), - 1073
Some(after), - 1074
)), - 1075
true, - 1076
) - 1077
} else if let Some(theirs) = context.theirs { - 1078
(Role::Theirs(theirs), false) - 1079
} else { - 1080
(Role::Plain, false) - 1081
}; - 1082
let order = self.chunk( - 1083
child, - 1084
Some(run), - 1085
index, - 1086
&text, - 1087
role, - 1088
matches!(local, "t" | "delText"), - 1089
link, - 1090
); - 1091
if let (true, Role::Guarded(group)) = (stray, role) { - 1092
self.model.groups[group].end_order = order; - 1093
} - 1094
} - 1095
"fldChar" => { - 1096
let order = self.fixed(child, Weight::Significant, after); - 1097
match tree.nodes[child].element.attr("fldCharType") { - 1098
Some("begin") => self.open_field(String::new(), Some(before)), - 1099
Some("separate") => self.enter_result(), - 1100
Some("end") => self.close_field(after, order), - 1101
_ => {} - 1102
} - 1103
} - 1104
"instrText" => { - 1105
let text = self.decode(child)?; - 1106
if let Some(field) = self.fields.last_mut() - 1107
&& !field.in_result - 1108
{ - 1109
field.instruction.push_str(&text); - 1110
field.instruction.push(' '); - 1111
} - 1112
self.fixed(child, Weight::Neutral, after); - 1113
} - 1114
"footnoteReference" | "endnoteReference" => { - 1115
self.fixed(child, Weight::Attach, after); - 1116
} - 1117
_ => self.element(child, context, Some((run, index)))?, - 1118
} - 1119
} - 1120
Ok(()) - 1121
} - 1122
- 1123
/// Any other element: zero-width when the reader finds no text in it, - 1124
/// and otherwise text that cannot change. - 1125
fn element( - 1126
&mut self, - 1127
node: usize, - 1128
context: Context, - 1129
in_run: Option<(usize, usize)>, - 1130
) -> Result<(), EditError> { - 1131
let local = self.part.tree.nodes[node].local().to_string(); - 1132
let (before, after) = match in_run { - 1133
Some((run, index)) => ( - 1134
Spot::InRun { - 1135
run, - 1136
child: index, - 1137
offset: 0, - 1138
}, - 1139
Spot::InRun { - 1140
run, - 1141
child: index + 1, - 1142
offset: 0, - 1143
}, - 1144
), - 1145
None => (Spot::Before(node), Spot::After(node)), - 1146
}; - 1147
let text = self.element_text(node)?; - 1148
if text.is_empty() { - 1149
let weight = if NEUTRAL.contains(&local.as_str()) { - 1150
Weight::Neutral - 1151
} else { - 1152
Weight::Significant - 1153
}; - 1154
self.fixed(node, weight, after); - 1155
return Ok(()); - 1156
} - 1157
let enclosing = self.enclosing_guard(context); - 1158
let group = match enclosing { - 1159
Some(group) => group, - 1160
None => self.group(Guard::Element(local), Some(before), Some(after)), - 1161
}; - 1162
let link = self.link_here(context); - 1163
let order = self.chunk( - 1164
node, - 1165
in_run.map(|(run, _)| run), - 1166
in_run.map_or(0, |(_, index)| index), - 1167
&text, - 1168
Role::Guarded(group), - 1169
false, - 1170
link, - 1171
); - 1172
if enclosing.is_none() { - 1173
self.model.groups[group].end_order = order; - 1174
} - 1175
Ok(()) - 1176
} - 1177
- 1178
/// The text the reader attributes to this paragraph from inside an - 1179
/// element: nested paragraphs (a text box) are their own. - 1180
fn element_text(&self, node: usize) -> Result<String, EditError> { - 1181
let tree = self.part.tree; - 1182
let end = tree.nodes[node].span.end; - 1183
let mut text = String::new(); - 1184
let mut skip_until = 0usize; - 1185
for index in node + 1..tree.nodes.len() { - 1186
let descendant = &tree.nodes[index]; - 1187
if descendant.span.start >= end { - 1188
break; - 1189
} - 1190
if descendant.skipped || descendant.span.start < skip_until { - 1191
continue; - 1192
} - 1193
match descendant.local() { - 1194
"p" => skip_until = descendant.span.end, - 1195
"t" | "delText" => text.push_str(&self.decode(index)?), - 1196
"tab" => text.push('\t'), - 1197
"br" | "cr" => text.push(' '), - 1198
"noBreakHyphen" => text.push('-'), - 1199
_ => {} - 1200
} - 1201
} - 1202
Ok(text) - 1203
} - 1204
} - 1205
- 1206
// ---- Placing the change ---------------------------------------------------------- - 1207
- 1208
impl Paragraph { - 1209
fn guarded(&self, index: usize) -> Option<usize> { - 1210
match self.chunks[self.owner[index]].role { - 1211
Role::Guarded(group) => Some(group), - 1212
_ => None, - 1213
} - 1214
} - 1215
- 1216
fn chunk_at(&self, index: usize) -> &Chunk { - 1217
&self.chunks[self.owner[index]] - 1218
} - 1219
- 1220
fn refusal(&self, anchor: &str, index: usize, inside: bool) -> EditError { - 1221
let Some(group) = self.guarded(index) else { - 1222
return EditError { - 1223
op: None, - 1224
message: format!("{anchor}: the change cannot be placed there"), - 1225
}; - 1226
}; - 1227
let text: String = (0..self.chars.len()) - 1228
.filter(|at| self.guarded(*at) == Some(group)) - 1229
.map(|at| self.chars[at]) - 1230
.collect(); - 1231
let text = text.trim(); - 1232
let text = if text.chars().count() > 60 { - 1233
format!("{}…", text.chars().take(59).collect::<String>()) - 1234
} else { - 1235
text.to_string() - 1236
}; - 1237
let what = match &self.groups[group].guard { - 1238
Guard::Field => { - 1239
"a field's result that Word computes (a cross-reference, page number or date)" - 1240
.to_string() - 1241
} - 1242
Guard::Tracked(author) => { - 1243
format!("part of a tracked change by {author} that this op cannot accept or reject") - 1244
} - 1245
Guard::Element(name) => match name.as_str() { - 1246
"oMath" | "oMathPara" => "an equation".to_string(), - 1247
"drawing" | "pict" | "object" => "text inside a drawing".to_string(), - 1248
_ => "content this op does not edit".to_string(), - 1249
}, - 1250
}; - 1251
let message = if inside { - 1252
format!( - 1253
"{anchor}: the new text would go inside {text:?}, {what}; put it before or after that text instead" - 1254
) - 1255
} else { - 1256
format!( - 1257
"{anchor}: the change would alter {text:?}, {what}; keep that text exactly as it is (the rest of the paragraph can change)" - 1258
) - 1259
}; - 1260
EditError { op: None, message } - 1261
} - 1262
- 1263
/// Where an insertion at `gap` goes, the run whose formatting it takes, - 1264
/// and whether to drop that run's character style (the new text is - 1265
/// outside the link the style belongs to). `deleted` is the text it - 1266
/// replaces, if any. - 1267
fn placement( - 1268
&self, - 1269
anchor: &str, - 1270
gap: usize, - 1271
deleted: Range<usize>, - 1272
) -> Result<(Spot, Option<usize>, bool), EditError> { - 1273
if !deleted.is_empty() { - 1274
// A replacement goes where the text it replaces ends and looks - 1275
// like most of that text. - 1276
let last = deleted.end - 1; - 1277
let mut counts: Vec<(usize, usize)> = Vec::new(); - 1278
for index in deleted.clone() { - 1279
if let Some(run) = self.chunk_at(index).run { - 1280
match counts.iter_mut().find(|(known, _)| *known == run) { - 1281
Some((_, count)) => *count += 1, - 1282
None => counts.push((run, 1)), - 1283
} - 1284
} - 1285
} - 1286
let dominant = counts - 1287
.iter() - 1288
.fold( - 1289
None, - 1290
|best: Option<(usize, usize)>, &(run, count)| match best { - 1291
Some((_, most)) if most >= count => best, - 1292
_ => Some((run, count)), - 1293
}, - 1294
) - 1295
.map(|(run, _)| run); - 1296
let dominant_link = deleted - 1297
.clone() - 1298
.find(|index| self.chunk_at(*index).run == dominant) - 1299
.and_then(|index| self.chunk_at(index).link); - 1300
let strip = dominant_link != self.chunk_at(last).link; - 1301
return Ok((self.after_char(last), dominant, strip)); - 1302
} - 1303
if gap > 0 { - 1304
let left = gap - 1; - 1305
let chunk = self.chunk_at(left); - 1306
if let Role::Guarded(group) = chunk.role { - 1307
if gap < self.chars.len() && self.guarded(gap) == Some(group) { - 1308
return Err(self.refusal(anchor, left, true)); - 1309
} - 1310
let group = &self.groups[group]; - 1311
let Some(after) = group.after else { - 1312
return Err(self.refusal(anchor, left, true)); - 1313
}; - 1314
return Ok(( - 1315
self.skip_attached(gap, after, group.end_order), - 1316
chunk.run.or_else(|| self.nearest_run(gap)), - 1317
false, - 1318
)); - 1319
} - 1320
let at_link_end = chunk - 1321
.link - 1322
.filter(|link| gap == self.chars.len() || self.chunk_at(gap).link != Some(*link)); - 1323
if let Some(link) = at_link_end - 1324
&& let Some(after) = self.links[link].after - 1325
{ - 1326
return Ok(( - 1327
self.skip_attached(gap, after, self.links[link].end_order), - 1328
chunk.run, - 1329
true, - 1330
)); - 1331
} - 1332
return Ok(( - 1333
self.skip_attached(gap, self.after_char(left), chunk.order), - 1334
chunk.run, - 1335
false, - 1336
)); - 1337
} - 1338
if self.chars.is_empty() { - 1339
return Ok((Spot::End, None, false)); - 1340
} - 1341
let first = self.chunk_at(0); - 1342
if let Role::Guarded(group) = first.role { - 1343
let Some(before) = self.groups[group].before else { - 1344
return Err(self.refusal(anchor, 0, true)); - 1345
}; - 1346
return Ok((before, first.run.or_else(|| self.nearest_run(0)), false)); - 1347
} - 1348
if let Some(link) = first.link - 1349
&& let Some(before) = self.links[link].before - 1350
{ - 1351
return Ok((before, first.run, true)); - 1352
} - 1353
Ok((self.before_char(0), first.run, false)) - 1354
} - 1355
- 1356
/// After a footnote or endnote mark that follows the text at `gap`, so - 1357
/// new text never separates a mark from the sentence it annotates. - 1358
fn skip_attached(&self, gap: usize, base: Spot, base_order: usize) -> Spot { - 1359
let mut following: Vec<&Fixed> = self - 1360
.fixed - 1361
.iter() - 1362
.filter(|fixed| fixed.gap == gap && fixed.order > base_order) - 1363
.collect(); - 1364
following.sort_by_key(|fixed| fixed.order); - 1365
let mut spot = base; - 1366
for fixed in following { - 1367
match fixed.weight { - 1368
Weight::Attach => spot = fixed.after, - 1369
Weight::Neutral => {} - 1370
Weight::Significant => break, - 1371
} - 1372
} - 1373
spot - 1374
} - 1375
- 1376
/// The nearest run with editable text, for formatting new text next to - 1377
/// something that has none of its own. - 1378
fn nearest_run(&self, gap: usize) -> Option<usize> { - 1379
let editable = |index: &usize| { - 1380
let chunk = self.chunk_at(*index); - 1381
(!matches!(chunk.role, Role::Guarded(_))) - 1382
.then_some(chunk.run) - 1383
.flatten() - 1384
}; - 1385
(0..gap) - 1386
.rev() - 1387
.find_map(|index| editable(&index)) - 1388
.or_else(|| (gap..self.chars.len()).find_map(|index| editable(&index))) - 1389
} - 1390
- 1391
fn after_char(&self, index: usize) -> Spot { - 1392
let chunk = self.chunk_at(index); - 1393
let Some(run) = chunk.run else { - 1394
return Spot::After(chunk.node); - 1395
}; - 1396
let offset = index - chunk.start + 1; - 1397
if chunk.splittable && offset < chunk.text.len() { - 1398
Spot::InRun { - 1399
run, - 1400
child: chunk.child, - 1401
offset, - 1402
} - 1403
} else { - 1404
Spot::InRun { - 1405
run, - 1406
child: chunk.child + 1, - 1407
offset: 0, - 1408
} - 1409
} - 1410
} - 1411
- 1412
fn before_char(&self, index: usize) -> Spot { - 1413
let chunk = self.chunk_at(index); - 1414
let Some(run) = chunk.run else { - 1415
return Spot::Before(chunk.node); - 1416
}; - 1417
Spot::InRun { - 1418
run, - 1419
child: chunk.child, - 1420
offset: if chunk.splittable { - 1421
index - chunk.start - 1422
} else { - 1423
0 - 1424
}, - 1425
} - 1426
} - 1427
- 1428
/// The same place, named so that nothing is split that need not be: a - 1429
/// run's edge becomes a place beside the run, beside the author's - 1430
/// deletion the run is the edge of, or beside the other author's - 1431
/// insertion it is the edge of (new text never goes inside that). - 1432
fn normalize(&self, spot: Spot) -> Spot { - 1433
let Spot::InRun { run, child, offset } = spot else { - 1434
return spot; - 1435
}; - 1436
let Some(children) = self.run_children.get(&run) else { - 1437
return spot; - 1438
}; - 1439
let length = |child: usize| { - 1440
children - 1441
.get(child) - 1442
.and_then(|node| self.chunk_of.get(node)) - 1443
.map_or(0, |chunk| self.chunks[*chunk].text.len()) - 1444
}; - 1445
let (child, offset) = if offset > 0 && offset >= length(child) { - 1446
(child + 1, 0) - 1447
} else { - 1448
(child, offset) - 1449
}; - 1450
let at_start = child == 0 && offset == 0; - 1451
let at_end = child >= children.len(); - 1452
if let Some(theirs) = self.in_theirs.get(&run) { - 1453
let runs = self.theirs.get(theirs); - 1454
return if at_start && runs.and_then(|runs| runs.first()) == Some(&run) { - 1455
Spot::Before(*theirs) - 1456
} else if at_end && runs.and_then(|runs| runs.last()) == Some(&run) { - 1457
Spot::After(*theirs) - 1458
} else { - 1459
Spot::InRun { run, child, offset } - 1460
}; - 1461
} - 1462
match self.in_own_deletion.get(&run) { - 1463
None if at_start => Spot::Before(run), - 1464
None if at_end => Spot::After(run), - 1465
Some(wrapper) => { - 1466
let runs = self.own_deletions.get(wrapper); - 1467
if at_start && runs.and_then(|runs| runs.first()) == Some(&run) { - 1468
Spot::Before(*wrapper) - 1469
} else if at_end && runs.and_then(|runs| runs.last()) == Some(&run) { - 1470
Spot::After(*wrapper) - 1471
} else { - 1472
Spot::InRun { run, child, offset } - 1473
} - 1474
} - 1475
None => Spot::InRun { run, child, offset }, - 1476
} - 1477
} - 1478
- 1479
/// Formatting for new text: `run`'s own, less anything that would hide - 1480
/// it or claim a revision, or the paragraph mark's when there is no run. - 1481
fn properties( - 1482
&self, - 1483
part: &Part<'_>, - 1484
run: Option<usize>, - 1485
strip_style: bool, - 1486
) -> Result<String, EditError> { - 1487
let properties = match run { - 1488
Some(run) => part.tree.children(run, "rPr").next(), - 1489
None => self.mark_properties, - 1490
}; - 1491
let Some(properties) = properties else { - 1492
return Ok(String::new()); - 1493
}; - 1494
let node = &part.tree.nodes[properties]; - 1495
if node.is_empty_element() { - 1496
return Ok(String::new()); - 1497
} - 1498
let mut splice = Splice::default(); - 1499
let mut kept = 0usize; - 1500
for &child in &node.children { - 1501
let child = &part.tree.nodes[child]; - 1502
let drop = matches!( - 1503
child.local(), - 1504
"rPrChange" - 1505
| "ins" - 1506
| "del" - 1507
| "moveFrom" - 1508
| "moveTo" - 1509
| "vanish" - 1510
| "specVanish" - 1511
| "webHidden" - 1512
) || (strip_style && child.local() == "rStyle") - 1513
|| (child.local() == "color" - 1514
&& child - 1515
.element - 1516
.attr("val") - 1517
.is_some_and(|value| value.eq_ignore_ascii_case("FFFFFF"))); - 1518
if drop { - 1519
splice.replace( - 1520
child.span.start - node.span.start..child.span.end - node.span.start, - 1521
"", - 1522
); - 1523
} else { - 1524
kept += 1; - 1525
} - 1526
} - 1527
if kept == 0 { - 1528
return Ok(String::new()); - 1529
} - 1530
let bytes = splice.apply(&part.bytes[node.span.clone()], part.name)?; - 1531
Ok(String::from_utf8_lossy(&bytes).into_owned()) - 1532
} - 1533
} - 1534
- 1535
// ---- Writing the change ---------------------------------------------------------- - 1536
- 1537
enum Segment { - 1538
Run { - 1539
deleted: bool, - 1540
xml: Vec<u8>, - 1541
}, - 1542
/// New text, written when the run is, so revision ids follow the - 1543
/// document's order. - 1544
Inserted(Vec<(String, String)>), - 1545
} - 1546
- 1547
/// What a rewritten unit becomes: markup that stays where the unit was - 1548
/// (runs, deletions), and new text, which never goes inside another - 1549
/// author's insertion. - 1550
enum Piece { - 1551
Kept(Vec<u8>), - 1552
New(Vec<u8>), - 1553
} - 1554
- 1555
fn concat(pieces: Vec<Piece>) -> Vec<u8> { - 1556
let mut out = Vec::new(); - 1557
for piece in pieces { - 1558
match piece { - 1559
Piece::Kept(xml) | Piece::New(xml) => out.extend(xml), - 1560
} - 1561
} - 1562
out - 1563
} - 1564
- 1565
struct Emitter<'p, 'a> { - 1566
part: &'p Part<'a>, - 1567
model: &'p Paragraph, - 1568
keep: &'p [bool], - 1569
/// Units rewritten in full: plain runs, the author's deletions, and - 1570
/// other authors' insertions. - 1571
rewrite: HashSet<usize>, - 1572
/// Runs and the author's deletions whose content changes. - 1573
changed: HashSet<usize>, - 1574
/// Containers re-emitted around a change, copying what did not change. - 1575
open: HashSet<usize>, - 1576
dropped: HashSet<usize>, - 1577
at: BTreeMap<Spot, Vec<(String, String)>>, - 1578
next_id: u64, - 1579
author: &'p str, - 1580
date: &'p str, - 1581
} - 1582
- 1583
impl<'p, 'a> Emitter<'p, 'a> { - 1584
fn new( - 1585
part: &'p Part<'a>, - 1586
model: &'p Paragraph, - 1587
keep: &'p [bool], - 1588
at: BTreeMap<Spot, Vec<(String, String)>>, - 1589
dropped: HashSet<usize>, - 1590
context: &'p EditContext, - 1591
first_id: u64, - 1592
) -> Self { - 1593
// A run's unit: the other author's insertion it sits in (directly or - 1594
// inside the author's own deletion), else the author's deletion it - 1595
// sits in, else the run itself. - 1596
let owner = |run: usize| model.in_own_deletion.get(&run).copied().unwrap_or(run); - 1597
let unit = |node: usize| model.in_theirs.get(&node).copied().unwrap_or(node); - 1598
let mut changed = HashSet::new(); - 1599
for chunk in &model.chunks { - 1600
let differs = - 1601
(chunk.start..chunk.start + chunk.text.len()).any(|index| match chunk.role { - 1602
Role::Plain | Role::Theirs(_) => !keep[index], - 1603
Role::OwnDeleted => keep[index], - 1604
Role::Guarded(_) => false, - 1605
}); - 1606
if differs && let Some(run) = chunk.run { - 1607
changed.insert(owner(run)); - 1608
} - 1609
} - 1610
for spot in at.keys() { - 1611
if let Spot::InRun { run, .. } = spot { - 1612
changed.insert(owner(*run)); - 1613
} - 1614
} - 1615
let rewrite: HashSet<usize> = changed.iter().map(|node| unit(*node)).collect(); - 1616
/// Marks the containers above `node`, up to the paragraph. - 1617
fn open_above(tree: &Tree, paragraph: usize, open: &mut HashSet<usize>, node: usize) { - 1618
let mut current = tree.nodes[node].parent; - 1619
while let Some(ancestor) = current { - 1620
if !open.insert(ancestor) || ancestor == paragraph { - 1621
break; - 1622
} - 1623
current = tree.nodes[ancestor].parent; - 1624
} - 1625
} - 1626
let tree = part.tree; - 1627
let mut open = HashSet::new(); - 1628
for &unit in &rewrite { - 1629
open_above(tree, model.node, &mut open, unit); - 1630
} - 1631
for &node in &dropped { - 1632
open_above(tree, model.node, &mut open, node); - 1633
} - 1634
for spot in at.keys() { - 1635
match spot { - 1636
Spot::Before(node) | Spot::After(node) => { - 1637
open_above(tree, model.node, &mut open, *node); - 1638
} - 1639
Spot::End => { - 1640
open.insert(model.node); - 1641
} - 1642
Spot::InRun { .. } => {} - 1643
} - 1644
} - 1645
Self { - 1646
part, - 1647
model, - 1648
keep, - 1649
rewrite, - 1650
changed, - 1651
open, - 1652
dropped, - 1653
at, - 1654
next_id: first_id, - 1655
author: &context.author, - 1656
date: &context.date, - 1657
} - 1658
} - 1659
- 1660
fn revision(&mut self) -> String { - 1661
let id = self.next_id; - 1662
self.next_id += 1; - 1663
let w = self.part.w; - 1664
format!( - 1665
r#" {w}id="{id}" {w}author="{}" {w}date="{}""#, - 1666
escape_attr(self.author), - 1667
escape_attr(self.date) - 1668
) - 1669
} - 1670
- 1671
fn insertions(&mut self, spot: Spot, out: &mut Vec<u8>) { - 1672
if let Some(list) = self.at.remove(&spot) { - 1673
self.render(list, out); - 1674
} - 1675
} - 1676
- 1677
/// New text: a tracked insertion, or in a new document plain runs. - 1678
fn render(&mut self, list: Vec<(String, String)>, out: &mut Vec<u8>) { - 1679
for (properties, text) in list { - 1680
let w = self.part.w; - 1681
let run = format!("<{w}r>{properties}{}</{w}r>", run_content(w, &text)); - 1682
if self.model.tracked { - 1683
let revision = self.revision(); - 1684
out.extend(format!("<{w}ins{revision}>{run}</{w}ins>").into_bytes()); - 1685
} else { - 1686
out.extend(run.into_bytes()); - 1687
} - 1688
} - 1689
} - 1690
- 1691
fn children(&mut self, node: usize) -> Result<Vec<u8>, EditError> { - 1692
let tree = self.part.tree; - 1693
let bytes = self.part.bytes; - 1694
let parent = &tree.nodes[node]; - 1695
let mut out = Vec::new(); - 1696
let mut cursor = parent.inner.start; - 1697
for &child in &parent.children { - 1698
let span = tree.nodes[child].span.clone(); - 1699
out.extend_from_slice(&bytes[cursor..span.start]); - 1700
self.insertions(Spot::Before(child), &mut out); - 1701
out.extend(self.node(child)?); - 1702
self.insertions(Spot::After(child), &mut out); - 1703
cursor = span.end; - 1704
} - 1705
out.extend_from_slice(&bytes[cursor.max(parent.inner.start)..parent.inner.end]); - 1706
if node == self.model.node { - 1707
self.insertions(Spot::End, &mut out); - 1708
} - 1709
Ok(out) - 1710
} - 1711
- 1712
fn node(&mut self, node: usize) -> Result<Vec<u8>, EditError> { - 1713
if self.dropped.contains(&node) { - 1714
return Ok(Vec::new()); - 1715
} - 1716
if self.rewrite.contains(&node) { - 1717
return if self.model.theirs.contains_key(&node) { - 1718
self.theirs(node) - 1719
} else if self.model.own_deletions.contains_key(&node) { - 1720
self.own_deletion(node).map(concat) - 1721
} else { - 1722
self.plain_run(node).map(concat) - 1723
}; - 1724
} - 1725
let element = &self.part.tree.nodes[node]; - 1726
if self.open.contains(&node) && !element.is_empty_element() { - 1727
let mut out = self.part.bytes[element.span.start..element.inner.start].to_vec(); - 1728
out.extend(self.children(node)?); - 1729
out.extend_from_slice(&self.part.bytes[element.inner.end..element.span.end]); - 1730
return Ok(out); - 1731
} - 1732
Ok(self.part.bytes[element.span.clone()].to_vec()) - 1733
} - 1734
- 1735
fn close(&self, local: &str) -> Vec<u8> { - 1736
format!("</{}{local}>", self.part.w).into_bytes() - 1737
} - 1738
- 1739
fn plain_run(&mut self, run: usize) -> Result<Vec<Piece>, EditError> { - 1740
let mut pieces = Vec::new(); - 1741
for segment in self.segments(run)? { - 1742
match segment { - 1743
Segment::Run { deleted: true, xml } => { - 1744
// A new document is written clean: deleted text just goes. - 1745
if self.model.tracked { - 1746
let revision = self.revision(); - 1747
let mut wrapped = format!("<{}del{revision}>", self.part.w).into_bytes(); - 1748
wrapped.extend(xml); - 1749
wrapped.extend(self.close("del")); - 1750
pieces.push(Piece::Kept(wrapped)); - 1751
} - 1752
} - 1753
Segment::Run { xml, .. } => pieces.push(Piece::Kept(xml)), - 1754
Segment::Inserted(list) => { - 1755
let mut out = Vec::new(); - 1756
self.render(list, &mut out); - 1757
pieces.push(Piece::New(out)); - 1758
} - 1759
} - 1760
} - 1761
Ok(pieces) - 1762
} - 1763
- 1764
fn own_deletion(&mut self, wrapper: usize) -> Result<Vec<Piece>, EditError> { - 1765
let runs = self - 1766
.model - 1767
.own_deletions - 1768
.get(&wrapper) - 1769
.cloned() - 1770
.unwrap_or_default(); - 1771
let mut pieces = Vec::new(); - 1772
let mut kept = Vec::new(); - 1773
let mut open = false; - 1774
for run in runs { - 1775
for segment in self.segments(run)? { - 1776
match segment { - 1777
Segment::Run { deleted: true, xml } => { - 1778
if !open { - 1779
let revision = self.revision(); - 1780
kept.extend(format!("<{}del{revision}>", self.part.w).into_bytes()); - 1781
open = true; - 1782
} - 1783
kept.extend(xml); - 1784
} - 1785
Segment::Run { xml, .. } => { - 1786
if open { - 1787
kept.extend(self.close("del")); - 1788
open = false; - 1789
} - 1790
kept.extend(xml); - 1791
} - 1792
Segment::Inserted(list) => { - 1793
if open { - 1794
kept.extend(self.close("del")); - 1795
open = false; - 1796
} - 1797
if !kept.is_empty() { - 1798
pieces.push(Piece::Kept(std::mem::take(&mut kept))); - 1799
} - 1800
let mut out = Vec::new(); - 1801
self.render(list, &mut out); - 1802
pieces.push(Piece::New(out)); - 1803
} - 1804
} - 1805
} - 1806
} - 1807
if open { - 1808
kept.extend(self.close("del")); - 1809
} - 1810
if !kept.is_empty() { - 1811
pieces.push(Piece::Kept(kept)); - 1812
} - 1813
Ok(pieces) - 1814
} - 1815
- 1816
/// Another author's insertion with a change inside it: struck text is a - 1817
/// deletion nested inside their insertion, and new text closes their - 1818
/// insertion, follows it, and opens it again (with a fresh id), so it is - 1819
/// never nested inside. - 1820
fn theirs(&mut self, wrapper: usize) -> Result<Vec<u8>, EditError> { - 1821
let tree = self.part.tree; - 1822
let bytes = self.part.bytes; - 1823
let node = &tree.nodes[wrapper]; - 1824
let open_tag = &bytes[node.span.start..node.inner.start]; - 1825
let close_tag = &bytes[node.inner.end..node.span.end]; - 1826
let mut out = Vec::new(); - 1827
let mut inside = Vec::new(); - 1828
let mut reopened = false; - 1829
for &child in &node.children { - 1830
let pieces = if !self.changed.contains(&child) { - 1831
vec![Piece::Kept(bytes[tree.nodes[child].span.clone()].to_vec())] - 1832
} else if self.model.own_deletions.contains_key(&child) { - 1833
self.own_deletion(child)? - 1834
} else { - 1835
self.plain_run(child)? - 1836
}; - 1837
for piece in pieces { - 1838
match piece { - 1839
Piece::Kept(xml) => inside.extend(xml), - 1840
Piece::New(xml) => { - 1841
self.close_theirs( - 1842
wrapper, - 1843
open_tag, - 1844
close_tag, - 1845
&mut reopened, - 1846
&mut inside, - 1847
&mut out, - 1848
); - 1849
out.extend(xml); - 1850
} - 1851
} - 1852
} - 1853
} - 1854
self.close_theirs( - 1855
wrapper, - 1856
open_tag, - 1857
close_tag, - 1858
&mut reopened, - 1859
&mut inside, - 1860
&mut out, - 1861
); - 1862
Ok(out) - 1863
} - 1864
- 1865
/// Writes the other author's insertion around what has gathered inside - 1866
/// it: with its own start tag the first time, a fresh id after that. - 1867
fn close_theirs( - 1868
&mut self, - 1869
wrapper: usize, - 1870
open_tag: &[u8], - 1871
close_tag: &[u8], - 1872
reopened: &mut bool, - 1873
inside: &mut Vec<u8>, - 1874
out: &mut Vec<u8>, - 1875
) { - 1876
if inside.is_empty() { - 1877
return; - 1878
} - 1879
if *reopened { - 1880
let element = &self.part.tree.nodes[wrapper].element; - 1881
let id = self.next_id; - 1882
self.next_id += 1; - 1883
let attributes: Vec<(String, String)> = element - 1884
.attributes - 1885
.iter() - 1886
.map(|(key, value)| { - 1887
if crate::xml::local_name(key) == "id" { - 1888
(key.clone(), id.to_string()) - 1889
} else { - 1890
(key.clone(), value.clone()) - 1891
} - 1892
}) - 1893
.collect(); - 1894
out.extend(start_tag(&element.name, &attributes, false).into_bytes()); - 1895
} else { - 1896
out.extend_from_slice(open_tag); - 1897
} - 1898
out.append(inside); - 1899
out.extend_from_slice(close_tag); - 1900
*reopened = true; - 1901
} - 1902
- 1903
/// A run cut where its characters change state or new text goes in: - 1904
/// every piece keeps the run's own start tag and formatting. - 1905
fn segments(&mut self, run: usize) -> Result<Vec<Segment>, EditError> { - 1906
let tree = self.part.tree; - 1907
let bytes = self.part.bytes; - 1908
let model: &'p Paragraph = self.model; - 1909
let keep: &'p [bool] = self.keep; - 1910
let node = &tree.nodes[run]; - 1911
let open_tag = &bytes[node.span.start..node.inner.start]; - 1912
let close_tag = &bytes[node.inner.end..node.span.end]; - 1913
let properties: &[u8] = tree - 1914
.children(run, "rPr") - 1915
.next() - 1916
.map(|properties| &bytes[tree.nodes[properties].span.clone()]) - 1917
.unwrap_or_default(); - 1918
let wrap = |deleted: bool, pieces: Vec<u8>| { - 1919
let mut xml = open_tag.to_vec(); - 1920
xml.extend_from_slice(properties); - 1921
xml.extend(pieces); - 1922
xml.extend_from_slice(close_tag); - 1923
Segment::Run { deleted, xml } - 1924
}; - 1925
let children = model.run_children.get(&run).cloned().unwrap_or_default(); - 1926
let base_deleted = model.in_own_deletion.contains_key(&run); - 1927
let mut segments = Vec::new(); - 1928
let mut current: Option<(bool, Vec<u8>)> = None; - 1929
let push = |current: &mut Option<(bool, Vec<u8>)>, - 1930
segments: &mut Vec<Segment>, - 1931
deleted: bool, - 1932
xml: Vec<u8>| { - 1933
match current { - 1934
Some((state, pieces)) if *state == deleted => pieces.extend(xml), - 1935
_ => { - 1936
if let Some((state, pieces)) = current.take() { - 1937
segments.push(wrap(state, pieces)); - 1938
} - 1939
*current = Some((deleted, xml)); - 1940
} - 1941
} - 1942
}; - 1943
for (index, &child) in children.iter().enumerate() { - 1944
self.split(run, index, 0, &mut current, &mut segments, &wrap); - 1945
let chunk = model - 1946
.chunk_of - 1947
.get(&child) - 1948
.map(|chunk| &model.chunks[*chunk]) - 1949
.filter(|chunk| !matches!(chunk.role, Role::Guarded(_))); - 1950
let Some(chunk) = chunk else { - 1951
push( - 1952
&mut current, - 1953
&mut segments, - 1954
base_deleted, - 1955
bytes[tree.nodes[child].span.clone()].to_vec(), - 1956
); - 1957
continue; - 1958
}; - 1959
let deleted: Vec<bool> = (0..chunk.text.len()) - 1960
.map(|offset| !keep[chunk.start + offset]) - 1961
.collect(); - 1962
if !chunk.splittable { - 1963
push( - 1964
&mut current, - 1965
&mut segments, - 1966
deleted.first().copied().unwrap_or(base_deleted), - 1967
bytes[tree.nodes[child].span.clone()].to_vec(), - 1968
); - 1969
continue; - 1970
} - 1971
let mut from = 0; - 1972
for to in 1..=chunk.text.len() { - 1973
let split_here = to < chunk.text.len() - 1974
&& self.at.contains_key(&Spot::InRun { - 1975
run, - 1976
child: index, - 1977
offset: to, - 1978
}); - 1979
if to == chunk.text.len() || deleted[to] != deleted[from] || split_here { - 1980
let piece = self.text_piece(child, chunk, from..to, deleted[from]); - 1981
push(&mut current, &mut segments, deleted[from], piece); - 1982
if split_here { - 1983
self.split(run, index, to, &mut current, &mut segments, &wrap); - 1984
} - 1985
from = to; - 1986
} - 1987
} - 1988
} - 1989
self.split(run, children.len(), 0, &mut current, &mut segments, &wrap); - 1990
if let Some((state, pieces)) = current.take() { - 1991
segments.push(wrap(state, pieces)); - 1992
} - 1993
Ok(segments) - 1994
} - 1995
- 1996
/// New text inside a run: closes the piece before it. - 1997
fn split( - 1998
&mut self, - 1999
run: usize, - 2000
child: usize,
Indexing the workspace…
Vakyartha documentation is discovering safe artifacts, anchors, and source references.