diff --git a/Cargo.lock b/Cargo.lock index bed1a1976c..f0504ebc48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1555,7 +1555,7 @@ dependencies = [ "envy", "fs", "futures 0.3.28", - "git3", + "git", "gpui2", "hyper", "indoc", @@ -2482,7 +2482,7 @@ dependencies = [ "env_logger", "futures 0.3.28", "fuzzy", - "git3", + "git", "gpui2", "indoc", "itertools 0.10.5", @@ -3181,7 +3181,7 @@ dependencies = [ "parking_lot 0.11.2", "smol", "sum_tree", - "text", + "text2", "unindent", "util", ] @@ -3199,26 +3199,6 @@ dependencies = [ "url", ] -[[package]] -name = "git3" -version = "0.1.0" -dependencies = [ - "anyhow", - "async-trait", - "clock", - "collections", - "futures 0.3.28", - "git2", - "lazy_static", - "log", - "parking_lot 0.11.2", - "smol", - "sum_tree", - "text2", - "unindent", - "util", -] - [[package]] name = "glob" version = "0.3.1" @@ -4044,7 +4024,7 @@ dependencies = [ "env_logger", "futures 0.3.28", "fuzzy", - "git3", + "git", "globset", "gpui2", "indoc", @@ -4714,7 +4694,7 @@ dependencies = [ "ctor", "env_logger", "futures 0.3.28", - "git3", + "git", "gpui2", "indoc", "itertools 0.10.5", @@ -5830,8 +5810,8 @@ dependencies = [ "fsevent", "futures 0.3.28", "fuzzy", + "git", "git2", - "git3", "globset", "gpui2", "ignore", diff --git a/crates/collab2/Cargo.toml b/crates/collab2/Cargo.toml index c11aadc085..32b2885aeb 100644 --- a/crates/collab2/Cargo.toml +++ b/crates/collab2/Cargo.toml @@ -69,7 +69,7 @@ channel = { path = "../channel" } editor = { path = "../editor", features = ["test-support"] } language = { path = "../language", features = ["test-support"] } fs = { path = "../fs", features = ["test-support"] } -git = { package = "git3", path = "../git3", features = ["test-support"] } +git = { path = "../git", features = ["test-support"] } live_kit_client = { package = "live_kit_client2", path = "../live_kit_client2", features = ["test-support"] } lsp = { path = "../lsp", features = ["test-support"] } node_runtime = { path = "../node_runtime" } diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index 0f1c3385b5..59e54bc14f 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -30,7 +30,7 @@ db = { path = "../db" } collections = { path = "../collections" } # context_menu = { path = "../context_menu" } fuzzy = { path = "../fuzzy" } -git = { package = "git3", path = "../git3" } +git = { path = "../git" } gpui = { package = "gpui2", path = "../gpui2" } language = { path = "../language" } lsp = { path = "../lsp" } diff --git a/crates/git/Cargo.toml b/crates/git/Cargo.toml index 72668ba766..1fc5da42d7 100644 --- a/crates/git/Cargo.toml +++ b/crates/git/Cargo.toml @@ -12,7 +12,7 @@ anyhow.workspace = true clock = { path = "../clock" } lazy_static.workspace = true sum_tree = { path = "../sum_tree" } -text = { path = "../text" } +text = { package = "text2", path = "../text2" } collections = { path = "../collections" } util = { path = "../util" } log.workspace = true diff --git a/crates/git3/Cargo.toml b/crates/git3/Cargo.toml deleted file mode 100644 index e88fa6574d..0000000000 --- a/crates/git3/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -# git2 was already taken. -name = "git3" -version = "0.1.0" -edition = "2021" -publish = false - -[lib] -path = "src/git.rs" - -[dependencies] -anyhow.workspace = true -clock = { path = "../clock" } -lazy_static.workspace = true -sum_tree = { path = "../sum_tree" } -text = { package = "text2", path = "../text2" } -collections = { path = "../collections" } -util = { path = "../util" } -log.workspace = true -smol.workspace = true -parking_lot.workspace = true -async-trait.workspace = true -futures.workspace = true -git2.workspace = true - -[dev-dependencies] -unindent.workspace = true - -[features] -test-support = [] diff --git a/crates/git3/src/diff.rs b/crates/git3/src/diff.rs deleted file mode 100644 index 39383cfc78..0000000000 --- a/crates/git3/src/diff.rs +++ /dev/null @@ -1,412 +0,0 @@ -use std::{iter, ops::Range}; -use sum_tree::SumTree; -use text::{Anchor, BufferSnapshot, OffsetRangeExt, Point}; - -pub use git2 as libgit; -use libgit::{DiffLineType as GitDiffLineType, DiffOptions as GitOptions, Patch as GitPatch}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DiffHunkStatus { - Added, - Modified, - Removed, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct DiffHunk { - pub buffer_range: Range, - pub diff_base_byte_range: Range, -} - -impl DiffHunk { - pub fn status(&self) -> DiffHunkStatus { - if self.diff_base_byte_range.is_empty() { - DiffHunkStatus::Added - } else if self.buffer_range.is_empty() { - DiffHunkStatus::Removed - } else { - DiffHunkStatus::Modified - } - } -} - -impl sum_tree::Item for DiffHunk { - type Summary = DiffHunkSummary; - - fn summary(&self) -> Self::Summary { - DiffHunkSummary { - buffer_range: self.buffer_range.clone(), - } - } -} - -#[derive(Debug, Default, Clone)] -pub struct DiffHunkSummary { - buffer_range: Range, -} - -impl sum_tree::Summary for DiffHunkSummary { - type Context = text::BufferSnapshot; - - fn add_summary(&mut self, other: &Self, buffer: &Self::Context) { - self.buffer_range.start = self - .buffer_range - .start - .min(&other.buffer_range.start, buffer); - self.buffer_range.end = self.buffer_range.end.max(&other.buffer_range.end, buffer); - } -} - -#[derive(Clone)] -pub struct BufferDiff { - last_buffer_version: Option, - tree: SumTree>, -} - -impl BufferDiff { - pub fn new() -> BufferDiff { - BufferDiff { - last_buffer_version: None, - tree: SumTree::new(), - } - } - - pub fn is_empty(&self) -> bool { - self.tree.is_empty() - } - - pub fn hunks_in_row_range<'a>( - &'a self, - range: Range, - buffer: &'a BufferSnapshot, - ) -> impl 'a + Iterator> { - let start = buffer.anchor_before(Point::new(range.start, 0)); - let end = buffer.anchor_after(Point::new(range.end, 0)); - - self.hunks_intersecting_range(start..end, buffer) - } - - pub fn hunks_intersecting_range<'a>( - &'a self, - range: Range, - buffer: &'a BufferSnapshot, - ) -> impl 'a + Iterator> { - let mut cursor = self.tree.filter::<_, DiffHunkSummary>(move |summary| { - let before_start = summary.buffer_range.end.cmp(&range.start, buffer).is_lt(); - let after_end = summary.buffer_range.start.cmp(&range.end, buffer).is_gt(); - !before_start && !after_end - }); - - let anchor_iter = std::iter::from_fn(move || { - cursor.next(buffer); - cursor.item() - }) - .flat_map(move |hunk| { - [ - (&hunk.buffer_range.start, hunk.diff_base_byte_range.start), - (&hunk.buffer_range.end, hunk.diff_base_byte_range.end), - ] - .into_iter() - }); - - let mut summaries = buffer.summaries_for_anchors_with_payload::(anchor_iter); - iter::from_fn(move || { - let (start_point, start_base) = summaries.next()?; - let (end_point, end_base) = summaries.next()?; - - let end_row = if end_point.column > 0 { - end_point.row + 1 - } else { - end_point.row - }; - - Some(DiffHunk { - buffer_range: start_point.row..end_row, - diff_base_byte_range: start_base..end_base, - }) - }) - } - - pub fn hunks_intersecting_range_rev<'a>( - &'a self, - range: Range, - buffer: &'a BufferSnapshot, - ) -> impl 'a + Iterator> { - let mut cursor = self.tree.filter::<_, DiffHunkSummary>(move |summary| { - let before_start = summary.buffer_range.end.cmp(&range.start, buffer).is_lt(); - let after_end = summary.buffer_range.start.cmp(&range.end, buffer).is_gt(); - !before_start && !after_end - }); - - std::iter::from_fn(move || { - cursor.prev(buffer); - - let hunk = cursor.item()?; - let range = hunk.buffer_range.to_point(buffer); - let end_row = if range.end.column > 0 { - range.end.row + 1 - } else { - range.end.row - }; - - Some(DiffHunk { - buffer_range: range.start.row..end_row, - diff_base_byte_range: hunk.diff_base_byte_range.clone(), - }) - }) - } - - pub fn clear(&mut self, buffer: &text::BufferSnapshot) { - self.last_buffer_version = Some(buffer.version().clone()); - self.tree = SumTree::new(); - } - - pub async fn update(&mut self, diff_base: &str, buffer: &text::BufferSnapshot) { - let mut tree = SumTree::new(); - - let buffer_text = buffer.as_rope().to_string(); - let patch = Self::diff(&diff_base, &buffer_text); - - if let Some(patch) = patch { - let mut divergence = 0; - for hunk_index in 0..patch.num_hunks() { - let hunk = Self::process_patch_hunk(&patch, hunk_index, buffer, &mut divergence); - tree.push(hunk, buffer); - } - } - - self.tree = tree; - self.last_buffer_version = Some(buffer.version().clone()); - } - - #[cfg(test)] - fn hunks<'a>(&'a self, text: &'a BufferSnapshot) -> impl 'a + Iterator> { - let start = text.anchor_before(Point::new(0, 0)); - let end = text.anchor_after(Point::new(u32::MAX, u32::MAX)); - self.hunks_intersecting_range(start..end, text) - } - - fn diff<'a>(head: &'a str, current: &'a str) -> Option> { - let mut options = GitOptions::default(); - options.context_lines(0); - - let patch = GitPatch::from_buffers( - head.as_bytes(), - None, - current.as_bytes(), - None, - Some(&mut options), - ); - - match patch { - Ok(patch) => Some(patch), - - Err(err) => { - log::error!("`GitPatch::from_buffers` failed: {}", err); - None - } - } - } - - fn process_patch_hunk<'a>( - patch: &GitPatch<'a>, - hunk_index: usize, - buffer: &text::BufferSnapshot, - buffer_row_divergence: &mut i64, - ) -> DiffHunk { - let line_item_count = patch.num_lines_in_hunk(hunk_index).unwrap(); - assert!(line_item_count > 0); - - let mut first_deletion_buffer_row: Option = None; - let mut buffer_row_range: Option> = None; - let mut diff_base_byte_range: Option> = None; - - for line_index in 0..line_item_count { - let line = patch.line_in_hunk(hunk_index, line_index).unwrap(); - let kind = line.origin_value(); - let content_offset = line.content_offset() as isize; - let content_len = line.content().len() as isize; - - if kind == GitDiffLineType::Addition { - *buffer_row_divergence += 1; - let row = line.new_lineno().unwrap().saturating_sub(1); - - match &mut buffer_row_range { - Some(buffer_row_range) => buffer_row_range.end = row + 1, - None => buffer_row_range = Some(row..row + 1), - } - } - - if kind == GitDiffLineType::Deletion { - let end = content_offset + content_len; - - match &mut diff_base_byte_range { - Some(head_byte_range) => head_byte_range.end = end as usize, - None => diff_base_byte_range = Some(content_offset as usize..end as usize), - } - - if first_deletion_buffer_row.is_none() { - let old_row = line.old_lineno().unwrap().saturating_sub(1); - let row = old_row as i64 + *buffer_row_divergence; - first_deletion_buffer_row = Some(row as u32); - } - - *buffer_row_divergence -= 1; - } - } - - //unwrap_or deletion without addition - let buffer_row_range = buffer_row_range.unwrap_or_else(|| { - //we cannot have an addition-less hunk without deletion(s) or else there would be no hunk - let row = first_deletion_buffer_row.unwrap(); - row..row - }); - - //unwrap_or addition without deletion - let diff_base_byte_range = diff_base_byte_range.unwrap_or(0..0); - - let start = Point::new(buffer_row_range.start, 0); - let end = Point::new(buffer_row_range.end, 0); - let buffer_range = buffer.anchor_before(start)..buffer.anchor_before(end); - DiffHunk { - buffer_range, - diff_base_byte_range, - } - } -} - -/// Range (crossing new lines), old, new -#[cfg(any(test, feature = "test-support"))] -#[track_caller] -pub fn assert_hunks( - diff_hunks: Iter, - buffer: &BufferSnapshot, - diff_base: &str, - expected_hunks: &[(Range, &str, &str)], -) where - Iter: Iterator>, -{ - let actual_hunks = diff_hunks - .map(|hunk| { - ( - hunk.buffer_range.clone(), - &diff_base[hunk.diff_base_byte_range], - buffer - .text_for_range( - Point::new(hunk.buffer_range.start, 0) - ..Point::new(hunk.buffer_range.end, 0), - ) - .collect::(), - ) - }) - .collect::>(); - - let expected_hunks: Vec<_> = expected_hunks - .iter() - .map(|(r, s, h)| (r.clone(), *s, h.to_string())) - .collect(); - - assert_eq!(actual_hunks, expected_hunks); -} - -#[cfg(test)] -mod tests { - use std::assert_eq; - - use super::*; - use text::Buffer; - use unindent::Unindent as _; - - #[test] - fn test_buffer_diff_simple() { - let diff_base = " - one - two - three - " - .unindent(); - - let buffer_text = " - one - HELLO - three - " - .unindent(); - - let mut buffer = Buffer::new(0, 0, buffer_text); - let mut diff = BufferDiff::new(); - smol::block_on(diff.update(&diff_base, &buffer)); - assert_hunks( - diff.hunks(&buffer), - &buffer, - &diff_base, - &[(1..2, "two\n", "HELLO\n")], - ); - - buffer.edit([(0..0, "point five\n")]); - smol::block_on(diff.update(&diff_base, &buffer)); - assert_hunks( - diff.hunks(&buffer), - &buffer, - &diff_base, - &[(0..1, "", "point five\n"), (2..3, "two\n", "HELLO\n")], - ); - - diff.clear(&buffer); - assert_hunks(diff.hunks(&buffer), &buffer, &diff_base, &[]); - } - - #[test] - fn test_buffer_diff_range() { - let diff_base = " - one - two - three - four - five - six - seven - eight - nine - ten - " - .unindent(); - - let buffer_text = " - A - one - B - two - C - three - HELLO - four - five - SIXTEEN - seven - eight - WORLD - nine - - ten - - " - .unindent(); - - let buffer = Buffer::new(0, 0, buffer_text); - let mut diff = BufferDiff::new(); - smol::block_on(diff.update(&diff_base, &buffer)); - assert_eq!(diff.hunks(&buffer).count(), 8); - - assert_hunks( - diff.hunks_in_row_range(7..12, &buffer), - &buffer, - &diff_base, - &[ - (6..7, "", "HELLO\n"), - (9..10, "six\n", "SIXTEEN\n"), - (12..13, "", "WORLD\n"), - ], - ); - } -} diff --git a/crates/git3/src/git.rs b/crates/git3/src/git.rs deleted file mode 100644 index b1b885eca2..0000000000 --- a/crates/git3/src/git.rs +++ /dev/null @@ -1,11 +0,0 @@ -use std::ffi::OsStr; - -pub use git2 as libgit; -pub use lazy_static::lazy_static; - -pub mod diff; - -lazy_static! { - pub static ref DOT_GIT: &'static OsStr = OsStr::new(".git"); - pub static ref GITIGNORE: &'static OsStr = OsStr::new(".gitignore"); -} diff --git a/crates/language/Cargo.toml b/crates/language/Cargo.toml index e721eb8c93..31da2cacc1 100644 --- a/crates/language/Cargo.toml +++ b/crates/language/Cargo.toml @@ -25,7 +25,7 @@ test-support = [ clock = { path = "../clock" } collections = { path = "../collections" } fuzzy = { path = "../fuzzy" } -git = { package = "git3", path = "../git3" } +git = { path = "../git" } gpui = { package = "gpui2", path = "../gpui2" } lsp = { path = "../lsp" } rpc = { path = "../rpc" } diff --git a/crates/multi_buffer/Cargo.toml b/crates/multi_buffer/Cargo.toml index 0f95db86ad..91fb64699c 100644 --- a/crates/multi_buffer/Cargo.toml +++ b/crates/multi_buffer/Cargo.toml @@ -23,7 +23,7 @@ test-support = [ client = { path = "../client" } clock = { path = "../clock" } collections = { path = "../collections" } -git = { package = "git3", path = "../git3" } +git = { path = "../git" } gpui = { package = "gpui2", path = "../gpui2" } language = { path = "../language" } lsp = { path = "../lsp" } diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index 33cb1762ac..be3ecf51c4 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -29,7 +29,7 @@ db = { path = "../db" } fs = { path = "../fs" } fsevent = { path = "../fsevent" } fuzzy = { path = "../fuzzy" } -git = { package = "git3", path = "../git3" } +git = { path = "../git" } gpui = { package = "gpui2", path = "../gpui2" } language = { path = "../language" } lsp = { path = "../lsp" }