Markdown parser fork with extended syntax for personal use.
1//! Deal with several changes in events, batching them together.
2//!
3//! Preferably, changes should be kept to a minimum.
4//! Sometimes, it’s needed to change the list of events, because parsing can be
5//! messy, and it helps to expose a cleaner interface of events to the compiler
6//! and other users.
7//! It can also help to merge many adjacent similar events.
8//! And, in other cases, it’s needed to parse subcontent: pass some events
9//! through another tokenizer and inject the result.
10
11use crate::event::Event;
12use alloc::{vec, vec::Vec};
13
14/// Shift `previous` and `next` links according to `jumps`.
15///
16/// This fixes links in case there are events removed or added between them.
17fn shift_links(events: &mut [Event], jumps: &[(usize, usize, usize)]) {
18 let mut jump_index = 0;
19 let mut index = 0;
20 let mut add = 0;
21 let mut rm = 0;
22
23 while index < events.len() {
24 let rm_curr = rm;
25
26 while jump_index < jumps.len() && jumps[jump_index].0 <= index {
27 add = jumps[jump_index].2;
28 rm = jumps[jump_index].1;
29 jump_index += 1;
30 }
31
32 // Ignore items that will be removed.
33 if rm > rm_curr {
34 index += rm - rm_curr;
35 } else {
36 if let Some(link) = &events[index].link {
37 if let Some(next) = link.next {
38 events[next].link.as_mut().unwrap().previous = Some(index + add - rm);
39
40 while jump_index < jumps.len() && jumps[jump_index].0 <= next {
41 add = jumps[jump_index].2;
42 rm = jumps[jump_index].1;
43 jump_index += 1;
44 }
45
46 events[index].link.as_mut().unwrap().next = Some(next + add - rm);
47 index = next;
48 continue;
49 }
50 }
51
52 index += 1;
53 }
54 }
55}
56
57/// Tracks a bunch of edits.
58#[derive(Debug)]
59pub struct EditMap {
60 /// Record of changes.
61 map: Vec<(usize, usize, Vec<Event>)>,
62}
63
64impl EditMap {
65 /// Create a new edit map.
66 pub fn new() -> EditMap {
67 EditMap { map: vec![] }
68 }
69 /// Create an edit: a remove and/or add at a certain place.
70 pub fn add(&mut self, index: usize, remove: usize, add: Vec<Event>) {
71 add_impl(self, index, remove, add, false);
72 }
73 /// Create an edit: but insert `add` before existing additions.
74 pub fn add_before(&mut self, index: usize, remove: usize, add: Vec<Event>) {
75 add_impl(self, index, remove, add, true);
76 }
77 /// Done, change the events.
78 pub fn consume(&mut self, events: &mut Vec<Event>) {
79 self.map
80 .sort_unstable_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
81
82 if self.map.is_empty() {
83 return;
84 }
85
86 // Calculate jumps: where items in the current list move to.
87 let mut jumps = Vec::with_capacity(self.map.len());
88 let mut index = 0;
89 let mut add_acc = 0;
90 let mut remove_acc = 0;
91 while index < self.map.len() {
92 let (at, remove, add) = &self.map[index];
93 remove_acc += remove;
94 add_acc += add.len();
95 jumps.push((*at, remove_acc, add_acc));
96 index += 1;
97 }
98
99 shift_links(events, &jumps);
100
101 let len_before = events.len();
102 let mut index = self.map.len();
103 let mut vecs = Vec::with_capacity(index * 2 + 1);
104 while index > 0 {
105 index -= 1;
106 vecs.push(events.split_off(self.map[index].0 + self.map[index].1));
107 vecs.push(self.map[index].2.split_off(0));
108 events.truncate(self.map[index].0);
109 }
110 vecs.push(events.split_off(0));
111
112 events.reserve(len_before + add_acc - remove_acc);
113
114 while let Some(mut slice) = vecs.pop() {
115 events.append(&mut slice);
116 }
117
118 self.map.truncate(0);
119 }
120}
121
122/// Create an edit.
123fn add_impl(edit_map: &mut EditMap, at: usize, remove: usize, mut add: Vec<Event>, before: bool) {
124 let mut index = 0;
125
126 if remove == 0 && add.is_empty() {
127 return;
128 }
129
130 while index < edit_map.map.len() {
131 if edit_map.map[index].0 == at {
132 edit_map.map[index].1 += remove;
133
134 if before {
135 add.append(&mut edit_map.map[index].2);
136 edit_map.map[index].2 = add;
137 } else {
138 edit_map.map[index].2.append(&mut add);
139 }
140
141 return;
142 }
143
144 index += 1;
145 }
146
147 edit_map.map.push((at, remove, add));
148}