From 4b2040a7ca3d12f0614ed8ea9a5f0cb78b521343 Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 12 Sep 2022 15:38:44 -0400 Subject: [PATCH] Move diff logic back into `BufferDiff::update` --- crates/language/src/buffer.rs | 3 +- crates/language/src/git.rs | 351 +++++++++------------------------- 2 files changed, 88 insertions(+), 266 deletions(-) diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 37f21511333372bfea57a0102c807452d7be3dda..e75e17e54134cc92ffa120c3d5a2305c3cf617b3 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -48,7 +48,7 @@ pub use lsp::DiagnosticSeverity; pub struct Buffer { text: TextBuffer, - head_text: Option, + head_text: Option, git_diff: BufferDiff, file: Option>, saved_version: clock::Global, @@ -422,7 +422,6 @@ impl Buffer { }; let git_diff = BufferDiff::new(&head_text, &buffer); - let head_text = head_text.map(|h| Rope::from(h.as_str())); Self { saved_mtime, diff --git a/crates/language/src/git.rs b/crates/language/src/git.rs index b3e2f7da51793e202a90f1ed564d962e6c6430fb..4025a2a42fb404c08f5aed8e075dc2bc42689d59 100644 --- a/crates/language/src/git.rs +++ b/crates/language/src/git.rs @@ -83,64 +83,6 @@ impl<'a> sum_tree::Dimension<'a, DiffHunkSummary> for HunkBufferEnd { } } -// struct HunkIter<'a> { -// index: usize, -// patch: GitPatch<'a>, -// } - -// impl<'a> HunkIter<'a> { -// fn diff(head: &'a [u8], current: &'a [u8]) -> Option { -// let mut options = GitOptions::default(); -// options.context_lines(0); -// let patch = match GitPatch::from_buffers(head, None, current, None, Some(&mut options)) { -// Ok(patch) => patch, -// Err(_) => return None, -// }; - -// Some(HunkIter { index: 0, patch }) -// } - -// fn next(&mut self, buffer: &BufferSnapshot) -> Option> { -// if self.index >= self.patch.num_hunks() { -// return None; -// } - -// let (hunk, _) = match self.patch.hunk(self.index) { -// Ok(it) => it, -// Err(_) => return None, -// }; -// let hunk_line_count = self.patch.num_lines_in_hunk(self.index).unwrap(); - -// println!("{hunk:#?}"); -// for index in 0..hunk_line_count { -// println!("{:?}", self.patch.line_in_hunk(self.index, index)); -// } - -// let new_start = hunk.new_start() - 1; -// let new_end = new_start + hunk.new_lines(); -// let start_anchor = buffer.anchor_at(Point::new(new_start, 0), Bias::Left); -// let end_anchor = buffer.anchor_at(Point::new(new_end, 0), Bias::Left); -// let buffer_range = start_anchor..end_anchor; - -// //This is probably wrong? When does this trigger? Should buffer range also do this? -// let head_range = if hunk.old_start() == 0 { -// 0..0 -// } else { -// let old_start = hunk.old_start() - 1; -// let old_end = old_start + hunk.old_lines(); -// old_start..old_end -// }; - -// // let head_start_index = self.patch.line_in_hunk(self.index, 0) - -// self.index += 1; -// Some(DiffHunk { -// buffer_range, -// head_range, -// }) -// } -// } - #[derive(Clone)] pub struct BufferDiffSnapshot { tree: SumTree>, @@ -187,221 +129,102 @@ pub struct BufferDiff { impl BufferDiff { pub fn new(head_text: &Option, buffer: &text::BufferSnapshot) -> BufferDiff { - let hunks = if let Some(head_text) = head_text { - let buffer_string = buffer.as_rope().to_string(); - let buffer_bytes = buffer_string.as_bytes(); - - let mut options = GitOptions::default(); - options.context_lines(0); - let patch = match GitPatch::from_buffers( - head_text.as_bytes(), - None, - buffer_bytes, - None, - Some(&mut options), - ) { - Ok(patch) => patch, - Err(_) => todo!("This needs to be handled"), - }; - - let mut hunks = SumTree::>::new(); - let mut delta = 0i64; - for i in 0..patch.num_hunks() { - let diff_line_item_count = patch.num_lines_in_hunk(i).unwrap(); - - // if diff_line_item_count == 0 { - // continue; - // } - - // let calc_line_diff_hunk = || { - - // }; - - // let first_line = patch.line_in_hunk(0).unwrap(); - // let mut hunk = - - for j in 0..diff_line_item_count { - let line = patch.line_in_hunk(i, j).unwrap(); - - let hunk = match line.origin_value() { - libgit::DiffLineType::Addition => { - let buffer_start = line.content_offset(); - let buffer_end = buffer_start as usize + line.content().len(); - let head_offset = (buffer_start - delta) as usize; - delta += line.content().len() as i64; - DiffHunk { - buffer_range: buffer.anchor_before(buffer_start as usize) - ..buffer.anchor_after(buffer_end), - head_range: head_offset..head_offset, - } - } - libgit::DiffLineType::Deletion => { - let head_start = line.content_offset(); - let head_end = head_start as usize + line.content().len(); - let buffer_offset = (head_start + delta) as usize; - delta -= line.content().len() as i64; - DiffHunk { - buffer_range: buffer.anchor_before(buffer_offset) - ..buffer.anchor_after(buffer_offset), - head_range: (head_start as usize)..head_end, - } - } - - libgit::DiffLineType::AddEOFNL => todo!(), - libgit::DiffLineType::ContextEOFNL => todo!(), - libgit::DiffLineType::DeleteEOFNL => todo!(), - libgit::DiffLineType::Context => unreachable!(), - libgit::DiffLineType::FileHeader => continue, - libgit::DiffLineType::HunkHeader => continue, - libgit::DiffLineType::Binary => continue, - }; - - let mut combined = false; - hunks.update_last( - |last_hunk| { - if last_hunk.head_range.end == hunk.head_range.start { - last_hunk.head_range.end = hunk.head_range.end; - last_hunk.buffer_range.end = hunk.buffer_range.end; - combined = true; - } - }, - buffer, - ); - if !combined { - hunks.push(hunk, buffer); - } - } - } - - // let iter = HunkIter::diff(head_text.as_bytes(), buffer_bytes); - // if let Some(mut iter) = iter { - // let mut hunks = SumTree::new(); - // while let Some(hunk) = iter.next(buffer) { - // hunks.push(hunk, buffer); - // } - // println!("========"); - // hunks - // } else { - // SumTree::new() - // } - hunks - } else { - SumTree::new() + let mut instance = BufferDiff { + last_update_version: buffer.version().clone(), + snapshot: BufferDiffSnapshot { + tree: SumTree::new(), + }, }; - BufferDiff { - last_update_version: buffer.version().clone(), - snapshot: BufferDiffSnapshot { tree: hunks }, + if let Some(head_text) = head_text { + instance.update(head_text, buffer); } + + instance } pub fn snapshot(&self) -> BufferDiffSnapshot { self.snapshot.clone() } - pub fn update(&mut self, head: &Rope, buffer: &text::BufferSnapshot) { - // let expand_by = 20; - // let combine_distance = 5; - - // struct EditRange { - // head_start: u32, - // head_end: u32, - // buffer_start: u32, - // buffer_end: u32, - // } - - // let mut ranges = Vec::::new(); - - // for edit in buffer.edits_since::(&self.last_update_version) { - // //This bit is extremely wrong, this is not where these row lines should come from - // let head_start = edit.old.start.row.saturating_sub(expand_by); - // let head_end = (edit.old.end.row + expand_by).min(head.summary().lines.row + 1); - - // let buffer_start = edit.new.start.row.saturating_sub(expand_by); - // let buffer_end = (edit.new.end.row + expand_by).min(buffer.row_count()); - - // if let Some(last_range) = ranges.last_mut() { - // let head_distance = last_range.head_end.abs_diff(head_end); - // let buffer_distance = last_range.buffer_end.abs_diff(buffer_end); - - // if head_distance <= combine_distance || buffer_distance <= combine_distance { - // last_range.head_start = last_range.head_start.min(head_start); - // last_range.head_end = last_range.head_end.max(head_end); - - // last_range.buffer_start = last_range.buffer_start.min(buffer_start); - // last_range.buffer_end = last_range.buffer_end.max(buffer_end); - // } else { - // ranges.push(EditRange { - // head_start, - // head_end, - // buffer_start, - // buffer_end, - // }); - // } - // } else { - // ranges.push(EditRange { - // head_start, - // head_end, - // buffer_start, - // buffer_end, - // }); - // } - // } - - // self.last_update_version = buffer.version().clone(); - - // let mut new_hunks = SumTree::new(); - // let mut cursor = self.snapshot.tree.cursor::(); - - // for range in ranges { - // let head_range = range.head_start..range.head_end; - // let head_slice = head.slice_rows(head_range.clone()); - // let head_str = head_slice.to_string(); - - // let buffer_range = range.buffer_start..range.buffer_end; - // let buffer_slice = buffer.as_rope().slice_rows(buffer_range.clone()); - // let buffer_str = buffer_slice.to_string(); - - // println!("diffing head {:?}, buffer {:?}", head_range, buffer_range); - - // let mut iter = match HunkIter::diff(head_str.as_bytes(), buffer_str.as_bytes()) { - // Some(iter) => iter, - // None => continue, - // }; - - // while let Some(hunk) = iter.next(buffer) { - // println!("hunk"); - // let prefix = cursor.slice(&HunkHeadEnd(hunk.head_range.end), Bias::Right, buffer); - // println!("prefix len: {}", prefix.iter().count()); - // new_hunks.extend(prefix.iter().cloned(), buffer); - - // new_hunks.push(hunk.clone(), buffer); - - // cursor.seek(&HunkHeadEnd(hunk.head_range.end), Bias::Right, buffer); - // println!("item: {:?}", cursor.item()); - // if let Some(item) = cursor.item() { - // if item.head_range.end <= hunk.head_range.end { - // println!("skipping"); - // cursor.next(buffer); - // } - // } - // } - // } - - // new_hunks.extend( - // cursor - // .suffix(buffer) - // .iter() - // .map(|i| { - // println!("extending with {i:?}"); - // i - // }) - // .cloned(), - // buffer, - // ); - // drop(cursor); - - // self.snapshot.tree = new_hunks; + pub fn update(&mut self, head_text: &str, buffer: &text::BufferSnapshot) { + let buffer_string = buffer.as_rope().to_string(); + let buffer_bytes = buffer_string.as_bytes(); + + let mut options = GitOptions::default(); + options.context_lines(0); + let patch = match GitPatch::from_buffers( + head_text.as_bytes(), + None, + buffer_bytes, + None, + Some(&mut options), + ) { + Ok(patch) => patch, + Err(_) => todo!("This needs to be handled"), + }; + + let mut hunks = SumTree::>::new(); + let mut delta = 0i64; + for hunk_index in 0..patch.num_hunks() { + for line_index in 0..patch.num_lines_in_hunk(hunk_index).unwrap() { + let line = patch.line_in_hunk(hunk_index, line_index).unwrap(); + + let hunk = match line.origin_value() { + libgit::DiffLineType::Addition => { + let buffer_start = line.content_offset(); + let buffer_end = buffer_start as usize + line.content().len(); + let head_offset = (buffer_start - delta) as usize; + delta += line.content().len() as i64; + DiffHunk { + buffer_range: buffer.anchor_before(buffer_start as usize) + ..buffer.anchor_after(buffer_end), + head_range: head_offset..head_offset, + } + } + + libgit::DiffLineType::Deletion => { + let head_start = line.content_offset(); + let head_end = head_start as usize + line.content().len(); + let buffer_offset = (head_start + delta) as usize; + delta -= line.content().len() as i64; + DiffHunk { + buffer_range: buffer.anchor_before(buffer_offset) + ..buffer.anchor_after(buffer_offset), + head_range: (head_start as usize)..head_end, + } + } + + libgit::DiffLineType::AddEOFNL => todo!(), + libgit::DiffLineType::ContextEOFNL => todo!(), + libgit::DiffLineType::DeleteEOFNL => todo!(), + + libgit::DiffLineType::FileHeader => continue, + libgit::DiffLineType::HunkHeader => continue, + libgit::DiffLineType::Binary => continue, + + //We specifically tell git to not give us context lines + libgit::DiffLineType::Context => unreachable!(), + }; + + let mut combined = false; + hunks.update_last( + |last_hunk| { + if last_hunk.head_range.end == hunk.head_range.start { + last_hunk.head_range.end = hunk.head_range.end; + last_hunk.buffer_range.end = hunk.buffer_range.end; + combined = true; + } + }, + buffer, + ); + if !combined { + hunks.push(hunk, buffer); + } + } + } + + self.snapshot.tree = hunks; } }