project_panel: Don't show trash dialog on remote connections (#40838)
In remote connections, we don't detect whether trashing is possible and generally shouldn't assume it is. This also fixes up some incomplete logic that was attempting to do that. Closes #39212 Release Notes: - No longer show trash option in remote projects
This commit is contained in:
@@ -1825,10 +1825,12 @@ impl Project {
|
||||
project
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn dap_store(&self) -> Entity<DapStore> {
|
||||
self.dap_store.clone()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn breakpoint_store(&self) -> Entity<BreakpointStore> {
|
||||
self.breakpoint_store.clone()
|
||||
}
|
||||
@@ -1842,50 +1844,62 @@ impl Project {
|
||||
Some((session, active_position.clone()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn lsp_store(&self) -> Entity<LspStore> {
|
||||
self.lsp_store.clone()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn worktree_store(&self) -> Entity<WorktreeStore> {
|
||||
self.worktree_store.clone()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn context_server_store(&self) -> Entity<ContextServerStore> {
|
||||
self.context_server_store.clone()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn buffer_for_id(&self, remote_id: BufferId, cx: &App) -> Option<Entity<Buffer>> {
|
||||
self.buffer_store.read(cx).get(remote_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn languages(&self) -> &Arc<LanguageRegistry> {
|
||||
&self.languages
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn client(&self) -> Arc<Client> {
|
||||
self.collab_client.clone()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn remote_client(&self) -> Option<Entity<RemoteClient>> {
|
||||
self.remote_client.clone()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn user_store(&self) -> Entity<UserStore> {
|
||||
self.user_store.clone()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn node_runtime(&self) -> Option<&NodeRuntime> {
|
||||
self.node.as_ref()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn opened_buffers(&self, cx: &App) -> Vec<Entity<Buffer>> {
|
||||
self.buffer_store.read(cx).buffers().collect()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn environment(&self) -> &Entity<ProjectEnvironment> {
|
||||
&self.environment
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn cli_environment(&self, cx: &App) -> Option<HashMap<String, String>> {
|
||||
self.environment.read(cx).get_cli_environment()
|
||||
}
|
||||
@@ -1916,6 +1930,7 @@ impl Project {
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn peek_environment_error<'a>(
|
||||
&'a self,
|
||||
cx: &'a App,
|
||||
@@ -1923,6 +1938,7 @@ impl Project {
|
||||
self.environment.read(cx).peek_environment_error()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn pop_environment_error(&mut self, cx: &mut Context<Self>) {
|
||||
self.environment.update(cx, |environment, _| {
|
||||
environment.pop_environment_error();
|
||||
@@ -1930,6 +1946,7 @@ impl Project {
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
#[inline]
|
||||
pub fn has_open_buffer(&self, path: impl Into<ProjectPath>, cx: &App) -> bool {
|
||||
self.buffer_store
|
||||
.read(cx)
|
||||
@@ -1937,10 +1954,12 @@ impl Project {
|
||||
.is_some()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn fs(&self) -> &Arc<dyn Fs> {
|
||||
&self.fs
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn remote_id(&self) -> Option<u64> {
|
||||
match self.client_state {
|
||||
ProjectClientState::Local => None,
|
||||
@@ -1949,6 +1968,7 @@ impl Project {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn supports_terminal(&self, _cx: &App) -> bool {
|
||||
if self.is_local() {
|
||||
return true;
|
||||
@@ -1960,18 +1980,21 @@ impl Project {
|
||||
false
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn remote_connection_state(&self, cx: &App) -> Option<remote::ConnectionState> {
|
||||
self.remote_client
|
||||
.as_ref()
|
||||
.map(|remote| remote.read(cx).connection_state())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn remote_connection_options(&self, cx: &App) -> Option<RemoteConnectionOptions> {
|
||||
self.remote_client
|
||||
.as_ref()
|
||||
.map(|remote| remote.read(cx).connection_options())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn replica_id(&self) -> ReplicaId {
|
||||
match self.client_state {
|
||||
ProjectClientState::Remote { replica_id, .. } => replica_id,
|
||||
@@ -1985,14 +2008,17 @@ impl Project {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn task_store(&self) -> &Entity<TaskStore> {
|
||||
&self.task_store
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn snippets(&self) -> &Entity<SnippetProvider> {
|
||||
&self.snippets
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn search_history(&self, kind: SearchInputKind) -> &SearchHistory {
|
||||
match kind {
|
||||
SearchInputKind::Query => &self.search_history,
|
||||
@@ -2001,6 +2027,7 @@ impl Project {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn search_history_mut(&mut self, kind: SearchInputKind) -> &mut SearchHistory {
|
||||
match kind {
|
||||
SearchInputKind::Query => &mut self.search_history,
|
||||
@@ -2009,14 +2036,17 @@ impl Project {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn collaborators(&self) -> &HashMap<proto::PeerId, Collaborator> {
|
||||
&self.collaborators
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn host(&self) -> Option<&Collaborator> {
|
||||
self.collaborators.values().find(|c| c.is_host)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_worktrees_reordered(&mut self, worktrees_reordered: bool, cx: &mut App) {
|
||||
self.worktree_store.update(cx, |store, _| {
|
||||
store.set_worktrees_reordered(worktrees_reordered);
|
||||
@@ -2024,6 +2054,7 @@ impl Project {
|
||||
}
|
||||
|
||||
/// Collect all worktrees, including ones that don't appear in the project panel
|
||||
#[inline]
|
||||
pub fn worktrees<'a>(
|
||||
&self,
|
||||
cx: &'a App,
|
||||
@@ -2032,6 +2063,7 @@ impl Project {
|
||||
}
|
||||
|
||||
/// Collect all user-visible worktrees, the ones that appear in the project panel.
|
||||
#[inline]
|
||||
pub fn visible_worktrees<'a>(
|
||||
&'a self,
|
||||
cx: &'a App,
|
||||
@@ -2039,16 +2071,19 @@ impl Project {
|
||||
self.worktree_store.read(cx).visible_worktrees(cx)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn worktree_for_root_name(&self, root_name: &str, cx: &App) -> Option<Entity<Worktree>> {
|
||||
self.visible_worktrees(cx)
|
||||
.find(|tree| tree.read(cx).root_name() == root_name)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn worktree_root_names<'a>(&'a self, cx: &'a App) -> impl Iterator<Item = &'a str> {
|
||||
self.visible_worktrees(cx)
|
||||
.map(|tree| tree.read(cx).root_name().as_unix_str())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn worktree_for_id(&self, id: WorktreeId, cx: &App) -> Option<Entity<Worktree>> {
|
||||
self.worktree_store.read(cx).worktree_for_id(id, cx)
|
||||
}
|
||||
@@ -2063,12 +2098,14 @@ impl Project {
|
||||
.worktree_for_entry(entry_id, cx)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn worktree_id_for_entry(&self, entry_id: ProjectEntryId, cx: &App) -> Option<WorktreeId> {
|
||||
self.worktree_for_entry(entry_id, cx)
|
||||
.map(|worktree| worktree.read(cx).id())
|
||||
}
|
||||
|
||||
/// Checks if the entry is the root of a worktree.
|
||||
#[inline]
|
||||
pub fn entry_is_worktree_root(&self, entry_id: ProjectEntryId, cx: &App) -> bool {
|
||||
self.worktree_for_entry(entry_id, cx)
|
||||
.map(|worktree| {
|
||||
@@ -2080,6 +2117,7 @@ impl Project {
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn project_path_git_status(
|
||||
&self,
|
||||
project_path: &ProjectPath,
|
||||
@@ -2090,6 +2128,7 @@ impl Project {
|
||||
.project_path_git_status(project_path, cx)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn visibility_for_paths(
|
||||
&self,
|
||||
paths: &[PathBuf],
|
||||
@@ -2141,6 +2180,7 @@ impl Project {
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn copy_entry(
|
||||
&mut self,
|
||||
entry_id: ProjectEntryId,
|
||||
@@ -2219,6 +2259,7 @@ impl Project {
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn delete_file(
|
||||
&mut self,
|
||||
path: ProjectPath,
|
||||
@@ -2229,6 +2270,7 @@ impl Project {
|
||||
self.delete_entry(entry.id, trash, cx)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn delete_entry(
|
||||
&mut self,
|
||||
entry_id: ProjectEntryId,
|
||||
@@ -2242,6 +2284,7 @@ impl Project {
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn expand_entry(
|
||||
&mut self,
|
||||
worktree_id: WorktreeId,
|
||||
@@ -2393,6 +2436,7 @@ impl Project {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn unshare(&mut self, cx: &mut Context<Self>) -> Result<()> {
|
||||
self.unshare_internal(cx)?;
|
||||
cx.emit(Event::RemoteIdChanged(None));
|
||||
@@ -2489,10 +2533,12 @@ impl Project {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn close(&mut self, cx: &mut Context<Self>) {
|
||||
cx.emit(Event::Closed);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_disconnected(&self, cx: &App) -> bool {
|
||||
match &self.client_state {
|
||||
ProjectClientState::Remote {
|
||||
@@ -2506,6 +2552,7 @@ impl Project {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn remote_client_is_disconnected(&self, cx: &App) -> bool {
|
||||
self.remote_client
|
||||
.as_ref()
|
||||
@@ -2513,6 +2560,7 @@ impl Project {
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn capability(&self) -> Capability {
|
||||
match &self.client_state {
|
||||
ProjectClientState::Remote { capability, .. } => *capability,
|
||||
@@ -2520,10 +2568,12 @@ impl Project {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_read_only(&self, cx: &App) -> bool {
|
||||
self.is_disconnected(cx) || self.capability() == Capability::ReadOnly
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_local(&self) -> bool {
|
||||
match &self.client_state {
|
||||
ProjectClientState::Local | ProjectClientState::Shared { .. } => {
|
||||
@@ -2533,6 +2583,8 @@ impl Project {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this project is a remote server (not counting collab).
|
||||
#[inline]
|
||||
pub fn is_via_remote_server(&self) -> bool {
|
||||
match &self.client_state {
|
||||
ProjectClientState::Local | ProjectClientState::Shared { .. } => {
|
||||
@@ -2542,6 +2594,8 @@ impl Project {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this project is from collab (not counting remote servers).
|
||||
#[inline]
|
||||
pub fn is_via_collab(&self) -> bool {
|
||||
match &self.client_state {
|
||||
ProjectClientState::Local | ProjectClientState::Shared { .. } => false,
|
||||
@@ -2549,6 +2603,17 @@ impl Project {
|
||||
}
|
||||
}
|
||||
|
||||
/// `!self.is_local()`
|
||||
#[inline]
|
||||
pub fn is_remote(&self) -> bool {
|
||||
debug_assert_eq!(
|
||||
!self.is_local(),
|
||||
self.is_via_collab() || self.is_via_remote_server()
|
||||
);
|
||||
!self.is_local()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn create_buffer(
|
||||
&mut self,
|
||||
searchable: bool,
|
||||
@@ -2559,6 +2624,7 @@ impl Project {
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn create_local_buffer(
|
||||
&mut self,
|
||||
text: &str,
|
||||
@@ -2566,7 +2632,7 @@ impl Project {
|
||||
project_searchable: bool,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Entity<Buffer> {
|
||||
if self.is_via_collab() || self.is_via_remote_server() {
|
||||
if self.is_remote() {
|
||||
panic!("called create_local_buffer on a remote project")
|
||||
}
|
||||
self.buffer_store.update(cx, |buffer_store, cx| {
|
||||
|
||||
@@ -615,8 +615,11 @@ impl ProjectPanel {
|
||||
.detach();
|
||||
|
||||
let trash_action = [TypeId::of::<Trash>()];
|
||||
let is_remote = project.read(cx).is_via_collab();
|
||||
let is_remote = project.read(cx).is_remote();
|
||||
|
||||
// Make sure the trash option is never displayed anywhere on remote
|
||||
// hosts since they may not support trashing. May want to dynamically
|
||||
// detect this in the future.
|
||||
if is_remote {
|
||||
CommandPaletteFilter::update_global(cx, |filter, _cx| {
|
||||
filter.hide_action_types(&trash_action);
|
||||
@@ -981,7 +984,7 @@ impl ProjectPanel {
|
||||
let is_foldable = auto_fold_dirs && self.is_foldable(entry, worktree);
|
||||
let is_unfoldable = auto_fold_dirs && self.is_unfoldable(entry, worktree);
|
||||
let is_read_only = project.is_read_only(cx);
|
||||
let is_remote = project.is_via_collab();
|
||||
let is_remote = project.is_remote();
|
||||
let is_local = project.is_local();
|
||||
|
||||
let settings = ProjectPanelSettings::get_global(cx);
|
||||
@@ -1045,13 +1048,13 @@ impl ProjectPanel {
|
||||
.when(!should_hide_rename, |menu| {
|
||||
menu.action("Rename", Box::new(Rename))
|
||||
})
|
||||
.when(!is_root & !is_remote, |menu| {
|
||||
.when(!is_root && !is_remote, |menu| {
|
||||
menu.action("Trash", Box::new(Trash { skip_prompt: false }))
|
||||
})
|
||||
.when(!is_root, |menu| {
|
||||
menu.action("Delete", Box::new(Delete { skip_prompt: false }))
|
||||
})
|
||||
.when(!is_remote & is_root, |menu| {
|
||||
.when(!is_remote && is_root, |menu| {
|
||||
menu.separator()
|
||||
.action(
|
||||
"Add Folder to Project…",
|
||||
@@ -5458,11 +5461,13 @@ impl Render for ProjectPanel {
|
||||
.on_action(cx.listener(Self::new_directory))
|
||||
.on_action(cx.listener(Self::rename))
|
||||
.on_action(cx.listener(Self::delete))
|
||||
.on_action(cx.listener(Self::trash))
|
||||
.on_action(cx.listener(Self::cut))
|
||||
.on_action(cx.listener(Self::copy))
|
||||
.on_action(cx.listener(Self::paste))
|
||||
.on_action(cx.listener(Self::duplicate))
|
||||
.when(!project.is_remote(), |el| {
|
||||
el.on_action(cx.listener(Self::trash))
|
||||
})
|
||||
})
|
||||
.when(project.is_local(), |el| {
|
||||
el.on_action(cx.listener(Self::reveal_in_finder))
|
||||
|
||||
Reference in New Issue
Block a user