collab: Fix project sharing between Windows and Unix (#23680)
Closes #14258 Windows user(host) sharing a project to a guest(using macOS), and host follows guest: https://github.com/user-attachments/assets/ba306b6b-23f7-48b1-8ba8-fdc5992d8f00 macOS user(host) sharing a project to a guest(using Windows), and host follows guest: https://github.com/user-attachments/assets/c5ee5e78-870d-49e5-907d-8565977a01ae macOS user edits files in a windows project through collab: https://github.com/user-attachments/assets/581057cf-e7df-4e56-a0ce-ced74339906a Release Notes: - N/A
This commit is contained in:
parent
929c5e76b4
commit
c1f162abc6
14 changed files with 226 additions and 117 deletions
|
@ -39,7 +39,7 @@ use postage::{
|
|||
watch,
|
||||
};
|
||||
use rpc::{
|
||||
proto::{self, split_worktree_update},
|
||||
proto::{self, split_worktree_update, FromProto, ToProto},
|
||||
AnyProtoClient,
|
||||
};
|
||||
pub use settings::WorktreeId;
|
||||
|
@ -283,13 +283,13 @@ impl RepositoryEntry {
|
|||
current_new_entry = new_statuses.next();
|
||||
}
|
||||
Ordering::Greater => {
|
||||
removed_statuses.push(old_entry.repo_path.to_proto());
|
||||
removed_statuses.push(old_entry.repo_path.as_ref().to_proto());
|
||||
current_old_entry = old_statuses.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
(None, Some(old_entry)) => {
|
||||
removed_statuses.push(old_entry.repo_path.to_proto());
|
||||
removed_statuses.push(old_entry.repo_path.as_ref().to_proto());
|
||||
current_old_entry = old_statuses.next();
|
||||
}
|
||||
(Some(new_entry), None) => {
|
||||
|
@ -308,7 +308,7 @@ impl RepositoryEntry {
|
|||
current_merge_conflicts: self
|
||||
.current_merge_conflicts
|
||||
.iter()
|
||||
.map(RepoPath::to_proto)
|
||||
.map(|path| path.as_ref().to_proto())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
@ -700,7 +700,7 @@ impl Worktree {
|
|||
let snapshot = Snapshot::new(
|
||||
worktree.id,
|
||||
worktree.root_name,
|
||||
Arc::from(PathBuf::from(worktree.abs_path)),
|
||||
Arc::<Path>::from_proto(worktree.abs_path),
|
||||
);
|
||||
|
||||
let background_snapshot = Arc::new(Mutex::new((snapshot.clone(), Vec::new())));
|
||||
|
@ -849,7 +849,7 @@ impl Worktree {
|
|||
id: self.id().to_proto(),
|
||||
root_name: self.root_name().to_string(),
|
||||
visible: self.is_visible(),
|
||||
abs_path: self.abs_path().as_os_str().to_string_lossy().into(),
|
||||
abs_path: self.abs_path().to_proto(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1007,7 +1007,7 @@ impl Worktree {
|
|||
is_directory: bool,
|
||||
cx: &Context<Worktree>,
|
||||
) -> Task<Result<CreatedEntry>> {
|
||||
let path = path.into();
|
||||
let path: Arc<Path> = path.into();
|
||||
let worktree_id = self.id();
|
||||
match self {
|
||||
Worktree::Local(this) => this.create_entry(path, is_directory, cx),
|
||||
|
@ -1016,7 +1016,7 @@ impl Worktree {
|
|||
let request = this.client.request(proto::CreateProjectEntry {
|
||||
worktree_id: worktree_id.to_proto(),
|
||||
project_id,
|
||||
path: path.to_string_lossy().into(),
|
||||
path: path.as_ref().to_proto(),
|
||||
is_directory,
|
||||
});
|
||||
cx.spawn(move |this, mut cx| async move {
|
||||
|
@ -1101,21 +1101,19 @@ impl Worktree {
|
|||
new_path: impl Into<Arc<Path>>,
|
||||
cx: &Context<Self>,
|
||||
) -> Task<Result<Option<Entry>>> {
|
||||
let new_path = new_path.into();
|
||||
let new_path: Arc<Path> = new_path.into();
|
||||
match self {
|
||||
Worktree::Local(this) => {
|
||||
this.copy_entry(entry_id, relative_worktree_source_path, new_path, cx)
|
||||
}
|
||||
Worktree::Remote(this) => {
|
||||
let relative_worktree_source_path =
|
||||
relative_worktree_source_path.map(|relative_worktree_source_path| {
|
||||
relative_worktree_source_path.to_string_lossy().into()
|
||||
});
|
||||
let relative_worktree_source_path = relative_worktree_source_path
|
||||
.map(|relative_worktree_source_path| relative_worktree_source_path.to_proto());
|
||||
let response = this.client.request(proto::CopyProjectEntry {
|
||||
project_id: this.project_id,
|
||||
entry_id: entry_id.to_proto(),
|
||||
relative_worktree_source_path,
|
||||
new_path: new_path.to_string_lossy().into(),
|
||||
new_path: new_path.to_proto(),
|
||||
});
|
||||
cx.spawn(move |this, mut cx| async move {
|
||||
let response = response.await?;
|
||||
|
@ -1214,7 +1212,11 @@ impl Worktree {
|
|||
let (scan_id, entry) = this.update(&mut cx, |this, cx| {
|
||||
(
|
||||
this.scan_id(),
|
||||
this.create_entry(PathBuf::from(request.path), request.is_directory, cx),
|
||||
this.create_entry(
|
||||
Arc::<Path>::from_proto(request.path),
|
||||
request.is_directory,
|
||||
cx,
|
||||
),
|
||||
)
|
||||
})?;
|
||||
Ok(proto::ProjectEntryResponse {
|
||||
|
@ -1288,7 +1290,7 @@ impl Worktree {
|
|||
this.scan_id(),
|
||||
this.rename_entry(
|
||||
ProjectEntryId::from_proto(request.entry_id),
|
||||
PathBuf::from(request.new_path),
|
||||
Arc::<Path>::from_proto(request.new_path),
|
||||
cx,
|
||||
),
|
||||
)
|
||||
|
@ -1308,14 +1310,15 @@ impl Worktree {
|
|||
mut cx: AsyncApp,
|
||||
) -> Result<proto::ProjectEntryResponse> {
|
||||
let (scan_id, task) = this.update(&mut cx, |this, cx| {
|
||||
let relative_worktree_source_path =
|
||||
request.relative_worktree_source_path.map(PathBuf::from);
|
||||
let relative_worktree_source_path = request
|
||||
.relative_worktree_source_path
|
||||
.map(PathBuf::from_proto);
|
||||
(
|
||||
this.scan_id(),
|
||||
this.copy_entry(
|
||||
ProjectEntryId::from_proto(request.entry_id),
|
||||
relative_worktree_source_path,
|
||||
PathBuf::from(request.new_path),
|
||||
PathBuf::from_proto(request.new_path),
|
||||
cx,
|
||||
),
|
||||
)
|
||||
|
@ -2368,11 +2371,11 @@ impl RemoteWorktree {
|
|||
new_path: impl Into<Arc<Path>>,
|
||||
cx: &Context<Worktree>,
|
||||
) -> Task<Result<CreatedEntry>> {
|
||||
let new_path = new_path.into();
|
||||
let new_path: Arc<Path> = new_path.into();
|
||||
let response = self.client.request(proto::RenameProjectEntry {
|
||||
project_id: self.project_id,
|
||||
entry_id: entry_id.to_proto(),
|
||||
new_path: new_path.to_string_lossy().into(),
|
||||
new_path: new_path.as_ref().to_proto(),
|
||||
});
|
||||
cx.spawn(move |this, mut cx| async move {
|
||||
let response = response.await?;
|
||||
|
@ -2454,7 +2457,7 @@ impl Snapshot {
|
|||
proto::UpdateWorktree {
|
||||
project_id,
|
||||
worktree_id,
|
||||
abs_path: self.abs_path().to_string_lossy().into(),
|
||||
abs_path: self.abs_path().to_proto(),
|
||||
root_name: self.root_name().to_string(),
|
||||
updated_entries,
|
||||
removed_entries: Vec::new(),
|
||||
|
@ -2555,7 +2558,7 @@ impl Snapshot {
|
|||
update.removed_entries.len()
|
||||
);
|
||||
self.update_abs_path(
|
||||
SanitizedPath::from(PathBuf::from(update.abs_path)),
|
||||
SanitizedPath::from(PathBuf::from_proto(update.abs_path)),
|
||||
update.root_name,
|
||||
);
|
||||
|
||||
|
@ -2617,7 +2620,7 @@ impl Snapshot {
|
|||
let edits = repository
|
||||
.removed_statuses
|
||||
.into_iter()
|
||||
.map(|path| Edit::Remove(PathKey(Path::new(&path).into())))
|
||||
.map(|path| Edit::Remove(PathKey(FromProto::from_proto(path))))
|
||||
.chain(repository.updated_statuses.into_iter().filter_map(
|
||||
|updated_status| {
|
||||
Some(Edit::Insert(updated_status.try_into().log_err()?))
|
||||
|
@ -2952,7 +2955,7 @@ impl LocalSnapshot {
|
|||
proto::UpdateWorktree {
|
||||
project_id,
|
||||
worktree_id,
|
||||
abs_path: self.abs_path().to_string_lossy().into(),
|
||||
abs_path: self.abs_path().to_proto(),
|
||||
root_name: self.root_name().to_string(),
|
||||
updated_entries,
|
||||
removed_entries,
|
||||
|
@ -3635,7 +3638,7 @@ impl language::File for File {
|
|||
rpc::proto::File {
|
||||
worktree_id: self.worktree.read(cx).id().to_proto(),
|
||||
entry_id: self.entry_id.map(|id| id.to_proto()),
|
||||
path: self.path.to_string_lossy().into(),
|
||||
path: self.path.as_ref().to_proto(),
|
||||
mtime: self.disk_state.mtime().map(|time| time.into()),
|
||||
is_deleted: self.disk_state == DiskState::Deleted,
|
||||
}
|
||||
|
@ -3716,7 +3719,7 @@ impl File {
|
|||
|
||||
Ok(Self {
|
||||
worktree,
|
||||
path: Path::new(&proto.path).into(),
|
||||
path: Arc::<Path>::from_proto(proto.path),
|
||||
disk_state,
|
||||
entry_id: proto.entry_id.map(ProjectEntryId::from_proto),
|
||||
is_local: false,
|
||||
|
@ -3835,8 +3838,9 @@ impl StatusEntry {
|
|||
index_status
|
||||
}),
|
||||
};
|
||||
|
||||
proto::StatusEntry {
|
||||
repo_path: self.repo_path.to_proto(),
|
||||
repo_path: self.repo_path.as_ref().to_proto(),
|
||||
simple_status,
|
||||
status: Some(status_to_proto(self.status)),
|
||||
}
|
||||
|
@ -3847,7 +3851,7 @@ impl TryFrom<proto::StatusEntry> for StatusEntry {
|
|||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: proto::StatusEntry) -> Result<Self, Self::Error> {
|
||||
let repo_path = RepoPath(Path::new(&value.repo_path).into());
|
||||
let repo_path = RepoPath(Arc::<Path>::from_proto(value.repo_path));
|
||||
let status = status_from_proto(value.simple_status, value.status)?;
|
||||
Ok(Self { repo_path, status })
|
||||
}
|
||||
|
@ -6231,7 +6235,7 @@ impl<'a> From<&'a Entry> for proto::Entry {
|
|||
Self {
|
||||
id: entry.id.to_proto(),
|
||||
is_dir: entry.is_dir(),
|
||||
path: entry.path.to_string_lossy().into(),
|
||||
path: entry.path.as_ref().to_proto(),
|
||||
inode: entry.inode,
|
||||
mtime: entry.mtime.map(|time| time.into()),
|
||||
is_ignored: entry.is_ignored,
|
||||
|
@ -6241,7 +6245,7 @@ impl<'a> From<&'a Entry> for proto::Entry {
|
|||
canonical_path: entry
|
||||
.canonical_path
|
||||
.as_ref()
|
||||
.map(|path| path.to_string_lossy().to_string()),
|
||||
.map(|path| path.as_ref().to_proto()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6257,20 +6261,22 @@ impl<'a> TryFrom<(&'a CharBag, &PathMatcher, proto::Entry)> for Entry {
|
|||
} else {
|
||||
EntryKind::File
|
||||
};
|
||||
let path: Arc<Path> = PathBuf::from(entry.path).into();
|
||||
|
||||
let path = Arc::<Path>::from_proto(entry.path);
|
||||
let char_bag = char_bag_for_path(*root_char_bag, &path);
|
||||
let is_always_included = always_included.is_match(path.as_ref());
|
||||
Ok(Entry {
|
||||
id: ProjectEntryId::from_proto(entry.id),
|
||||
kind,
|
||||
path: path.clone(),
|
||||
path,
|
||||
inode: entry.inode,
|
||||
mtime: entry.mtime.map(|time| time.into()),
|
||||
size: entry.size.unwrap_or(0),
|
||||
canonical_path: entry
|
||||
.canonical_path
|
||||
.map(|path_string| Box::from(Path::new(&path_string))),
|
||||
.map(|path_string| Box::from(PathBuf::from_proto(path_string))),
|
||||
is_ignored: entry.is_ignored,
|
||||
is_always_included: always_included.is_match(path.as_ref()),
|
||||
is_always_included,
|
||||
is_external: entry.is_external,
|
||||
is_private: false,
|
||||
char_bag,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue