Markdown parser fork with extended syntax for personal use.
at hack 148 lines 4.6 kB view raw
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}