Always open the project panel for dev server projects (#12654)

Conrad Irwin created

Release Notes:

- N/A

Change summary

crates/project/src/project.rs              | 13 ++++++++
crates/project_panel/src/project_panel.rs  | 12 ++++---
crates/terminal_view/src/terminal_panel.rs | 35 ++++++++++++++++++++---
crates/zed/src/zed.rs                      | 20 -------------
4 files changed, 51 insertions(+), 29 deletions(-)

Detailed changes

crates/project/src/project.rs 🔗

@@ -1281,6 +1281,19 @@ impl Project {
         self.dev_server_project_id
     }
 
+    pub fn supports_remote_terminal(&self, cx: &AppContext) -> bool {
+        let Some(id) = self.dev_server_project_id else {
+            return false;
+        };
+        let Some(server) = dev_server_projects::Store::global(cx)
+            .read(cx)
+            .dev_server_for_project(id)
+        else {
+            return false;
+        };
+        server.ssh_connection_string.is_some()
+    }
+
     pub fn ssh_connection_string(&self, cx: &ModelContext<Self>) -> Option<SharedString> {
         if self.is_local() {
             return None;

crates/project_panel/src/project_panel.rs 🔗

@@ -2377,11 +2377,13 @@ impl Panel for ProjectPanel {
     }
 
     fn starts_open(&self, cx: &WindowContext) -> bool {
-        self.project.read(cx).visible_worktrees(cx).any(|tree| {
-            tree.read(cx)
-                .root_entry()
-                .map_or(false, |entry| entry.is_dir())
-        })
+        let project = &self.project.read(cx);
+        project.dev_server_project_id().is_some()
+            || project.visible_worktrees(cx).any(|tree| {
+                tree.read(cx)
+                    .root_entry()
+                    .map_or(false, |entry| entry.is_dir())
+            })
     }
 }
 

crates/terminal_view/src/terminal_panel.rs 🔗

@@ -44,7 +44,13 @@ pub fn init(cx: &mut AppContext) {
             workspace.register_action(TerminalPanel::new_terminal);
             workspace.register_action(TerminalPanel::open_terminal);
             workspace.register_action(|workspace, _: &ToggleFocus, cx| {
-                workspace.toggle_panel_focus::<TerminalPanel>(cx);
+                if workspace
+                    .panel::<TerminalPanel>(cx)
+                    .as_ref()
+                    .is_some_and(|panel| panel.read(cx).enabled)
+                {
+                    workspace.toggle_panel_focus::<TerminalPanel>(cx);
+                }
             });
         },
     )
@@ -61,6 +67,7 @@ pub struct TerminalPanel {
     pending_terminals_to_add: usize,
     _subscriptions: Vec<Subscription>,
     deferred_tasks: HashMap<TaskId, Task<()>>,
+    enabled: bool,
 }
 
 impl TerminalPanel {
@@ -190,6 +197,8 @@ impl TerminalPanel {
             cx.observe(&pane, |_, _, cx| cx.notify()),
             cx.subscribe(&pane, Self::handle_pane_event),
         ];
+        let project = workspace.project().read(cx);
+        let enabled = project.is_local() || project.supports_remote_terminal(cx);
         let this = Self {
             pane,
             fs: workspace.app_state().fs.clone(),
@@ -200,6 +209,7 @@ impl TerminalPanel {
             pending_terminals_to_add: 0,
             deferred_tasks: HashMap::default(),
             _subscriptions: subscriptions,
+            enabled,
         };
         this
     }
@@ -487,6 +497,19 @@ impl TerminalPanel {
         reveal_strategy: RevealStrategy,
         cx: &mut ViewContext<Self>,
     ) -> Task<Result<Model<Terminal>>> {
+        if !self.enabled {
+            if spawn_task.is_none()
+                || !matches!(
+                    spawn_task.as_ref().unwrap().cwd,
+                    Some(TerminalWorkDir::Ssh { .. })
+                )
+            {
+                return Task::ready(Err(anyhow::anyhow!(
+                    "terminal not yet supported for remote projects"
+                )));
+            }
+        }
+
         let workspace = self.workspace.clone();
         self.pending_terminals_to_add += 1;
 
@@ -619,7 +642,7 @@ impl TerminalPanel {
         &self.pane
     }
 
-    fn has_no_terminals(&mut self, cx: &mut ViewContext<'_, Self>) -> bool {
+    fn has_no_terminals(&self, cx: &WindowContext) -> bool {
         self.pane.read(cx).items_len() == 0 && self.pending_terminals_to_add == 0
     }
 }
@@ -754,9 +777,11 @@ impl Panel for TerminalPanel {
     }
 
     fn icon(&self, cx: &WindowContext) -> Option<IconName> {
-        TerminalSettings::get_global(cx)
-            .button
-            .then(|| IconName::Terminal)
+        if (self.enabled || !self.has_no_terminals(cx)) && TerminalSettings::get_global(cx).button {
+            Some(IconName::Terminal)
+        } else {
+            None
+        }
     }
 
     fn icon_tooltip(&self, _cx: &WindowContext) -> Option<&'static str> {

crates/zed/src/zed.rs 🔗

@@ -219,25 +219,7 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
             workspace_handle.update(&mut cx, |workspace, cx| {
                 workspace.add_panel(assistant_panel, cx);
                 workspace.add_panel(project_panel, cx);
-                {
-                    let project = workspace.project().read(cx);
-                    if project.is_local()
-                        || project
-                            .dev_server_project_id()
-                            .and_then(|dev_server_project_id| {
-                                Some(
-                                    dev_server_projects::Store::global(cx)
-                                        .read(cx)
-                                        .dev_server_for_project(dev_server_project_id)?
-                                        .ssh_connection_string
-                                        .is_some(),
-                                )
-                            })
-                            .unwrap_or(false)
-                    {
-                        workspace.add_panel(terminal_panel, cx);
-                    }
-                }
+                workspace.add_panel(terminal_panel, cx);
                 workspace.add_panel(channels_panel, cx);
                 workspace.add_panel(chat_panel, cx);
                 workspace.add_panel(notification_panel, cx);