Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

git: Compute and synchronize diffs from HEAD #23626

Merged
merged 49 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
3f93e8b
git: Use HEAD as base for buffer diffs
cole-miller Jan 24, 2025
28904b1
Fix
cole-miller Jan 24, 2025
2929836
Fix
cole-miller Jan 24, 2025
e9eade3
Merge remote-tracking branch 'origin/main' into cole/change-diff-base
cole-miller Jan 24, 2025
610f5dd
Merge origin/main
cole-miller Jan 27, 2025
5bdc5c0
Checkpoint
cole-miller Jan 28, 2025
c1b706e
Update zed.proto to prepare for fine-grained diff base sync
cole-miller Jan 28, 2025
21be179
WIP multiple diff bases
cole-miller Jan 29, 2025
76819d7
Fix more errors
cole-miller Jan 29, 2025
224ef9c
Warnings
cole-miller Jan 29, 2025
366725d
Fix remaining errors
cole-miller Jan 29, 2025
0bfc37b
Checkpoint
cole-miller Jan 29, 2025
5a00ea4
Checkpoint
cole-miller Jan 29, 2025
62914fc
Checkpoint
cole-miller Jan 29, 2025
618db0f
Implement last todos
cole-miller Jan 29, 2025
6457a77
Checkpoint
cole-miller Jan 29, 2025
53c9a3b
Rewrite recalculate_diffs
cole-miller Jan 29, 2025
9bc4248
Cleanup
cole-miller Jan 29, 2025
842d208
More cleanup
cole-miller Jan 29, 2025
7ba98e9
Add basic tests for new diff base handling
cole-miller Jan 30, 2025
304a6d5
Merge remote-tracking branch 'origin/main' into cole/change-diff-base
cole-miller Jan 30, 2025
d473d08
Fixes
cole-miller Jan 30, 2025
7f99ea4
Emit event
cole-miller Jan 30, 2025
946e01b
Fix a test
cole-miller Jan 30, 2025
e62be05
WIP
cole-miller Jan 30, 2025
8d13e75
WIP
cole-miller Jan 31, 2025
9e68581
Cleanup from previous iteration
cole-miller Jan 31, 2025
3e9b19e
Get more multibuffer randomized tests passing
maxbrunsfeld Jan 31, 2025
91eb05e
Reorder assertions
maxbrunsfeld Jan 31, 2025
c2ca767
Fix incorrect range ends in lift_buffer_metadata
maxbrunsfeld Jan 31, 2025
b379de2
Normalize base text in test-helper method new_with_base_text
maxbrunsfeld Jan 31, 2025
249d63f
Merge branch 'main' into cole/change-diff-base
maxbrunsfeld Jan 31, 2025
dbe170f
:art:
maxbrunsfeld Jan 31, 2025
f480013
Fix excerpt_boundaries in range when first excerpt starts with deleted
ConradIrwin Jan 31, 2025
7362451
SEED=1838
cole-miller Feb 3, 2025
1e37867
Don't expand hunks that start before the beginning of their excerpt
cole-miller Feb 4, 2025
23806a3
Avoid stale expanded hunks that fall just after an edit
cole-miller Feb 4, 2025
363c368
Merge remote-tracking branch 'origin/main' into cole/change-diff-base
cole-miller Feb 4, 2025
7129542
Fix proto
cole-miller Feb 4, 2025
847b790
hey! it looks like you're trying to use point-free style
cole-miller Feb 4, 2025
1eafefa
Fix
cole-miller Feb 4, 2025
ea46775
Fix
cole-miller Feb 4, 2025
ff4f1f4
Fix
cole-miller Feb 4, 2025
a0ac135
Fix remaining editor tests
cole-miller Feb 4, 2025
1a1b4f1
Merge remote-tracking branch 'origin/main' into cole/change-diff-base
cole-miller Feb 4, 2025
cdb8e5e
Fix after merge #1
cole-miller Feb 4, 2025
408ba97
Fix handling of anchors into removed excerpts in summaries_for_anchors
cole-miller Feb 4, 2025
a333b90
Merge remote-tracking branch 'origin/main' into cole/change-diff-base
cole-miller Feb 4, 2025
df9adc1
paperclip minimization
cole-miller Feb 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions crates/collab/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ impl Server {
.add_request_handler(forward_read_only_project_request::<proto::ResolveInlayHint>)
.add_request_handler(forward_read_only_project_request::<proto::OpenBufferByPath>)
.add_request_handler(forward_read_only_project_request::<proto::GitBranches>)
.add_request_handler(forward_read_only_project_request::<proto::GetStagedText>)
.add_request_handler(forward_read_only_project_request::<proto::OpenUnstagedChanges>)
.add_request_handler(forward_read_only_project_request::<proto::OpenUncommittedChanges>)
.add_request_handler(
forward_mutating_project_request::<proto::RegisterBufferWithLanguageServers>,
)
Expand Down Expand Up @@ -348,7 +349,7 @@ impl Server {
.add_message_handler(broadcast_project_message_from_host::<proto::UpdateBufferFile>)
.add_message_handler(broadcast_project_message_from_host::<proto::BufferReloaded>)
.add_message_handler(broadcast_project_message_from_host::<proto::BufferSaved>)
.add_message_handler(broadcast_project_message_from_host::<proto::UpdateDiffBase>)
.add_message_handler(broadcast_project_message_from_host::<proto::UpdateDiffBases>)
.add_request_handler(get_users)
.add_request_handler(fuzzy_search_users)
.add_request_handler(request_contact)
Expand Down
7 changes: 3 additions & 4 deletions crates/collab/src/tests/editor_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1991,10 +1991,9 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
.collect(),
remote_url: Some("[email protected]:zed-industries/zed.git".to_string()),
};
client_a.fs().set_blame_for_repo(
Path::new("/my-repo/.git"),
vec![(Path::new("file.txt"), blame)],
);
client_a
.fs()
.set_blame_for_repo(Path::new("/my-repo/.git"), vec![("file.txt".into(), blame)]);

let (project_a, worktree_id) = client_a.build_local_project("/my-repo", cx_a).await;
let project_id = active_call_a
Expand Down
134 changes: 96 additions & 38 deletions crates/collab/src/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2558,29 +2558,47 @@ async fn test_git_diff_base_change(

let project_remote = client_b.join_remote_project(project_id, cx_b).await;

let diff_base = "
let staged_text = "
one
three
"
.unindent();

let new_diff_base = "
let committed_text = "
one
TWO
three
"
.unindent();

let new_committed_text = "
one
TWO_HUNDRED
three
"
.unindent();

let new_staged_text = "
one
two
"
.unindent();

client_a.fs().set_index_for_repo(
Path::new("/dir/.git"),
&[(Path::new("a.txt"), diff_base.clone())],
&[("a.txt".into(), staged_text.clone())],
);
client_a.fs().set_head_for_repo(
Path::new("/dir/.git"),
&[("a.txt".into(), committed_text.clone())],
);

// Create the buffer
let buffer_local_a = project_local
.update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
.await
.unwrap();
let change_set_local_a = project_local
let local_unstaged_changes_a = project_local
.update(cx_a, |p, cx| {
p.open_unstaged_changes(buffer_local_a.clone(), cx)
})
Expand All @@ -2589,16 +2607,16 @@ async fn test_git_diff_base_change(

// Wait for it to catch up to the new diff
executor.run_until_parked();
change_set_local_a.read_with(cx_a, |change_set, cx| {
local_unstaged_changes_a.read_with(cx_a, |change_set, cx| {
let buffer = buffer_local_a.read(cx);
assert_eq!(
change_set.base_text_string().as_deref(),
Some(diff_base.as_str())
Some(staged_text.as_str())
);
git::diff::assert_hunks(
change_set.diff_to_buffer.hunks_in_row_range(0..4, buffer),
buffer,
&diff_base,
&change_set.base_text_string().unwrap(),
&[(1..2, "", "two\n")],
);
});
Expand All @@ -2608,7 +2626,7 @@ async fn test_git_diff_base_change(
.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
.await
.unwrap();
let change_set_remote_a = project_remote
let remote_unstaged_changes_a = project_remote
.update(cx_b, |p, cx| {
p.open_unstaged_changes(buffer_remote_a.clone(), cx)
})
Expand All @@ -2617,80 +2635,120 @@ async fn test_git_diff_base_change(

// Wait remote buffer to catch up to the new diff
executor.run_until_parked();
change_set_remote_a.read_with(cx_b, |change_set, cx| {
remote_unstaged_changes_a.read_with(cx_b, |change_set, cx| {
let buffer = buffer_remote_a.read(cx);
assert_eq!(
change_set.base_text_string().as_deref(),
Some(diff_base.as_str())
Some(staged_text.as_str())
);
git::diff::assert_hunks(
change_set.diff_to_buffer.hunks_in_row_range(0..4, buffer),
buffer,
&diff_base,
&change_set.base_text_string().unwrap(),
&[(1..2, "", "two\n")],
);
});

// Update the staged text of the open buffer
// Open uncommitted changes on the guest, without opening them on the host first
let remote_uncommitted_changes_a = project_remote
.update(cx_b, |p, cx| {
p.open_uncommitted_changes(buffer_remote_a.clone(), cx)
})
.await
.unwrap();
executor.run_until_parked();
remote_uncommitted_changes_a.read_with(cx_b, |change_set, cx| {
let buffer = buffer_remote_a.read(cx);
assert_eq!(
change_set.base_text_string().as_deref(),
Some(committed_text.as_str())
);
git::diff::assert_hunks(
change_set.diff_to_buffer.hunks_in_row_range(0..4, buffer),
buffer,
&change_set.base_text_string().unwrap(),
&[(1..2, "TWO\n", "two\n")],
);
});

// Update the index text of the open buffer
client_a.fs().set_index_for_repo(
Path::new("/dir/.git"),
&[(Path::new("a.txt"), new_diff_base.clone())],
&[("a.txt".into(), new_staged_text.clone())],
);
client_a.fs().set_head_for_repo(
Path::new("/dir/.git"),
&[("a.txt".into(), new_committed_text.clone())],
);

// Wait for buffer_local_a to receive it
executor.run_until_parked();
change_set_local_a.read_with(cx_a, |change_set, cx| {
local_unstaged_changes_a.read_with(cx_a, |change_set, cx| {
let buffer = buffer_local_a.read(cx);
assert_eq!(
change_set.base_text_string().as_deref(),
Some(new_diff_base.as_str())
Some(new_staged_text.as_str())
);
git::diff::assert_hunks(
change_set.diff_to_buffer.hunks_in_row_range(0..4, buffer),
buffer,
&new_diff_base,
&change_set.base_text_string().unwrap(),
&[(2..3, "", "three\n")],
);
});

change_set_remote_a.read_with(cx_b, |change_set, cx| {
remote_unstaged_changes_a.read_with(cx_b, |change_set, cx| {
let buffer = buffer_remote_a.read(cx);
assert_eq!(
change_set.base_text_string().as_deref(),
Some(new_diff_base.as_str())
Some(new_staged_text.as_str())
);
git::diff::assert_hunks(
change_set.diff_to_buffer.hunks_in_row_range(0..4, buffer),
buffer,
&new_diff_base,
&change_set.base_text_string().unwrap(),
&[(2..3, "", "three\n")],
);
});

remote_uncommitted_changes_a.read_with(cx_b, |change_set, cx| {
let buffer = buffer_remote_a.read(cx);
assert_eq!(
change_set.base_text_string().as_deref(),
Some(new_committed_text.as_str())
);
git::diff::assert_hunks(
change_set.diff_to_buffer.hunks_in_row_range(0..4, buffer),
buffer,
&change_set.base_text_string().unwrap(),
&[(1..2, "TWO_HUNDRED\n", "two\n")],
);
});

// Nested git dir
let diff_base = "
let staged_text = "
one
three
"
.unindent();

let new_diff_base = "
let new_staged_text = "
one
two
"
.unindent();

client_a.fs().set_index_for_repo(
Path::new("/dir/sub/.git"),
&[(Path::new("b.txt"), diff_base.clone())],
&[("b.txt".into(), staged_text.clone())],
);

// Create the buffer
let buffer_local_b = project_local
.update(cx_a, |p, cx| p.open_buffer((worktree_id, "sub/b.txt"), cx))
.await
.unwrap();
let change_set_local_b = project_local
let local_unstaged_changes_b = project_local
.update(cx_a, |p, cx| {
p.open_unstaged_changes(buffer_local_b.clone(), cx)
})
Expand All @@ -2699,16 +2757,16 @@ async fn test_git_diff_base_change(

// Wait for it to catch up to the new diff
executor.run_until_parked();
change_set_local_b.read_with(cx_a, |change_set, cx| {
local_unstaged_changes_b.read_with(cx_a, |change_set, cx| {
let buffer = buffer_local_b.read(cx);
assert_eq!(
change_set.base_text_string().as_deref(),
Some(diff_base.as_str())
Some(staged_text.as_str())
);
git::diff::assert_hunks(
change_set.diff_to_buffer.hunks_in_row_range(0..4, buffer),
buffer,
&diff_base,
&change_set.base_text_string().unwrap(),
&[(1..2, "", "two\n")],
);
});
Expand All @@ -2718,60 +2776,60 @@ async fn test_git_diff_base_change(
.update(cx_b, |p, cx| p.open_buffer((worktree_id, "sub/b.txt"), cx))
.await
.unwrap();
let change_set_remote_b = project_remote
let remote_unstaged_changes_b = project_remote
.update(cx_b, |p, cx| {
p.open_unstaged_changes(buffer_remote_b.clone(), cx)
})
.await
.unwrap();

executor.run_until_parked();
change_set_remote_b.read_with(cx_b, |change_set, cx| {
remote_unstaged_changes_b.read_with(cx_b, |change_set, cx| {
let buffer = buffer_remote_b.read(cx);
assert_eq!(
change_set.base_text_string().as_deref(),
Some(diff_base.as_str())
Some(staged_text.as_str())
);
git::diff::assert_hunks(
change_set.diff_to_buffer.hunks_in_row_range(0..4, buffer),
buffer,
&diff_base,
&staged_text,
&[(1..2, "", "two\n")],
);
});

// Update the staged text
// Updatet the staged text
client_a.fs().set_index_for_repo(
Path::new("/dir/sub/.git"),
&[(Path::new("b.txt"), new_diff_base.clone())],
&[("b.txt".into(), new_staged_text.clone())],
);

// Wait for buffer_local_b to receive it
executor.run_until_parked();
change_set_local_b.read_with(cx_a, |change_set, cx| {
local_unstaged_changes_b.read_with(cx_a, |change_set, cx| {
let buffer = buffer_local_b.read(cx);
assert_eq!(
change_set.base_text_string().as_deref(),
Some(new_diff_base.as_str())
Some(new_staged_text.as_str())
);
git::diff::assert_hunks(
change_set.diff_to_buffer.hunks_in_row_range(0..4, buffer),
buffer,
&new_diff_base,
&new_staged_text,
&[(2..3, "", "three\n")],
);
});

change_set_remote_b.read_with(cx_b, |change_set, cx| {
remote_unstaged_changes_b.read_with(cx_b, |change_set, cx| {
let buffer = buffer_remote_b.read(cx);
assert_eq!(
change_set.base_text_string().as_deref(),
Some(new_diff_base.as_str())
Some(new_staged_text.as_str())
);
git::diff::assert_hunks(
change_set.diff_to_buffer.hunks_in_row_range(0..4, buffer),
buffer,
&new_diff_base,
&new_staged_text,
&[(2..3, "", "three\n")],
);
});
Expand Down
8 changes: 4 additions & 4 deletions crates/collab/src/tests/random_project_collaboration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -953,8 +953,8 @@ impl RandomizedTest for ProjectCollaborationTest {

let dot_git_dir = repo_path.join(".git");
let contents = contents
.iter()
.map(|(path, contents)| (path.as_path(), contents.clone()))
.into_iter()
.map(|(path, contents)| (path.into(), contents))
.collect::<Vec<_>>();
if client.fs().metadata(&dot_git_dir).await?.is_none() {
client.fs().create_dir(&dot_git_dir).await?;
Expand Down Expand Up @@ -1339,7 +1339,7 @@ impl RandomizedTest for ProjectCollaborationTest {
project
.buffer_store()
.read(cx)
.get_unstaged_changes(host_buffer.read(cx).remote_id())
.get_unstaged_changes(host_buffer.read(cx).remote_id(), cx)
.unwrap()
.read(cx)
.base_text_string()
Expand All @@ -1348,7 +1348,7 @@ impl RandomizedTest for ProjectCollaborationTest {
project
.buffer_store()
.read(cx)
.get_unstaged_changes(guest_buffer.read(cx).remote_id())
.get_unstaged_changes(guest_buffer.read(cx).remote_id(), cx)
.unwrap()
.read(cx)
.base_text_string()
Expand Down
2 changes: 1 addition & 1 deletion crates/diagnostics/src/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ impl DiagnosticIndicator {
(buffer, cursor_position)
});
let new_diagnostic = buffer
.diagnostics_in_range::<_, usize>(cursor_position..cursor_position)
.diagnostics_in_range::<usize>(cursor_position..cursor_position)
.filter(|entry| !entry.range.is_empty())
.min_by_key(|entry| (entry.diagnostic.severity, entry.range.len()))
.map(|entry| entry.diagnostic);
Expand Down
1 change: 1 addition & 0 deletions crates/editor/src/display_map/wrap_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,7 @@ impl<'a> Iterator for WrapRows<'a> {

Some(if soft_wrapped {
RowInfo {
buffer_id: None,
buffer_row: None,
multibuffer_row: None,
diff_status,
Expand Down
Loading
Loading