use std::{char, sync::Arc};
use itertools::Itertools;
use rustc_hash::FxHashMap;
use crate::diff::DiffHandler;
use super::TextHandler;
pub(super) struct DiffHook<'a> {
text: &'a TextHandler,
new: &'a [u32],
last_old_index: usize,
current_index: usize,
}
impl<'a> DiffHook<'a> {
pub(crate) fn new(text: &'a TextHandler, new: &'a [u32]) -> Self {
Self {
text,
new,
last_old_index: 0,
current_index: 0,
}
}
}
impl DiffHandler for DiffHook<'_> {
fn insert(&mut self, old_index: usize, new_index: usize, new_len: usize) {
if old_index > self.last_old_index {
self.current_index += old_index - self.last_old_index;
self.last_old_index = old_index;
}
self.text
.insert_unicode(
self.current_index,
&self.new[new_index..new_index + new_len]
.iter()
.map(|x| char::from_u32(*x).unwrap())
.collect::<String>(),
)
.unwrap();
self.current_index += new_len;
}
fn delete(&mut self, old_index: usize, old_len: usize) {
self.current_index += old_index - self.last_old_index;
self.text
.delete_unicode(self.current_index, old_len)
.unwrap();
self.last_old_index = old_index + old_len;
}
}
pub(super) struct DiffHookForLine<'a> {
text: &'a TextHandler,
old: Vec<u32>,
new: Vec<u32>,
lines: Vec<Arc<str>>,
lines_lookup: FxHashMap<Arc<str>, usize>,
last_old_index: usize,
current_index: usize,
}
impl<'a> DiffHookForLine<'a> {
pub(crate) fn new(text: &'a TextHandler, new_str: &str) -> Self {
let mut this = Self {
text,
old: Vec::new(),
new: Vec::new(),
lines: Vec::new(),
lines_lookup: FxHashMap::default(),
last_old_index: 0,
current_index: 0,
};
let text_str = text.to_string();
for line in text_str.split_inclusive('\n') {
let line: Arc<str> = Arc::from(line);
let id = this.register_line(line);
this.old.push(id as u32);
}
for line in new_str.split_inclusive('\n') {
let line: Arc<str> = Arc::from(line);
let id = this.register_line(line);
this.new.push(id as u32);
}
this
}
fn register_line(&mut self, line: Arc<str>) -> usize {
if let Some(&index) = self.lines_lookup.get(&line) {
return index;
}
self.lines.push(line.clone());
self.lines_lookup.insert(line, self.lines.len() - 1);
self.lines.len() - 1
}
pub fn get_old_arr(&self) -> &[u32] {
&self.old
}
pub fn get_new_arr(&self) -> &[u32] {
&self.new
}
}
impl DiffHandler for DiffHookForLine<'_> {
fn insert(&mut self, old_index: usize, new_index: usize, new_len: usize) {
if self.last_old_index < old_index {
assert!(self.last_old_index < old_index);
self.current_index += (self.last_old_index..old_index)
.map(|x| self.lines[self.old[x] as usize].chars().count())
.sum::<usize>();
self.last_old_index = old_index;
}
let s = self.new[new_index..new_index + new_len]
.iter()
.map(|x| self.lines[*x as usize].clone())
.join("");
self.text.insert_unicode(self.current_index, &s).unwrap();
self.current_index += s.chars().count();
}
fn delete(&mut self, old_index: usize, old_len: usize) {
if self.last_old_index != old_index {
assert!(self.last_old_index < old_index);
self.current_index += (self.last_old_index..old_index)
.map(|x| self.lines[self.old[x] as usize].chars().count())
.sum::<usize>();
}
self.last_old_index = old_index + old_len;
let delete_len = (old_index..old_index + old_len)
.map(|x| self.lines[self.old[x] as usize].chars().count())
.sum::<usize>();
self.text
.delete_unicode(self.current_index, delete_len)
.unwrap();
}
}