terminal_view: Fix terminal opening in / when no project is open (#46582)

Max Malkin created

Closes #46574

The `default_working_directory()` function in
`crates/terminal_view/src/terminal_view.rs:1585` returned `None` when no
project directory was available. The code comment (now removed)
incorrectly claimed "None implies `~` on whichever machine we end up
on". However, when `None` is passed to `alacritty_terminal`, it uses the
process CWD, not the home directory. On macOS when Zed is launched from
a .`app` bundle, the CWD is `/`.
    
Added a fallback at the end of` default_working_directory()` that
explicitly returns the home directory when no project directory is
found: `directory.or_else(dirs::home_dir)`

  This ensures:
  1. `CurrentProjectDirectory` with no project open → home directory
  2. `FirstProjectDirectory `with no project open → home directory
3. `AlwaysHome `→ home directory (explicitly, not relying on shell
behavior)
  4. Always `{ directory }` with invalid directory → home directory



Release Notes:
- Fixed terminal opening in `/` instead of home directory when no
project is open.

Change summary

crates/terminal_view/src/terminal_view.rs | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)

Detailed changes

crates/terminal_view/src/terminal_view.rs 🔗

@@ -1580,10 +1580,10 @@ impl SearchableItem for TerminalView {
     }
 }
 
-///Gets the working directory for the given workspace, respecting the user's settings.
-/// None implies "~" on whichever machine we end up on.
+/// Gets the working directory for the given workspace, respecting the user's settings.
+/// Falls back to home directory when no project directory is available.
 pub(crate) fn default_working_directory(workspace: &Workspace, cx: &App) -> Option<PathBuf> {
-    match &TerminalSettings::get_global(cx).working_directory {
+    let directory = match &TerminalSettings::get_global(cx).working_directory {
         WorkingDirectory::CurrentProjectDirectory => workspace
             .project()
             .read(cx)
@@ -1593,13 +1593,12 @@ pub(crate) fn default_working_directory(workspace: &Workspace, cx: &App) -> Opti
             .or_else(|| first_project_directory(workspace, cx)),
         WorkingDirectory::FirstProjectDirectory => first_project_directory(workspace, cx),
         WorkingDirectory::AlwaysHome => None,
-        WorkingDirectory::Always { directory } => {
-            shellexpand::full(&directory) //TODO handle this better
-                .ok()
-                .map(|dir| Path::new(&dir.to_string()).to_path_buf())
-                .filter(|dir| dir.is_dir())
-        }
-    }
+        WorkingDirectory::Always { directory } => shellexpand::full(directory)
+            .ok()
+            .map(|dir| Path::new(&dir.to_string()).to_path_buf())
+            .filter(|dir| dir.is_dir()),
+    };
+    directory.or_else(dirs::home_dir)
 }
 ///Gets the first project's home directory, or the home directory
 fn first_project_directory(workspace: &Workspace, cx: &App) -> Option<PathBuf> {
@@ -1637,7 +1636,7 @@ mod tests {
             assert!(workspace.worktrees(cx).next().is_none());
 
             let res = default_working_directory(workspace, cx);
-            assert_eq!(res, None);
+            assert_eq!(res, dirs::home_dir());
             let res = first_project_directory(workspace, cx);
             assert_eq!(res, None);
         });