diff --git a/crates/file_finder/src/open_path_prompt.rs b/crates/file_finder/src/open_path_prompt.rs index c28eeb470d..71203874f6 100644 --- a/crates/file_finder/src/open_path_prompt.rs +++ b/crates/file_finder/src/open_path_prompt.rs @@ -93,6 +93,8 @@ impl PickerDelegate for OpenPathDelegate { cx.notify(); } + // todo(windows) + // Is this method woring correctly on Windows? This method uses `/` for path separator. fn update_matches( &mut self, query: String, diff --git a/crates/git/src/repository.rs b/crates/git/src/repository.rs index 39f244f125..e1bf864e50 100644 --- a/crates/git/src/repository.rs +++ b/crates/git/src/repository.rs @@ -571,10 +571,6 @@ impl RepoPath { RepoPath(path.into()) } - - pub fn to_proto(&self) -> String { - self.0.to_string_lossy().to_string() - } } impl std::fmt::Display for RepoPath { diff --git a/crates/project/src/buffer_store.rs b/crates/project/src/buffer_store.rs index eed41f1f6b..7eda617c88 100644 --- a/crates/project/src/buffer_store.rs +++ b/crates/project/src/buffer_store.rs @@ -23,7 +23,10 @@ use language::{ }, Buffer, BufferEvent, Capability, DiskState, File as _, Language, LanguageRegistry, Operation, }; -use rpc::{proto, AnyProtoClient, ErrorExt as _, TypedEnvelope}; +use rpc::{ + proto::{self, ToProto}, + AnyProtoClient, ErrorExt as _, TypedEnvelope, +}; use serde::Deserialize; use smol::channel::Receiver; use std::{ @@ -580,13 +583,12 @@ impl RemoteBufferStore { let worktree_id = worktree.read(cx).id().to_proto(); let project_id = self.project_id; let client = self.upstream_client.clone(); - let path_string = path.clone().to_string_lossy().to_string(); cx.spawn(move |this, mut cx| async move { let response = client .request(proto::OpenBufferByPath { project_id, worktree_id, - path: path_string, + path: path.to_proto(), }) .await?; let buffer_id = BufferId::new(response.buffer_id)?; diff --git a/crates/project/src/git.rs b/crates/project/src/git.rs index debc89b321..6385025ff5 100644 --- a/crates/project/src/git.rs +++ b/crates/project/src/git.rs @@ -13,6 +13,7 @@ use gpui::{ App, AppContext, Context, Entity, EventEmitter, SharedString, Subscription, Task, WeakEntity, }; use language::{Buffer, LanguageRegistry}; +use rpc::proto::ToProto; use rpc::{proto, AnyProtoClient}; use settings::WorktreeId; use std::path::{Path, PathBuf}; @@ -222,7 +223,7 @@ impl GitState { work_directory_id: work_directory_id.to_proto(), paths: paths .into_iter() - .map(|repo_path| repo_path.to_proto()) + .map(|repo_path| repo_path.as_ref().to_proto()) .collect(), }) .await @@ -247,7 +248,7 @@ impl GitState { work_directory_id: work_directory_id.to_proto(), paths: paths .into_iter() - .map(|repo_path| repo_path.to_proto()) + .map(|repo_path| repo_path.as_ref().to_proto()) .collect(), }) .await diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs index 7fbb781f0f..b831b0e681 100644 --- a/crates/project/src/lsp_store.rs +++ b/crates/project/src/lsp_store.rs @@ -55,7 +55,10 @@ use parking_lot::Mutex; use postage::watch; use rand::prelude::*; -use rpc::AnyProtoClient; +use rpc::{ + proto::{FromProto, ToProto}, + AnyProtoClient, +}; use serde::Serialize; use settings::{Settings, SettingsLocation, SettingsStore}; use sha2::{Digest, Sha256}; @@ -5360,7 +5363,7 @@ impl LspStore { project_id: *project_id, worktree_id: worktree_id.to_proto(), summary: Some(proto::DiagnosticSummary { - path: worktree_path.to_string_lossy().to_string(), + path: worktree_path.to_proto(), language_server_id: server_id.0 as u64, error_count: new_summary.error_count as u32, warning_count: new_summary.warning_count as u32, @@ -5848,10 +5851,8 @@ impl LspStore { .ok_or_else(|| anyhow!("worktree not found"))?; let (old_abs_path, new_abs_path) = { let root_path = worktree.update(&mut cx, |this, _| this.abs_path())?; - ( - root_path.join(&old_path), - root_path.join(&envelope.payload.new_path), - ) + let new_path = PathBuf::from_proto(envelope.payload.new_path.clone()); + (root_path.join(&old_path), root_path.join(&new_path)) }; Self::will_rename_entry( @@ -5881,7 +5882,7 @@ impl LspStore { if let Some(message) = envelope.payload.summary { let project_path = ProjectPath { worktree_id, - path: Path::new(&message.path).into(), + path: Arc::::from_proto(message.path), }; let path = project_path.path.clone(); let server_id = LanguageServerId(message.language_server_id as usize); @@ -5915,7 +5916,7 @@ impl LspStore { project_id: *project_id, worktree_id: worktree_id.to_proto(), summary: Some(proto::DiagnosticSummary { - path: project_path.path.to_string_lossy().to_string(), + path: project_path.path.as_ref().to_proto(), language_server_id: server_id.0 as u64, error_count: summary.error_count as u32, warning_count: summary.warning_count as u32, @@ -7114,7 +7115,7 @@ impl LspStore { project_id, worktree_id: worktree_id.to_proto(), summary: Some(proto::DiagnosticSummary { - path: path.to_string_lossy().to_string(), + path: path.as_ref().to_proto(), language_server_id: server_id.0 as u64, error_count: 0, warning_count: 0, @@ -7768,7 +7769,7 @@ impl LspStore { language_server_name: symbol.language_server_name.0.to_string(), source_worktree_id: symbol.source_worktree_id.to_proto(), worktree_id: symbol.path.worktree_id.to_proto(), - path: symbol.path.path.to_string_lossy().to_string(), + path: symbol.path.path.as_ref().to_proto(), name: symbol.name.clone(), kind: unsafe { mem::transmute::(symbol.kind) }, start: Some(proto::PointUtf16 { @@ -7789,7 +7790,7 @@ impl LspStore { let kind = unsafe { mem::transmute::(serialized_symbol.kind) }; let path = ProjectPath { worktree_id, - path: PathBuf::from(serialized_symbol.path).into(), + path: Arc::::from_proto(serialized_symbol.path), }; let start = serialized_symbol @@ -8263,7 +8264,7 @@ impl DiagnosticSummary { path: &Path, ) -> proto::DiagnosticSummary { proto::DiagnosticSummary { - path: path.to_string_lossy().to_string(), + path: path.to_proto(), language_server_id: language_server_id.0 as u64, error_count: self.error_count as u32, warning_count: self.warning_count as u32, diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index da2eeb8578..7d0c0f6796 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -73,7 +73,7 @@ pub use prettier_store::PrettierStore; use project_settings::{ProjectSettings, SettingsObserver, SettingsObserverEvent}; use remote::{SshConnectionOptions, SshRemoteClient}; use rpc::{ - proto::{LanguageServerPromptResponse, SSH_PROJECT_ID}, + proto::{FromProto, LanguageServerPromptResponse, ToProto, SSH_PROJECT_ID}, AnyProtoClient, ErrorCode, }; use search::{SearchInputKind, SearchQuery, SearchResult}; @@ -297,14 +297,14 @@ impl ProjectPath { pub fn from_proto(p: proto::ProjectPath) -> Self { Self { worktree_id: WorktreeId::from_proto(p.worktree_id), - path: Arc::from(PathBuf::from(p.path)), + path: Arc::::from_proto(p.path), } } pub fn to_proto(&self) -> proto::ProjectPath { proto::ProjectPath { worktree_id: self.worktree_id.to_proto(), - path: self.path.to_string_lossy().to_string(), + path: self.path.as_ref().to_proto(), } } @@ -3360,18 +3360,19 @@ impl Project { }) }) } else if let Some(ssh_client) = self.ssh_client.as_ref() { + let request_path = Path::new(path); let request = ssh_client .read(cx) .proto_client() .request(proto::GetPathMetadata { project_id: SSH_PROJECT_ID, - path: path.to_string(), + path: request_path.to_proto(), }); cx.background_executor().spawn(async move { let response = request.await.log_err()?; if response.exists { Some(ResolvedPath::AbsPath { - path: PathBuf::from(response.path), + path: PathBuf::from_proto(response.path), is_dir: response.is_dir, }) } else { @@ -3441,9 +3442,10 @@ impl Project { if self.is_local() { DirectoryLister::Local(self.fs.clone()).list_directory(query, cx) } else if let Some(session) = self.ssh_client.as_ref() { + let path_buf = PathBuf::from(query); let request = proto::ListRemoteDirectory { dev_server_id: SSH_PROJECT_ID, - path: query, + path: path_buf.to_proto(), }; let response = session.read(cx).proto_client().request(request); @@ -3994,7 +3996,7 @@ impl Project { this.open_buffer( ProjectPath { worktree_id, - path: PathBuf::from(envelope.payload.path).into(), + path: Arc::::from_proto(envelope.payload.path), }, cx, ) diff --git a/crates/project/src/project_settings.rs b/crates/project/src/project_settings.rs index 642418e3f1..360d8a9529 100644 --- a/crates/project/src/project_settings.rs +++ b/crates/project/src/project_settings.rs @@ -7,18 +7,17 @@ use paths::{ local_settings_file_relative_path, local_tasks_file_relative_path, local_vscode_tasks_file_relative_path, EDITORCONFIG_NAME, }; -use rpc::{proto, AnyProtoClient, TypedEnvelope}; +use rpc::{ + proto::{self, FromProto, ToProto}, + AnyProtoClient, TypedEnvelope, +}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use settings::{ parse_json_with_comments, InvalidSettingsError, LocalSettingsKind, Settings, SettingsLocation, SettingsSources, SettingsStore, }; -use std::{ - path::{Path, PathBuf}, - sync::Arc, - time::Duration, -}; +use std::{path::Path, sync::Arc, time::Duration}; use task::{TaskTemplates, VsCodeTaskFile}; use util::ResultExt; use worktree::{PathChange, UpdatedEntriesSet, Worktree, WorktreeId}; @@ -292,7 +291,7 @@ impl SettingsObserver { .send(proto::UpdateWorktreeSettings { project_id, worktree_id, - path: path.to_string_lossy().into(), + path: path.to_proto(), content: Some(content), kind: Some( local_settings_kind_to_proto(LocalSettingsKind::Settings).into(), @@ -305,7 +304,7 @@ impl SettingsObserver { .send(proto::UpdateWorktreeSettings { project_id, worktree_id, - path: path.to_string_lossy().into(), + path: path.to_proto(), content: Some(content), kind: Some( local_settings_kind_to_proto(LocalSettingsKind::Editorconfig).into(), @@ -343,7 +342,7 @@ impl SettingsObserver { this.update_settings( worktree, [( - PathBuf::from(&envelope.payload.path).into(), + Arc::::from_proto(envelope.payload.path.clone()), local_settings_kind_from_proto(kind), envelope.payload.content, )], @@ -551,7 +550,7 @@ impl SettingsObserver { .send(proto::UpdateWorktreeSettings { project_id: self.project_id, worktree_id: remote_worktree_id.to_proto(), - path: directory.to_string_lossy().into_owned(), + path: directory.to_proto(), content: file_content, kind: Some(local_settings_kind_to_proto(kind).into()), }) diff --git a/crates/project/src/toolchain_store.rs b/crates/project/src/toolchain_store.rs index 4fc1134272..d4af70e41f 100644 --- a/crates/project/src/toolchain_store.rs +++ b/crates/project/src/toolchain_store.rs @@ -1,4 +1,4 @@ -use std::{str::FromStr, sync::Arc}; +use std::{path::PathBuf, str::FromStr, sync::Arc}; use anyhow::{bail, Result}; @@ -8,7 +8,10 @@ use gpui::{ App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, Subscription, Task, WeakEntity, }; use language::{LanguageName, LanguageRegistry, LanguageToolchainStore, Toolchain, ToolchainList}; -use rpc::{proto, AnyProtoClient, TypedEnvelope}; +use rpc::{ + proto::{self, FromProto, ToProto}, + AnyProtoClient, TypedEnvelope, +}; use settings::WorktreeId; use util::ResultExt as _; @@ -120,7 +123,9 @@ impl ToolchainStore { }; let toolchain = Toolchain { name: toolchain.name.into(), - path: toolchain.path.into(), + // todo(windows) + // Do we need to convert path to native string? + path: PathBuf::from(toolchain.path).to_proto().into(), as_json: serde_json::Value::from_str(&toolchain.raw_json)?, language_name, }; @@ -144,10 +149,13 @@ impl ToolchainStore { .await; Ok(proto::ActiveToolchainResponse { - toolchain: toolchain.map(|toolchain| proto::Toolchain { - name: toolchain.name.into(), - path: toolchain.path.into(), - raw_json: toolchain.as_json.to_string(), + toolchain: toolchain.map(|toolchain| { + let path = PathBuf::from(toolchain.path.to_string()); + proto::Toolchain { + name: toolchain.name.into(), + path: path.to_proto(), + raw_json: toolchain.as_json.to_string(), + } }), }) } @@ -183,10 +191,13 @@ impl ToolchainStore { toolchains .toolchains .into_iter() - .map(|toolchain| proto::Toolchain { - name: toolchain.name.to_string(), - path: toolchain.path.to_string(), - raw_json: toolchain.as_json.to_string(), + .map(|toolchain| { + let path = PathBuf::from(toolchain.path.to_string()); + proto::Toolchain { + name: toolchain.name.to_string(), + path: path.to_proto(), + raw_json: toolchain.as_json.to_string(), + } }) .collect::>() } else { @@ -354,6 +365,7 @@ impl RemoteToolchainStore { let project_id = self.project_id; let client = self.client.clone(); cx.spawn(move |_| async move { + let path = PathBuf::from(toolchain.path.to_string()); let _ = client .request(proto::ActivateToolchain { project_id, @@ -361,7 +373,7 @@ impl RemoteToolchainStore { language_name: toolchain.language_name.into(), toolchain: Some(proto::Toolchain { name: toolchain.name.into(), - path: toolchain.path.into(), + path: path.to_proto(), raw_json: toolchain.as_json.to_string(), }), }) @@ -398,7 +410,12 @@ impl RemoteToolchainStore { Some(Toolchain { language_name: language_name.clone(), name: toolchain.name.into(), - path: toolchain.path.into(), + // todo(windows) + // Do we need to convert path to native string? + path: PathBuf::from_proto(toolchain.path) + .to_string_lossy() + .to_string() + .into(), as_json: serde_json::Value::from_str(&toolchain.raw_json).ok()?, }) }) @@ -439,7 +456,12 @@ impl RemoteToolchainStore { Some(Toolchain { language_name: language_name.clone(), name: toolchain.name.into(), - path: toolchain.path.into(), + // todo(windows) + // Do we need to convert path to native string? + path: PathBuf::from_proto(toolchain.path) + .to_string_lossy() + .to_string() + .into(), as_json: serde_json::Value::from_str(&toolchain.raw_json).ok()?, }) }) diff --git a/crates/project/src/worktree_store.rs b/crates/project/src/worktree_store.rs index 95d88384fe..6461d97723 100644 --- a/crates/project/src/worktree_store.rs +++ b/crates/project/src/worktree_store.rs @@ -15,7 +15,7 @@ use futures::{ use gpui::{App, AsyncApp, Context, Entity, EntityId, EventEmitter, Task, WeakEntity}; use postage::oneshot; use rpc::{ - proto::{self, SSH_PROJECT_ID}, + proto::{self, FromProto, ToProto, SSH_PROJECT_ID}, AnyProtoClient, ErrorExt, TypedEnvelope, }; use smol::{ @@ -268,10 +268,11 @@ impl WorktreeStore { cx.spawn(|this, mut cx| async move { let this = this.upgrade().context("Dropped worktree store")?; + let path = Path::new(abs_path.as_str()); let response = client .request(proto::AddWorktree { project_id: SSH_PROJECT_ID, - path: abs_path.clone(), + path: path.to_proto(), visible, }) .await?; @@ -282,10 +283,11 @@ impl WorktreeStore { return Ok(existing_worktree); } - let root_name = PathBuf::from(&response.canonicalized_path) + let root_path_buf = PathBuf::from_proto(response.canonicalized_path.clone()); + let root_name = root_path_buf .file_name() .map(|n| n.to_string_lossy().to_string()) - .unwrap_or(response.canonicalized_path.to_string()); + .unwrap_or(root_path_buf.to_string_lossy().to_string()); let worktree = cx.update(|cx| { Worktree::remote( @@ -596,7 +598,7 @@ impl WorktreeStore { id: worktree.id().to_proto(), root_name: worktree.root_name().into(), visible: worktree.is_visible(), - abs_path: worktree.abs_path().to_string_lossy().into(), + abs_path: worktree.abs_path().to_proto(), } }) .collect() @@ -923,7 +925,7 @@ impl WorktreeStore { project_id: remote_worktree.project_id(), repository: Some(proto::ProjectPath { worktree_id: project_path.worktree_id.to_proto(), - path: project_path.path.to_string_lossy().to_string(), // Root path + path: project_path.path.to_proto(), // Root path }), }); @@ -994,7 +996,7 @@ impl WorktreeStore { project_id: remote_worktree.project_id(), repository: Some(proto::ProjectPath { worktree_id: repository.worktree_id.to_proto(), - path: repository.path.to_string_lossy().to_string(), // Root path + path: repository.path.to_proto(), // Root path }), branch_name: new_branch, }); @@ -1116,7 +1118,7 @@ impl WorktreeStore { .context("Invalid GitBranches call")?; let project_path = ProjectPath { worktree_id: WorktreeId::from_proto(project_path.worktree_id), - path: Path::new(&project_path.path).into(), + path: Arc::::from_proto(project_path.path), }; let branches = this @@ -1147,7 +1149,7 @@ impl WorktreeStore { .context("Invalid GitBranches call")?; let project_path = ProjectPath { worktree_id: WorktreeId::from_proto(project_path.worktree_id), - path: Path::new(&project_path.path).into(), + path: Arc::::from_proto(project_path.path), }; let new_branch = update_branch.payload.branch_name; diff --git a/crates/proto/proto/zed.proto b/crates/proto/proto/zed.proto index e94bd1479d..7d33dd1a3e 100644 --- a/crates/proto/proto/zed.proto +++ b/crates/proto/proto/zed.proto @@ -2489,8 +2489,8 @@ message RefreshLlmToken {} // Remote FS message AddWorktree { - uint64 project_id = 2; string path = 1; + uint64 project_id = 2; bool visible = 3; } @@ -2625,6 +2625,7 @@ message UpdateGitBranch { string branch_name = 2; ProjectPath repository = 3; } + message GetPanicFiles { } diff --git a/crates/proto/src/proto.rs b/crates/proto/src/proto.rs index 0ba9b6ef19..d45cc0936c 100644 --- a/crates/proto/src/proto.rs +++ b/crates/proto/src/proto.rs @@ -15,6 +15,8 @@ use std::{ cmp, fmt::{self, Debug}, iter, mem, + path::{Path, PathBuf}, + sync::Arc, time::{Duration, SystemTime, UNIX_EPOCH}, }; @@ -137,6 +139,62 @@ impl fmt::Display for PeerId { } } +pub trait FromProto { + fn from_proto(proto: String) -> Self; +} + +pub trait ToProto { + fn to_proto(self) -> String; +} + +impl FromProto for PathBuf { + #[cfg(target_os = "windows")] + fn from_proto(proto: String) -> Self { + proto.split("/").collect() + } + + #[cfg(not(target_os = "windows"))] + fn from_proto(proto: String) -> Self { + PathBuf::from(proto) + } +} + +impl FromProto for Arc { + fn from_proto(proto: String) -> Self { + PathBuf::from_proto(proto).into() + } +} + +impl ToProto for PathBuf { + #[cfg(target_os = "windows")] + fn to_proto(self) -> String { + self.components() + .map(|comp| comp.as_os_str().to_string_lossy().to_string()) + .collect::>() + .join("/") + } + + #[cfg(not(target_os = "windows"))] + fn to_proto(self) -> String { + self.to_string_lossy().to_string() + } +} + +impl ToProto for &Path { + #[cfg(target_os = "windows")] + fn to_proto(self) -> String { + self.components() + .map(|comp| comp.as_os_str().to_string_lossy().to_string()) + .collect::>() + .join("/") + } + + #[cfg(not(target_os = "windows"))] + fn to_proto(self) -> String { + self.to_string_lossy().to_string() + } +} + messages!( (AcceptTermsOfService, Foreground), (AcceptTermsOfServiceResponse, Foreground), @@ -757,4 +815,22 @@ mod tests { }; assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id); } + + #[test] + #[cfg(target_os = "windows")] + fn test_proto() { + fn generate_proto_path(path: PathBuf) -> PathBuf { + let proto = path.to_proto(); + PathBuf::from_proto(proto) + } + + let path = PathBuf::from("C:\\foo\\bar"); + assert_eq!(path, generate_proto_path(path.clone())); + + let path = PathBuf::from("C:/foo/bar/"); + assert_eq!(path, generate_proto_path(path.clone())); + + let path = PathBuf::from("C:/foo\\bar\\"); + assert_eq!(path, generate_proto_path(path.clone())); + } } diff --git a/crates/remote_server/src/headless_project.rs b/crates/remote_server/src/headless_project.rs index be22a52fa7..eb4122a321 100644 --- a/crates/remote_server/src/headless_project.rs +++ b/crates/remote_server/src/headless_project.rs @@ -1,3 +1,4 @@ +use ::proto::{FromProto, ToProto}; use anyhow::{anyhow, Context as _, Result}; use extension::ExtensionHostProxy; use extension_host::headless_host::HeadlessExtensionStore; @@ -325,10 +326,8 @@ impl HeadlessProject { mut cx: AsyncApp, ) -> Result { use client::ErrorCodeExt; - let path = shellexpand::tilde(&message.payload.path).to_string(); - let fs = this.read_with(&mut cx, |this, _| this.fs.clone())?; - let path = PathBuf::from(path); + let path = PathBuf::from_proto(shellexpand::tilde(&message.payload.path).to_string()); let canonicalized = match fs.canonicalize(&path).await { Ok(path) => path, @@ -363,7 +362,7 @@ impl HeadlessProject { let response = this.update(&mut cx, |_, cx| { worktree.update(cx, |worktree, _| proto::AddWorktreeResponse { worktree_id: worktree.id().to_proto(), - canonicalized_path: canonicalized.to_string_lossy().to_string(), + canonicalized_path: canonicalized.to_proto(), }) })?; @@ -418,7 +417,7 @@ impl HeadlessProject { buffer_store.open_buffer( ProjectPath { worktree_id, - path: PathBuf::from(message.payload.path).into(), + path: Arc::::from_proto(message.payload.path), }, cx, ) @@ -559,11 +558,11 @@ impl HeadlessProject { envelope: TypedEnvelope, cx: AsyncApp, ) -> Result { - let expanded = shellexpand::tilde(&envelope.payload.path).to_string(); let fs = cx.read_entity(&this, |this, _| this.fs.clone())?; + let expanded = PathBuf::from_proto(shellexpand::tilde(&envelope.payload.path).to_string()); let mut entries = Vec::new(); - let mut response = fs.read_dir(Path::new(&expanded)).await?; + let mut response = fs.read_dir(&expanded).await?; while let Some(path) = response.next().await { if let Some(file_name) = path?.file_name() { entries.push(file_name.to_string_lossy().to_string()); @@ -578,15 +577,15 @@ impl HeadlessProject { cx: AsyncApp, ) -> Result { let fs = cx.read_entity(&this, |this, _| this.fs.clone())?; - let expanded = shellexpand::tilde(&envelope.payload.path).to_string(); + let expanded = PathBuf::from_proto(shellexpand::tilde(&envelope.payload.path).to_string()); - let metadata = fs.metadata(&PathBuf::from(expanded.clone())).await?; + let metadata = fs.metadata(&expanded).await?; let is_dir = metadata.map(|metadata| metadata.is_dir).unwrap_or(false); Ok(proto::GetPathMetadataResponse { exists: metadata.is_some(), is_dir, - path: expanded, + path: expanded.to_proto(), }) } diff --git a/crates/remote_server/src/remote_editing_tests.rs b/crates/remote_server/src/remote_editing_tests.rs index 7552e950aa..1aed77e343 100644 --- a/crates/remote_server/src/remote_editing_tests.rs +++ b/crates/remote_server/src/remote_editing_tests.rs @@ -859,7 +859,7 @@ async fn test_remote_resolve_path_in_buffer( async fn test_remote_resolve_abs_path(cx: &mut TestAppContext, server_cx: &mut TestAppContext) { let fs = FakeFs::new(server_cx.executor()); fs.insert_tree( - "/code", + path!("/code"), json!({ "project1": { ".git": {}, @@ -876,7 +876,7 @@ async fn test_remote_resolve_abs_path(cx: &mut TestAppContext, server_cx: &mut T let path = project .update(cx, |project, cx| { - project.resolve_abs_path("/code/project1/README.md", cx) + project.resolve_abs_path(path!("/code/project1/README.md"), cx) }) .await .unwrap(); @@ -884,12 +884,12 @@ async fn test_remote_resolve_abs_path(cx: &mut TestAppContext, server_cx: &mut T assert!(path.is_file()); assert_eq!( path.abs_path().unwrap().to_string_lossy(), - "/code/project1/README.md" + path!("/code/project1/README.md") ); let path = project .update(cx, |project, cx| { - project.resolve_abs_path("/code/project1/src", cx) + project.resolve_abs_path(path!("/code/project1/src"), cx) }) .await .unwrap(); @@ -897,12 +897,12 @@ async fn test_remote_resolve_abs_path(cx: &mut TestAppContext, server_cx: &mut T assert!(path.is_dir()); assert_eq!( path.abs_path().unwrap().to_string_lossy(), - "/code/project1/src" + path!("/code/project1/src") ); let path = project .update(cx, |project, cx| { - project.resolve_abs_path("/code/project1/DOESNOTEXIST", cx) + project.resolve_abs_path(path!("/code/project1/DOESNOTEXIST"), cx) }) .await; assert!(path.is_none()); @@ -958,7 +958,7 @@ async fn test_adding_then_removing_then_adding_worktrees( ) { let fs = FakeFs::new(server_cx.executor()); fs.insert_tree( - "/code", + path!("/code"), json!({ "project1": { ".git": {}, @@ -977,14 +977,14 @@ async fn test_adding_then_removing_then_adding_worktrees( let (project, _headless) = init_test(&fs, cx, server_cx).await; let (_worktree, _) = project .update(cx, |project, cx| { - project.find_or_create_worktree("/code/project1", true, cx) + project.find_or_create_worktree(path!("/code/project1"), true, cx) }) .await .unwrap(); let (worktree_2, _) = project .update(cx, |project, cx| { - project.find_or_create_worktree("/code/project2", true, cx) + project.find_or_create_worktree(path!("/code/project2"), true, cx) }) .await .unwrap(); @@ -994,7 +994,7 @@ async fn test_adding_then_removing_then_adding_worktrees( let (worktree_2, _) = project .update(cx, |project, cx| { - project.find_or_create_worktree("/code/project2", true, cx) + project.find_or_create_worktree(path!("/code/project2"), true, cx) }) .await .unwrap(); diff --git a/crates/worktree/src/worktree.rs b/crates/worktree/src/worktree.rs index 08d55e0540..07f77283db 100644 --- a/crates/worktree/src/worktree.rs +++ b/crates/worktree/src/worktree.rs @@ -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::::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, ) -> Task> { - let path = path.into(); + let path: Arc = 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>, cx: &Context, ) -> Task>> { - let new_path = new_path.into(); + let new_path: Arc = 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::::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::::from_proto(request.new_path), cx, ), ) @@ -1308,14 +1310,15 @@ impl Worktree { mut cx: AsyncApp, ) -> Result { 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>, cx: &Context, ) -> Task> { - let new_path = new_path.into(); + let new_path: Arc = 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::::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 for StatusEntry { type Error = anyhow::Error; fn try_from(value: proto::StatusEntry) -> Result { - let repo_path = RepoPath(Path::new(&value.repo_path).into()); + let repo_path = RepoPath(Arc::::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 = PathBuf::from(entry.path).into(); + + let path = Arc::::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,