mirror of
https://git.savannah.gnu.org/git/guix.git
synced 2026-06-14 10:34:08 +02:00
2c51b803e3
* gnu/packages/patches/zed-0.225.10-add-guix-container-support.patch: New file. * gnu/packages/patches/zed-0.225.10-collapse-multiline-git-deps.patch: New file. * gnu/packages/patches/zed-0.225.10-disable-dlopen.patch: New file. * gnu/packages/patches/zed-0.225.10-exclude-libwebrtc-from-audio.patch: New file. * gnu/packages/patches/zed-0.225.10-fix-sqlite-memory-mode.patch: New file. * gnu/packages/patches/zed-0.225.10-fix-test-db-isolation.patch: New file. * gnu/packages/patches/zed-0.225.10-fix-workspace-race.patch: New file. * gnu/packages/patches/zed-0.225.10-keep-regular-file-workspaces.patch: New file. * gnu/packages/patches/zed-0.225.10-remove-patch-crates-io.patch: New file. * gnu/packages/patches/zed-0.225.10-use-mock-livekit-on-linux.patch: New file. * gnu/packages/patches/rust-candle-0.9.1-add-candle-onnx-to-workspace.patch: New file. * gnu/local.mk (dist_patch_DATA): Register them. * gnu/packages/rust-sources.scm (rust-alacritty-0.25.1.9d9640d, rust-candle-0.9.1.724d75e, rust-dap-types-0.0.1.1b461b3, rust-gh-workflow-0.8.0.c9eac0e, rust-livekit-0.7.8.5f04705, rust-notify-8.2.0.ce58c24, rust-pet-0.1.0.d5b5bb0, rust-tiktoken-rs-0.9.1.2570c43, rust-zed-xim-0.4.0-zed.16f35a2): New variables. * gnu/packages/rust-crates.scm (lookup-cargo-inputs): Modify. * gnu/packages/text-editors.scm (zed): New variable. Change-Id: I16d4c5431e3398261ac4eb74483747c09cf74449
164 lines
6.7 KiB
Diff
164 lines
6.7 KiB
Diff
From: Danny Milosavljevic <dannym@friendly-machines.com>
|
|
Date: Fri, 6 Mar 2026 20:20:00 +0000
|
|
Subject: [PATCH] workspace: Keep local workspaces whose roots are only regular files
|
|
License: expat
|
|
|
|
Zed persists local workspaces for standalone regular files as well as
|
|
directory-backed projects. Recent-workspace cleanup and last-session
|
|
restoration were using a helper that only kept local workspaces if all
|
|
saved paths existed and at least one of them was a directory.
|
|
|
|
That made local workspaces whose roots were only regular files look
|
|
invalid. A background recent-workspaces pass could then delete the
|
|
workspace row, which in turn cascaded to item-specific state such as
|
|
editors. In the window edited-state restore test, reopening a
|
|
standalone regular file could therefore fail because the saved editor
|
|
row had been deleted by that cleanup path.
|
|
|
|
Fix this by treating a local workspace as valid whenever all of its
|
|
saved paths still exist, whether those paths are directories or
|
|
regular files. Apply the same rule to last-session workspace
|
|
restoration, and add regression coverage for both code paths.
|
|
|
|
diff --git a/crates/workspace/src/persistence.rs b/crates/workspace/src/persistence.rs
|
|
--- a/crates/workspace/src/persistence.rs
|
|
+++ b/crates/workspace/src/persistence.rs
|
|
@@ -1783,19 +1783,13 @@ impl WorkspaceDb {
|
|
}
|
|
}
|
|
|
|
- async fn all_paths_exist_with_a_directory(paths: &[PathBuf], fs: &dyn Fs) -> bool {
|
|
- let mut any_dir = false;
|
|
+ async fn all_paths_exist(paths: &[PathBuf], fs: &dyn Fs) -> bool {
|
|
for path in paths {
|
|
- match fs.metadata(path).await.ok().flatten() {
|
|
- None => return false,
|
|
- Some(meta) => {
|
|
- if meta.is_dir {
|
|
- any_dir = true;
|
|
- }
|
|
- }
|
|
+ if fs.metadata(path).await.ok().flatten().is_none() {
|
|
+ return false;
|
|
}
|
|
}
|
|
- any_dir
|
|
+ true
|
|
}
|
|
|
|
// Returns the recent locations which are still valid on disk and deletes ones which no longer
|
|
@@ -1843,7 +1837,11 @@ impl WorkspaceDb {
|
|
// If a local workspace points to WSL, this check will cause us to wait for the
|
|
// WSL VM and file server to boot up. This can block for many seconds.
|
|
// Supported scenarios use remote workspaces.
|
|
- if !has_wsl_path && Self::all_paths_exist_with_a_directory(paths.paths(), fs).await {
|
|
+ //
|
|
+ // Local workspaces may legitimately contain only regular files (for example, a
|
|
+ // standalone file opened outside any worktree). Those should be preserved as
|
|
+ // long as all of their saved paths still exist.
|
|
+ if !has_wsl_path && Self::all_paths_exist(paths.paths(), fs).await {
|
|
result.push((id, SerializedWorkspaceLocation::Local, paths, timestamp));
|
|
} else {
|
|
delete_tasks.push(self.delete_workspace_by_id(id));
|
|
@@ -1903,7 +1901,7 @@ impl WorkspaceDb {
|
|
window_id,
|
|
});
|
|
} else {
|
|
- if Self::all_paths_exist_with_a_directory(paths.paths(), fs).await {
|
|
+ if Self::all_paths_exist(paths.paths(), fs).await {
|
|
workspaces.push(SessionWorkspace {
|
|
workspace_id,
|
|
location: SerializedWorkspaceLocation::Local,
|
|
@@ -3425,6 +3423,91 @@ mod tests {
|
|
);
|
|
}
|
|
|
|
+ #[gpui::test]
|
|
+ async fn test_recent_workspaces_on_disk_keeps_regular_file_only_workspace(
|
|
+ cx: &mut gpui::TestAppContext,
|
|
+ ) {
|
|
+ let dir = tempfile::TempDir::with_prefix("regular-file-workspace").unwrap();
|
|
+ let regular_file = dir.path().join("a");
|
|
+
|
|
+ let fs = fs::FakeFs::new(cx.executor());
|
|
+ fs.insert_tree(dir.path(), json!({"a": "hey"})).await;
|
|
+
|
|
+ let db = WorkspaceDb::open_test_db("test_recent_workspaces_keeps_regular_file_only")
|
|
+ .await;
|
|
+ let workspace = SerializedWorkspace {
|
|
+ id: WorkspaceId(1),
|
|
+ paths: PathList::new(&[regular_file.clone()]),
|
|
+ location: SerializedWorkspaceLocation::Local,
|
|
+ center_group: Default::default(),
|
|
+ window_bounds: Default::default(),
|
|
+ display: Default::default(),
|
|
+ docks: Default::default(),
|
|
+ centered_layout: false,
|
|
+ breakpoints: Default::default(),
|
|
+ session_id: None,
|
|
+ window_id: Some(1),
|
|
+ user_toolchains: Default::default(),
|
|
+ };
|
|
+
|
|
+ db.save_workspace(workspace.clone()).await;
|
|
+
|
|
+ let recent = db.recent_workspaces_on_disk(fs.as_ref()).await.unwrap();
|
|
+ assert_eq!(
|
|
+ recent,
|
|
+ vec![(
|
|
+ workspace.id,
|
|
+ SerializedWorkspaceLocation::Local,
|
|
+ workspace.paths.clone(),
|
|
+ recent[0].3,
|
|
+ )]
|
|
+ );
|
|
+ assert_eq!(db.workspace_for_roots(&[regular_file]).unwrap().id, workspace.id);
|
|
+ }
|
|
+
|
|
+ #[gpui::test]
|
|
+ async fn test_last_session_workspace_locations_keeps_regular_file_only_workspace(
|
|
+ cx: &mut gpui::TestAppContext,
|
|
+ ) {
|
|
+ let dir = tempfile::TempDir::with_prefix("regular-file-workspace-session").unwrap();
|
|
+ let regular_file = dir.path().join("a");
|
|
+
|
|
+ let fs = fs::FakeFs::new(cx.executor());
|
|
+ fs.insert_tree(dir.path(), json!({"a": "hey"})).await;
|
|
+
|
|
+ let db = WorkspaceDb::open_test_db("test_last_session_keeps_regular_file_only").await;
|
|
+ let workspace = SerializedWorkspace {
|
|
+ id: WorkspaceId(1),
|
|
+ paths: PathList::new(&[regular_file.clone()]),
|
|
+ location: SerializedWorkspaceLocation::Local,
|
|
+ center_group: Default::default(),
|
|
+ window_bounds: Default::default(),
|
|
+ display: Default::default(),
|
|
+ docks: Default::default(),
|
|
+ centered_layout: false,
|
|
+ breakpoints: Default::default(),
|
|
+ session_id: Some("one-session".to_owned()),
|
|
+ window_id: Some(7),
|
|
+ user_toolchains: Default::default(),
|
|
+ };
|
|
+
|
|
+ db.save_workspace(workspace.clone()).await;
|
|
+
|
|
+ let locations = db
|
|
+ .last_session_workspace_locations("one-session", None, fs.as_ref())
|
|
+ .await
|
|
+ .unwrap();
|
|
+ assert_eq!(
|
|
+ locations,
|
|
+ vec![SessionWorkspace {
|
|
+ workspace_id: workspace.id,
|
|
+ location: SerializedWorkspaceLocation::Local,
|
|
+ paths: workspace.paths,
|
|
+ window_id: Some(WindowId::from(7u64)),
|
|
+ }]
|
|
+ );
|
|
+ }
|
|
+
|
|
#[gpui::test]
|
|
async fn test_get_or_create_ssh_project() {
|
|
let db = WorkspaceDb::open_test_db("test_get_or_create_ssh_project").await;
|