workspace: Do not reuse window for sub directory (only for root directory and sub files) (#24560)
Closes #10232 Context: We have three ways to open files or dirs in Zed: `zed`, `zed --new`, and `zed --add`. `--new` forces the project to open in a new window, while `--add` forces it to open in an existing window (even if the dir isn’t a subdir of an existing project or the file isn’t part of it). Using just `zed` tries to open it in an existing window based on similar logic of `--add`, but if no related project is found the dir, opens in a new window. Problem: Right now, subdirs that are part of an existing project open in the existing window when using `zed`. By default, subdirs should open in a new window instead. If someone wants to open it in the existing window, they can explicitly use `--add`. After this PR, only root dir and files will focus on existing window, when `zed ` is used. Fix: For the `zed` case, we’ve filtered out subdirs in the logic that assigns them to an existing window. Release Notes: - Fixed an issue where subdirectories of an already opened project, when opened via the terminal, would open in the existing project instead of a new window.
This commit is contained in:
parent
c771ca49e1
commit
5dc3c237eb
3 changed files with 77 additions and 58 deletions
|
@ -95,7 +95,10 @@ use task_store::TaskStore;
|
||||||
use terminals::Terminals;
|
use terminals::Terminals;
|
||||||
use text::{Anchor, BufferId};
|
use text::{Anchor, BufferId};
|
||||||
use toolchain_store::EmptyToolchainStore;
|
use toolchain_store::EmptyToolchainStore;
|
||||||
use util::{paths::compare_paths, ResultExt as _};
|
use util::{
|
||||||
|
paths::{compare_paths, SanitizedPath},
|
||||||
|
ResultExt as _,
|
||||||
|
};
|
||||||
use worktree::{CreatedEntry, Snapshot, Traversal};
|
use worktree::{CreatedEntry, Snapshot, Traversal};
|
||||||
use worktree_store::{WorktreeStore, WorktreeStoreEvent};
|
use worktree_store::{WorktreeStore, WorktreeStoreEvent};
|
||||||
|
|
||||||
|
@ -1484,22 +1487,37 @@ impl Project {
|
||||||
.and_then(|worktree| worktree.read(cx).status_for_file(&project_path.path))
|
.and_then(|worktree| worktree.read(cx).status_for_file(&project_path.path))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn visibility_for_paths(&self, paths: &[PathBuf], cx: &App) -> Option<bool> {
|
pub fn visibility_for_paths(
|
||||||
|
&self,
|
||||||
|
paths: &[PathBuf],
|
||||||
|
metadatas: &[Metadata],
|
||||||
|
exclude_sub_dirs: bool,
|
||||||
|
cx: &App,
|
||||||
|
) -> Option<bool> {
|
||||||
paths
|
paths
|
||||||
.iter()
|
.iter()
|
||||||
.map(|path| self.visibility_for_path(path, cx))
|
.zip(metadatas)
|
||||||
|
.map(|(path, metadata)| self.visibility_for_path(path, metadata, exclude_sub_dirs, cx))
|
||||||
.max()
|
.max()
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn visibility_for_path(&self, path: &Path, cx: &App) -> Option<bool> {
|
pub fn visibility_for_path(
|
||||||
|
&self,
|
||||||
|
path: &Path,
|
||||||
|
metadata: &Metadata,
|
||||||
|
exclude_sub_dirs: bool,
|
||||||
|
cx: &App,
|
||||||
|
) -> Option<bool> {
|
||||||
|
let sanitized_path = SanitizedPath::from(path);
|
||||||
|
let path = sanitized_path.as_path();
|
||||||
self.worktrees(cx)
|
self.worktrees(cx)
|
||||||
.filter_map(|worktree| {
|
.filter_map(|worktree| {
|
||||||
let worktree = worktree.read(cx);
|
let worktree = worktree.read(cx);
|
||||||
worktree
|
let abs_path = worktree.as_local()?.abs_path();
|
||||||
.as_local()?
|
let contains = path == abs_path
|
||||||
.contains_abs_path(path)
|
|| (path.starts_with(abs_path) && (!exclude_sub_dirs || !metadata.is_dir));
|
||||||
.then(|| worktree.is_visible())
|
contains.then(|| worktree.is_visible())
|
||||||
})
|
})
|
||||||
.max()
|
.max()
|
||||||
}
|
}
|
||||||
|
|
|
@ -5958,7 +5958,6 @@ pub struct OpenOptions {
|
||||||
pub replace_window: Option<WindowHandle<Workspace>>,
|
pub replace_window: Option<WindowHandle<Workspace>>,
|
||||||
pub env: Option<HashMap<String, String>>,
|
pub env: Option<HashMap<String, String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub fn open_paths(
|
pub fn open_paths(
|
||||||
abs_paths: &[PathBuf],
|
abs_paths: &[PathBuf],
|
||||||
|
@ -5976,58 +5975,65 @@ pub fn open_paths(
|
||||||
let mut best_match = None;
|
let mut best_match = None;
|
||||||
let mut open_visible = OpenVisible::All;
|
let mut open_visible = OpenVisible::All;
|
||||||
|
|
||||||
if open_options.open_new_workspace != Some(true) {
|
|
||||||
for window in local_workspace_windows(cx) {
|
|
||||||
if let Ok(workspace) = window.read(cx) {
|
|
||||||
let m = workspace
|
|
||||||
.project
|
|
||||||
.read(cx)
|
|
||||||
.visibility_for_paths(&abs_paths, cx);
|
|
||||||
if m > best_match {
|
|
||||||
existing = Some(window);
|
|
||||||
best_match = m;
|
|
||||||
} else if best_match.is_none() && open_options.open_new_workspace == Some(false) {
|
|
||||||
existing = Some(window)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cx.spawn(move |mut cx| async move {
|
cx.spawn(move |mut cx| async move {
|
||||||
if open_options.open_new_workspace.is_none() && existing.is_none() {
|
if open_options.open_new_workspace != Some(true) {
|
||||||
let all_files = abs_paths.iter().map(|path| app_state.fs.metadata(path));
|
let all_paths = abs_paths.iter().map(|path| app_state.fs.metadata(path));
|
||||||
if futures::future::join_all(all_files)
|
let all_metadatas = futures::future::join_all(all_paths)
|
||||||
.await
|
.await
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|result| result.ok().flatten())
|
.filter_map(|result| result.ok().flatten())
|
||||||
.all(|file| !file.is_dir)
|
.collect::<Vec<_>>();
|
||||||
{
|
|
||||||
cx.update(|cx| {
|
cx.update(|cx| {
|
||||||
if let Some(window) = cx
|
for window in local_workspace_windows(&cx) {
|
||||||
.active_window()
|
if let Ok(workspace) = window.read(&cx) {
|
||||||
.and_then(|window| window.downcast::<Workspace>())
|
let m = workspace.project.read(&cx).visibility_for_paths(
|
||||||
{
|
&abs_paths,
|
||||||
if let Ok(workspace) = window.read(cx) {
|
&all_metadatas,
|
||||||
let project = workspace.project().read(cx);
|
open_options.open_new_workspace == None,
|
||||||
if project.is_local() && !project.is_via_collab() {
|
cx,
|
||||||
|
);
|
||||||
|
if m > best_match {
|
||||||
|
existing = Some(window);
|
||||||
|
best_match = m;
|
||||||
|
} else if best_match.is_none()
|
||||||
|
&& open_options.open_new_workspace == Some(false)
|
||||||
|
{
|
||||||
|
existing = Some(window)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if open_options.open_new_workspace.is_none() && existing.is_none() {
|
||||||
|
if all_metadatas.iter().all(|file| !file.is_dir) {
|
||||||
|
cx.update(|cx| {
|
||||||
|
if let Some(window) = cx
|
||||||
|
.active_window()
|
||||||
|
.and_then(|window| window.downcast::<Workspace>())
|
||||||
|
{
|
||||||
|
if let Ok(workspace) = window.read(cx) {
|
||||||
|
let project = workspace.project().read(cx);
|
||||||
|
if project.is_local() && !project.is_via_collab() {
|
||||||
|
existing = Some(window);
|
||||||
|
open_visible = OpenVisible::None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for window in local_workspace_windows(cx) {
|
||||||
|
if let Ok(workspace) = window.read(cx) {
|
||||||
|
let project = workspace.project().read(cx);
|
||||||
|
if project.is_via_collab() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
existing = Some(window);
|
existing = Some(window);
|
||||||
open_visible = OpenVisible::None;
|
open_visible = OpenVisible::None;
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})?;
|
||||||
for window in local_workspace_windows(cx) {
|
}
|
||||||
if let Ok(workspace) = window.read(cx) {
|
|
||||||
let project = workspace.project().read(cx);
|
|
||||||
if project.is_via_collab() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
existing = Some(window);
|
|
||||||
open_visible = OpenVisible::None;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1335,11 +1335,6 @@ impl LocalWorktree {
|
||||||
&self.fs
|
&self.fs
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains_abs_path(&self, path: &Path) -> bool {
|
|
||||||
let path = SanitizedPath::from(path);
|
|
||||||
path.starts_with(&self.abs_path)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_path_private(&self, path: &Path) -> bool {
|
pub fn is_path_private(&self, path: &Path) -> bool {
|
||||||
!self.share_private_files && self.settings.is_path_private(path)
|
!self.share_private_files && self.settings.is_path_private(path)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue