Persist dev container suggestion dismissal across git worktrees (#58576)
Opening a new git worktree of a repository that has a dev container configuration re-prompted you to reopen in a dev container, even after you'd clicked "Don't Show Again" in another worktree of the same repo. The dismissal was keyed on each worktree's own absolute path, so sibling worktrees never saw the stored choice. This keys the dismissal on the repository's common Git directory instead, which is shared across all linked git worktrees of the same repo, so dismissing in one worktree now suppresses the prompt in the others. Projects that aren't Git repositories fall back to the worktree path as before. Closes AI-357 Release Notes: - Fixed the "Reopen in Dev Container" suggestion re-appearing in new git worktrees after choosing "Don't Show Again"
This commit is contained in:
1 parent
674cf4ff2f
commit
24d400d04c
2 files changed
+50
-3
No files matched your search
@@ -745,7 +745,14 @@ impl GitStore {
|
||||
.values()
|
||||
.filter(|repo| {
|
||||
let repo_path = &repo.read(cx).work_directory_abs_path;
|
||||
*repo_path == worktree_abs_path || worktree_abs_path.starts_with(repo_path.as_ref())
|
||||
// The folder opened in Zed isn't necessarily the repo root; it may be
|
||||
// a subdirectory of it, e.g. opening `~/code/myrepo/backend` when the
|
||||
// repo lives at `~/code/myrepo`. So match any repo whose work directory
|
||||
// contains the folder. Nested repos can produce multiple matches, e.g.
|
||||
// opening `~/code/myrepo/vendor/lib` where `vendor/lib` is a submodule
|
||||
// matches both `myrepo` and the submodule; `max_by_key` then picks the
|
||||
// innermost match (the submodule), which the folder actually belongs to.
|
||||
worktree_abs_path.starts_with(repo_path.as_ref())
|
||||
})
|
||||
.max_by_key(|repo| repo.read(cx).work_directory_abs_path.as_os_str().len())
|
||||
.map(|repo| repo.read(cx).id)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use db::kvp::KeyValueStore;
|
||||
use dev_container::find_configs_in_snapshot;
|
||||
use gpui::{SharedString, Window};
|
||||
use gpui::{App, SharedString, Window};
|
||||
use project::{Project, WorktreeId};
|
||||
use std::path::Path;
|
||||
use std::sync::LazyLock;
|
||||
use ui::Tooltip;
|
||||
use ui::prelude::*;
|
||||
@@ -30,6 +31,44 @@ fn project_devcontainer_key(project_path: &str) -> String {
|
||||
format!("{}_{}", DEV_CONTAINER_SUGGEST_KEY, project_path)
|
||||
}
|
||||
|
||||
/// Returns the path used to remember the user's "Don't Show Again" choice for a
|
||||
/// worktree's dev container suggestion. This is keyed on the repository's common
|
||||
/// Git directory rather than the worktree's own path, so that dismissing the
|
||||
/// suggestion in one git worktree also suppresses it in sibling worktrees of the
|
||||
/// same repository. Falls back to the worktree path when it isn't part of a Git
|
||||
/// repository.
|
||||
fn dismiss_path_for_worktree(
|
||||
project: &gpui::Entity<Project>,
|
||||
worktree_abs_path: &Path,
|
||||
cx: &App,
|
||||
) -> String {
|
||||
let common_dir = project
|
||||
.read(cx)
|
||||
.repositories(cx)
|
||||
.values()
|
||||
.filter_map(|repo| {
|
||||
let repo = repo.read(cx);
|
||||
let work_dir = repo.work_directory_abs_path.clone();
|
||||
// The folder opened in Zed isn't necessarily the repo root; it may be
|
||||
// a subdirectory of it, e.g. opening `~/code/myrepo/backend` when the
|
||||
// repo lives at `~/code/myrepo`. So match any repo whose work directory
|
||||
// contains the folder. Nested repos can produce multiple matches, e.g.
|
||||
// opening `~/code/myrepo/vendor/lib` where `vendor/lib` is a submodule
|
||||
// matches both `myrepo` and the submodule; `max_by_key` then picks the
|
||||
// innermost match (the submodule), which the folder actually belongs to.
|
||||
worktree_abs_path
|
||||
.starts_with(work_dir.as_ref())
|
||||
.then(|| (work_dir.as_os_str().len(), repo.common_dir_abs_path.clone()))
|
||||
})
|
||||
.max_by_key(|(work_dir_len, _)| *work_dir_len)
|
||||
.map(|(_, common_dir)| common_dir);
|
||||
|
||||
match common_dir {
|
||||
Some(common_dir) => common_dir.to_string_lossy().to_string(),
|
||||
None => worktree_abs_path.to_string_lossy().to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn suggest_on_worktree_updated(
|
||||
workspace: &mut Workspace,
|
||||
worktree_id: WorktreeId,
|
||||
@@ -93,7 +132,8 @@ pub fn suggest_on_worktree_updated(
|
||||
let abs_path = worktree.abs_path();
|
||||
let project_path = abs_path.to_string_lossy().to_string();
|
||||
let worktree_name = worktree.root_name_str().to_string();
|
||||
let key_for_dismiss = project_devcontainer_key(&project_path);
|
||||
let dismiss_path = dismiss_path_for_worktree(project, abs_path.as_ref(), cx);
|
||||
let key_for_dismiss = project_devcontainer_key(&dismiss_path);
|
||||
|
||||
let already_dismissed = KeyValueStore::global(cx)
|
||||
.read_kvp(&key_for_dismiss)
|
||||
|
||||
Reference in new issue
Block a user