diff --git a/crates/assistant_slash_command/src/extension_slash_command.rs b/crates/assistant_slash_command/src/extension_slash_command.rs index 6dd2c05f19..71eb39c816 100644 --- a/crates/assistant_slash_command/src/extension_slash_command.rs +++ b/crates/assistant_slash_command/src/extension_slash_command.rs @@ -46,7 +46,7 @@ struct WorktreeDelegateAdapter(Arc); #[async_trait] impl WorktreeDelegate for WorktreeDelegateAdapter { fn id(&self) -> u64 { - self.0.worktree_id().to_proto() + self.0.project_worktree().worktree_id.to_proto() } fn root_path(&self) -> String { diff --git a/crates/client/src/telemetry.rs b/crates/client/src/telemetry.rs index 68b6c302fb..a8a299e357 100644 --- a/crates/client/src/telemetry.rs +++ b/crates/client/src/telemetry.rs @@ -10,7 +10,7 @@ use http_client::{self, AsyncBody, HttpClient, HttpClientWithUrl, Method, Reques use parking_lot::Mutex; use regex::Regex; use release_channel::ReleaseChannel; -use settings::{Settings, SettingsStore}; +use settings::{Settings, SettingsStore, WorktreeId}; use sha2::{Digest, Sha256}; use std::collections::HashSet; use std::fs::File; @@ -20,7 +20,7 @@ use std::time::Instant; use std::{env, mem, path::PathBuf, sync::Arc, time::Duration}; use telemetry_events::{AssistantEventData, AssistantPhase, Event, EventRequestBody, EventWrapper}; use util::TryFutureExt; -use worktree::{UpdatedEntriesSet, WorktreeId}; +use worktree::UpdatedEntriesSet; use self::event_coalescer::EventCoalescer; @@ -604,10 +604,11 @@ mod tests { use clock::FakeSystemClock; use gpui::TestAppContext; use http_client::FakeHttpClient; + use settings::WorktreeId; use std::collections::HashMap; use telemetry_events::FlexibleEvent; use util::rel_path::RelPath; - use worktree::{PathChange, ProjectEntryId, WorktreeId}; + use worktree::{PathChange, ProjectEntryId}; #[gpui::test] fn test_telemetry_flush_on_max_queue_size(cx: &mut TestAppContext) { diff --git a/crates/dap/src/adapters.rs b/crates/dap/src/adapters.rs index 7babb85904..96a35bc8ab 100644 --- a/crates/dap/src/adapters.rs +++ b/crates/dap/src/adapters.rs @@ -12,7 +12,7 @@ use language::{LanguageName, LanguageToolchainStore}; use node_runtime::NodeRuntime; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use settings::ProjectWorktree; +use settings::WorktreeId; use smol::fs::File; use std::{ borrow::Borrow, @@ -36,7 +36,7 @@ pub enum DapStatus { #[async_trait] pub trait DapDelegate: Send + Sync + 'static { - fn worktree_id(&self) -> ProjectWorktree; + fn worktree_id(&self) -> WorktreeId; fn worktree_root_path(&self) -> &Path; fn http_client(&self) -> Arc; fn node_runtime(&self) -> NodeRuntime; diff --git a/crates/dap_adapters/src/dap_adapters.rs b/crates/dap_adapters/src/dap_adapters.rs index 89f6347051..bc758adde6 100644 --- a/crates/dap_adapters/src/dap_adapters.rs +++ b/crates/dap_adapters/src/dap_adapters.rs @@ -59,8 +59,8 @@ mod test_mocks { #[async_trait::async_trait] impl adapters::DapDelegate for MockDelegate { - fn worktree_id(&self) -> settings::ProjectWorktree { - settings::ProjectWorktree::from_u64(0) + fn worktree_id(&self) -> settings::WorktreeId { + WorktreeId(0) } fn worktree_root_path(&self) -> &std::path::Path { diff --git a/crates/dap_adapters/src/python.rs b/crates/dap_adapters/src/python.rs index 2f84193ac9..0cbfadf609 100644 --- a/crates/dap_adapters/src/python.rs +++ b/crates/dap_adapters/src/python.rs @@ -868,7 +868,7 @@ impl DebugAdapter for PythonDebugAdapter { if let Some(found_toolchain) = delegate .toolchain_store() .active_toolchain( - delegate.worktree_id(), + delegate.worktree_id() base_path.into_arc(), language::LanguageName::new(Self::LANGUAGE_NAME), cx, diff --git a/crates/debug_adapter_extension/src/extension_dap_adapter.rs b/crates/debug_adapter_extension/src/extension_dap_adapter.rs index 073d148b67..4c1d5a0e8b 100644 --- a/crates/debug_adapter_extension/src/extension_dap_adapter.rs +++ b/crates/debug_adapter_extension/src/extension_dap_adapter.rs @@ -52,7 +52,7 @@ struct WorktreeDelegateAdapter(pub Arc); #[async_trait] impl WorktreeDelegate for WorktreeDelegateAdapter { fn id(&self) -> u64 { - self.0.worktree_id().worktree_id + self.0.worktree_id().0 as u64 } fn root_path(&self) -> String { diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index bc138d140a..82a1293939 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -37,7 +37,7 @@ use lsp::{LanguageServerId, NumberOrString}; use parking_lot::{Mutex, RawMutex, lock_api::MutexGuard}; use serde::{Deserialize, Serialize}; use serde_json::Value; -use settings::ProjectWorktree; +use settings::{ProjectWorktree, WorktreeId}; use smallvec::SmallVec; use smol::future::yield_now; use std::{ @@ -396,7 +396,7 @@ pub trait File: Send + Sync + Any { fn project_worktree(&self, cx: &App) -> ProjectWorktree; /// worktree_id - fn worktree_id(&self, cx: &App) -> u64 { + fn worktree_id(&self, cx: &App) -> WorktreeId { self.project_worktree(cx).worktree_id } diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index a3509be993..2b3ec75b60 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -294,7 +294,7 @@ impl CachedLspAdapter { pub trait LspAdapterDelegate: Send + Sync { fn show_notification(&self, message: &str, cx: &mut App); fn http_client(&self) -> Arc; - fn worktree_id(&self) -> ProjectWorktree; + fn project_worktree(&self) -> ProjectWorktree; fn worktree_root_path(&self) -> &Path; fn resolve_executable_path(&self, path: PathBuf) -> PathBuf; fn update_status(&self, language: LanguageServerName, status: BinaryStatus); diff --git a/crates/language/src/toolchain.rs b/crates/language/src/toolchain.rs index 72ae645a96..5717ffb514 100644 --- a/crates/language/src/toolchain.rs +++ b/crates/language/src/toolchain.rs @@ -10,7 +10,7 @@ use async_trait::async_trait; use collections::HashMap; use fs::Fs; use gpui::{App, AsyncApp, SharedString}; -use settings::ProjectWorktree; +use settings::WorktreeId; use task::ShellKind; use util::rel_path::RelPath; @@ -36,7 +36,7 @@ pub struct Toolchain { /// - Only in the subproject they're currently in. #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub enum ToolchainScope { - Subproject(ProjectWorktree, Arc), + Subproject(WorktreeId, Arc), Project, /// Available in all projects on this box. It wouldn't make sense to show suggestions across machines. Global, @@ -130,7 +130,7 @@ pub struct ToolchainMetadata { pub trait LanguageToolchainStore: Send + Sync + 'static { async fn active_toolchain( self: Arc, - worktree_id: ProjectWorktree, + worktree_id: WorktreeId, relative_path: Arc, language_name: LanguageName, cx: &mut AsyncApp, @@ -140,7 +140,7 @@ pub trait LanguageToolchainStore: Send + Sync + 'static { pub trait LocalLanguageToolchainStore: Send + Sync + 'static { fn active_toolchain( self: Arc, - worktree_id: ProjectWorktree, + worktree_id: WorktreeId, relative_path: &Arc, language_name: LanguageName, cx: &mut AsyncApp, @@ -151,7 +151,7 @@ pub trait LocalLanguageToolchainStore: Send + Sync + 'static { impl LanguageToolchainStore for T { async fn active_toolchain( self: Arc, - worktree_id: ProjectWorktree, + worktree_id: WorktreeId, relative_path: Arc, language_name: LanguageName, cx: &mut AsyncApp, diff --git a/crates/language_extension/src/extension_lsp_adapter.rs b/crates/language_extension/src/extension_lsp_adapter.rs index 566e6f3b36..d866034d9e 100644 --- a/crates/language_extension/src/extension_lsp_adapter.rs +++ b/crates/language_extension/src/extension_lsp_adapter.rs @@ -28,7 +28,7 @@ struct WorktreeDelegateAdapter(pub Arc); #[async_trait] impl WorktreeDelegate for WorktreeDelegateAdapter { fn id(&self) -> u64 { - self.0.worktree_id().to_proto() + self.0.project_worktree().worktree_id.to_proto() } fn root_path(&self) -> String { diff --git a/crates/languages/src/yaml.rs b/crates/languages/src/yaml.rs index 05f506df47..060f609acf 100644 --- a/crates/languages/src/yaml.rs +++ b/crates/languages/src/yaml.rs @@ -138,7 +138,7 @@ impl LspAdapter for YamlLspAdapter { cx: &mut AsyncApp, ) -> Result { let location = SettingsLocation { - worktree: delegate.worktree_id(), + worktree: delegate.project_worktree(), path: RelPath::empty(), }; diff --git a/crates/multi_buffer/src/path_key.rs b/crates/multi_buffer/src/path_key.rs index d19501e4fd..6d08462c21 100644 --- a/crates/multi_buffer/src/path_key.rs +++ b/crates/multi_buffer/src/path_key.rs @@ -29,7 +29,7 @@ impl PathKey { pub fn for_buffer(buffer: &Entity, cx: &App) -> Self { if let Some(file) = buffer.read(cx).file() { - Self::with_sort_prefix(file.project_worktree(cx).worktree_id as u64, file.path().clone()) + Self::with_sort_prefix(file.worktree_id(cx).0 as u64, file.path().clone()) } else { Self { sort_prefix: None, diff --git a/crates/project/src/agent_server_store.rs b/crates/project/src/agent_server_store.rs index d6bd83531e..c622b0463f 100644 --- a/crates/project/src/agent_server_store.rs +++ b/crates/project/src/agent_server_store.rs @@ -2054,7 +2054,7 @@ mod extension_agent_tests { async fn archive_agent_uses_extension_and_agent_id_for_cache_key(cx: &mut TestAppContext) { let fs = fs::FakeFs::new(cx.background_executor.clone()); let http_client = http_client::FakeHttpClient::with_404_response(); - let worktree_store = cx.new(|_| WorktreeStore::local(false, fs.clone())); + let worktree_store = cx.new(|_| WorktreeStore::local(0, false, fs.clone())); let project_environment = cx.new(|cx| { crate::ProjectEnvironment::new(None, worktree_store.downgrade(), None, false, cx) }); @@ -2135,7 +2135,7 @@ mod extension_agent_tests { let fs = fs::FakeFs::new(cx.background_executor.clone()); let http_client = http_client::FakeHttpClient::with_404_response(); let node_runtime = NodeRuntime::unavailable(); - let worktree_store = cx.new(|_| WorktreeStore::local(false, fs.clone())); + let worktree_store = cx.new(|_| WorktreeStore::local(0, false, fs.clone())); let project_environment = cx.new(|cx| { crate::ProjectEnvironment::new(None, worktree_store.downgrade(), None, false, cx) }); @@ -2178,7 +2178,7 @@ mod extension_agent_tests { let fs = fs::FakeFs::new(cx.background_executor.clone()); let http_client = http_client::FakeHttpClient::with_404_response(); let node_runtime = NodeRuntime::unavailable(); - let worktree_store = cx.new(|_| WorktreeStore::local(false, fs.clone())); + let worktree_store = cx.new(|_| WorktreeStore::local(0, false, fs.clone())); let project_environment = cx.new(|cx| { crate::ProjectEnvironment::new(None, worktree_store.downgrade(), None, false, cx) }); diff --git a/crates/project/src/buffer_store.rs b/crates/project/src/buffer_store.rs index 4c86dedd03..6586167fe2 100644 --- a/crates/project/src/buffer_store.rs +++ b/crates/project/src/buffer_store.rs @@ -21,11 +21,13 @@ use rpc::{ AnyProtoClient, ErrorCode, ErrorExt as _, TypedEnvelope, proto::{self}, }; +use settings::WorktreeId; use std::{io, sync::Arc, time::Instant}; use text::{BufferId, ReplicaId}; use util::{ResultExt as _, TryFutureExt, debug_panic, maybe, paths::PathStyle, rel_path::RelPath}; -use worktree::{File, PathChange, ProjectEntryId, Worktree, WorktreeId}; +use worktree::{File, PathChange, ProjectEntryId, Worktree}; + /// A set of open buffers. pub struct BufferStore { @@ -167,7 +169,7 @@ impl RemoteBufferStore { let buffer_result = maybe!({ let mut buffer_file = None; if let Some(file) = state.file.take() { - let worktree_id = worktree::WorktreeId::from_proto(file.worktree_id); + let worktree_id = WorktreeId::from_proto(file.worktree_id); let worktree = self .worktree_store .read(cx) @@ -906,7 +908,7 @@ impl BufferStore { this.update(cx, |this, cx| { old_file.clone().and_then(|file| { this.path_to_buffer_id.remove(&ProjectPath { - worktree_id: file.project_worktree(cx).into(), + worktree_id: file.worktree_id(cx), path: file.path().clone(), }) }); diff --git a/crates/project/src/context_server_store.rs b/crates/project/src/context_server_store.rs index 4f0b8228be..394de08144 100644 --- a/crates/project/src/context_server_store.rs +++ b/crates/project/src/context_server_store.rs @@ -529,7 +529,7 @@ impl ContextServerStore { .visible_worktrees(cx) .next() .map(|worktree| settings::SettingsLocation { - worktree: worktree.read(cx).id(), + worktree: worktree.read(cx).project_worktree(), path: RelPath::empty(), }); &ProjectSettings::get(location, cx).context_servers diff --git a/crates/project/src/debugger/dap_store.rs b/crates/project/src/debugger/dap_store.rs index be871cad3d..e82d7a7caa 100644 --- a/crates/project/src/debugger/dap_store.rs +++ b/crates/project/src/debugger/dap_store.rs @@ -32,7 +32,7 @@ use gpui::{App, AppContext, AsyncApp, Context, Entity, EventEmitter, SharedStrin use http_client::HttpClient; use language::{Buffer, LanguageToolchainStore}; use node_runtime::NodeRuntime; -use settings::InlayHintKind; +use settings::{InlayHintKind, WorktreeId}; use remote::RemoteClient; use rpc::{ @@ -40,7 +40,7 @@ use rpc::{ proto::{self}, }; use serde::{Deserialize, Serialize}; -use settings::{Settings, SettingsLocation, ProjectWorktree}; +use settings::{ProjectWorktree, Settings, SettingsLocation}; use std::{ borrow::Borrow, collections::BTreeMap, @@ -253,7 +253,7 @@ impl DapStore { }; let settings_location = SettingsLocation { - worktree: worktree.read(cx).id(), + worktree: worktree.read(cx).project_worktree(), path: RelPath::empty(), }; let dap_settings = ProjectSettings::get(Some(settings_location), cx) @@ -855,9 +855,10 @@ impl DapStore { let worktree = this .update(&mut cx, |this, cx| { - this.worktree_store - .read(cx) - .worktree_for_id(ProjectWorktree::from_proto(envelope.payload.worktree_id), cx) + this.worktree_store.read(cx).worktree_for_id( + WorktreeId::from_proto(envelope.payload.worktree_id), + cx, + ) })? .context("Failed to find worktree with a given ID")?; let binary = this @@ -971,7 +972,7 @@ impl DapAdapterDelegate { #[async_trait] impl dap::adapters::DapDelegate for DapAdapterDelegate { - fn worktree_id(&self) -> ProjectWorktree { + fn worktree_id(&self) -> WorktreeId { self.worktree.id() } diff --git a/crates/project/src/environment.rs b/crates/project/src/environment.rs index 0adcec1df2..b83d2d6bae 100644 --- a/crates/project/src/environment.rs +++ b/crates/project/src/environment.rs @@ -180,7 +180,7 @@ impl ProjectEnvironment { worktree .as_ref() .map(|(worktree, path)| settings::SettingsLocation { - worktree: worktree.read(cx).id(), + worktree: worktree.read(cx).project_worktree(), path: &path, }), cx, diff --git a/crates/project/src/git_store.rs b/crates/project/src/git_store.rs index 9e971a4d10..7ce4bbfbf5 100644 --- a/crates/project/src/git_store.rs +++ b/crates/project/src/git_store.rs @@ -1166,7 +1166,7 @@ impl GitStore { return; } self.update_repositories_from_worktree( - *worktree_id, + worktree_id.worktree_id, project_environment.clone(), next_repository_id.clone(), downstream diff --git a/crates/project/src/image_store.rs b/crates/project/src/image_store.rs index 71bee30b99..170a188814 100644 --- a/crates/project/src/image_store.rs +++ b/crates/project/src/image_store.rs @@ -15,8 +15,9 @@ use rpc::{AnyProtoClient, ErrorExt as _, TypedEnvelope, proto}; use std::num::NonZeroU64; use std::path::PathBuf; use std::sync::Arc; +use settings::WorktreeId; use util::{ResultExt, rel_path::RelPath}; -use worktree::{LoadedBinaryFile, PathChange, Worktree, WorktreeId}; +use worktree::{LoadedBinaryFile, PathChange, Worktree, }; #[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd, Ord, Eq)] pub struct ImageId(NonZeroU64); diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs index 5c2c1d9c65..a77d8d0763 100644 --- a/crates/project/src/lsp_store.rs +++ b/crates/project/src/lsp_store.rs @@ -94,7 +94,7 @@ use rpc::{ }; use serde::Serialize; use serde_json::Value; -use settings::{Settings, SettingsLocation, SettingsStore}; +use settings::{ProjectWorktree, Settings, SettingsLocation, SettingsStore, WorktreeId}; use sha2::{Digest, Sha256}; use smol::channel::Sender; use snippet::Snippet; @@ -134,7 +134,7 @@ pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy}; pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX; pub use worktree::{ Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId, - UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings, + UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeSettings, }; const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5); @@ -8477,7 +8477,12 @@ impl LspStore { let worktree = lsp_store .update(cx, |lsp_store, cx| { lsp_store.worktree_store.update(cx, |worktree_store, cx| { - worktree_store.create_worktree(&worktree_root_target, self.project_id_for_settings(cx), false, cx) + worktree_store.create_worktree( + &worktree_root_target, + self.project_id_for_settings(cx), + false, + cx, + ) }) })? .await?; @@ -13609,7 +13614,7 @@ pub fn language_server_settings<'a>( ) -> Option<&'a LspSettings> { language_server_settings_for( SettingsLocation { - worktree: delegate.worktree_id(), + worktree: delegate.project_worktree(), path: RelPath::empty(), }, language, @@ -13628,6 +13633,7 @@ pub(crate) fn language_server_settings_for<'a>( pub struct LocalLspAdapterDelegate { lsp_store: WeakEntity, worktree: worktree::Snapshot, + project_worktree: ProjectWorktree, fs: Arc, http_client: Arc, language_registry: Arc, @@ -13647,9 +13653,12 @@ impl LocalLspAdapterDelegate { let load_shell_env_task = environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx)); + let project_worktree = worktree.read(cx).snapshot().project_worktree(); + Arc::new(Self { lsp_store, worktree: worktree.read(cx).snapshot(), + project_worktree, fs, http_client, language_registry, @@ -13688,8 +13697,8 @@ impl LspAdapterDelegate for LocalLspAdapterDelegate { self.http_client.clone() } - fn worktree_id(&self) -> WorktreeId { - self.worktree.id() + fn project_worktree(&self) -> ProjectWorktree { + self.project_worktree } fn worktree_root_path(&self) -> &Path { diff --git a/crates/project/src/lsp_store/log_store.rs b/crates/project/src/lsp_store/log_store.rs index 80d8e781a4..8152132c93 100644 --- a/crates/project/src/lsp_store/log_store.rs +++ b/crates/project/src/lsp_store/log_store.rs @@ -8,7 +8,6 @@ use lsp::{ MessageType, TraceValue, }; use rpc::proto; -use settings::ProjectWorktree; use crate::{LanguageServerLogType, LspStore, Project, ProjectItem as _, WorktreeId}; diff --git a/crates/project/src/manifest_tree.rs b/crates/project/src/manifest_tree.rs index 72af11e79e..77add1f9bb 100644 --- a/crates/project/src/manifest_tree.rs +++ b/crates/project/src/manifest_tree.rs @@ -16,7 +16,8 @@ pub use manifest_store::ManifestProvidersStore; use path_trie::{LabelPresence, RootPathTrie, TriePath}; use settings::SettingsStore; use util::rel_path::RelPath; -use worktree::{Event as WorktreeEvent, Snapshot, Worktree, WorktreeId}; +use settings::WorktreeId; +use worktree::{Event as WorktreeEvent, Snapshot, Worktree, }; use crate::{ ProjectPath, @@ -96,7 +97,7 @@ impl ManifestTree { delegate: &Arc, cx: &mut App, ) -> Option { - debug_assert_eq!(delegate.worktree_id().worktree_id, worktree_id.to_usize() as u64); + debug_assert_eq!(delegate.worktree_id().worktree_id, *worktree_id); let (mut marked_path, mut current_presence) = (None, LabelPresence::KnownAbsent); let worktree_roots = match self.root_points.entry(*worktree_id) { Entry::Occupied(occupied_entry) => occupied_entry.get().clone(), diff --git a/crates/project/src/manifest_tree/server_tree.rs b/crates/project/src/manifest_tree/server_tree.rs index 2627eb0ed0..db291a1dfa 100644 --- a/crates/project/src/manifest_tree/server_tree.rs +++ b/crates/project/src/manifest_tree/server_tree.rs @@ -18,8 +18,7 @@ use language::{ language_settings::AllLanguageSettings, }; use lsp::LanguageServerName; -use settings::{Settings, SettingsLocation}; -use worktree::WorktreeId; +use settings::{WorktreeId,Settings, SettingsLocation}; use std::sync::OnceLock; use util::rel_path::RelPath; diff --git a/crates/project/src/prettier_store.rs b/crates/project/src/prettier_store.rs index 40deac7640..dc40cee741 100644 --- a/crates/project/src/prettier_store.rs +++ b/crates/project/src/prettier_store.rs @@ -22,13 +22,11 @@ use lsp::{LanguageServer, LanguageServerId, LanguageServerName}; use node_runtime::NodeRuntime; use paths::default_prettier_dir; use prettier::Prettier; +use settings::WorktreeId; use smol::stream::StreamExt; use util::{ResultExt, TryFutureExt, rel_path::RelPath}; -use crate::{ - File, PathChange, ProjectEntryId, Worktree, lsp_store::WorktreeId, - worktree_store::WorktreeStore, -}; +use crate::{File, PathChange, ProjectEntryId, Worktree, worktree_store::WorktreeStore}; pub struct PrettierStore { node: NodeRuntime, diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 3dbfc2b451..1d9adaa639 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -104,7 +104,7 @@ use rpc::{ }; use search::{SearchInputKind, SearchQuery, SearchResult}; use search_history::SearchHistory; -use settings::{InvalidSettingsError, RegisterSetting, Settings, SettingsLocation, SettingsStore}; +use settings::{InvalidSettingsError, RegisterSetting, Settings, SettingsLocation, SettingsStore, WorktreeId}; use smol::channel::Receiver; use snippet::Snippet; pub use snippet_provider; @@ -133,7 +133,7 @@ use util::{ use worktree::{CreatedEntry, Snapshot, Traversal}; pub use worktree::{ Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId, - UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings, + UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeSettings, }; use worktree_store::{WorktreeStore, WorktreeStoreEvent}; @@ -367,7 +367,7 @@ pub struct ProjectPath { impl ProjectPath { pub fn from_file(value: &dyn language::File, cx: &App) -> Self { ProjectPath { - worktree_id: WorktreeId(value.project_worktree(cx).worktree_id as usize), + worktree_id: value.project_worktree(cx).worktree_id, path: value.path().clone(), } } @@ -1520,6 +1520,7 @@ impl Project { WorktreeStore::remote( true, client.clone().into(), + self.id, response.payload.project_id, path_style, ) @@ -5507,7 +5508,7 @@ impl ProjectItem for Buffer { fn project_path(&self, cx: &App) -> Option { self.file().map(|file| ProjectPath { - worktree_id: file.project_worktree(cx).worktree_id(), + worktree_id: file.project_worktree(cx).worktree_id.into(), path: file.path().clone(), }) } diff --git a/crates/project/src/project_settings.rs b/crates/project/src/project_settings.rs index 2ba99d0093..6da3e9c536 100644 --- a/crates/project/src/project_settings.rs +++ b/crates/project/src/project_settings.rs @@ -21,12 +21,12 @@ pub use settings::DirenvSettings; pub use settings::LspSettings; use settings::{ DapSettingsContent, InvalidSettingsError, LocalSettingsKind, RegisterSetting, Settings, - SettingsLocation, SettingsStore, parse_json_with_comments, watch_config_file, + SettingsLocation, SettingsStore, WorktreeId, parse_json_with_comments, watch_config_file, }; use std::{path::PathBuf, sync::Arc, time::Duration}; use task::{DebugTaskFile, TaskTemplates, VsCodeDebugTaskFile, VsCodeTaskFile}; use util::{ResultExt, rel_path::RelPath, serde::default_true}; -use worktree::{PathChange, UpdatedEntriesSet, Worktree, WorktreeId}; +use worktree::{PathChange, UpdatedEntriesSet, Worktree}; use crate::{ task_store::{TaskSettingsLocation, TaskStore}, @@ -702,8 +702,8 @@ impl SettingsObserver { let store = cx.global::(); for worktree in self.worktree_store.read(cx).worktrees() { - let worktree_id = worktree.read(cx).id().to_proto(); - for (path, content) in store.local_settings(worktree.read(cx).id()) { + let worktree_id = worktree.read(cx).id(); + for (path, content) in store.local_settings(worktree_id.with_project_id(project_id)) { let content = serde_json::to_string(&content).unwrap(); downstream_client .send(proto::UpdateWorktreeSettings { diff --git a/crates/project/src/task_inventory.rs b/crates/project/src/task_inventory.rs index 8dad4369e1..c3f32904a0 100644 --- a/crates/project/src/task_inventory.rs +++ b/crates/project/src/task_inventory.rs @@ -19,6 +19,7 @@ use language::{ }; use lsp::{LanguageServerId, LanguageServerName}; use paths::{debug_task_file_name, task_file_name}; +use settings::WorktreeId; use settings::{InvalidSettingsError, parse_json_with_comments}; use task::{ DebugScenario, ResolvedTask, TaskContext, TaskId, TaskTemplate, TaskTemplates, TaskVariables, @@ -26,7 +27,6 @@ use task::{ }; use text::{BufferId, Point, ToPoint}; use util::{NumericPrefixWithSuffix, ResultExt as _, post_inc, rel_path::RelPath}; -use worktree::WorktreeId; use crate::{task_store::TaskSettingsLocation, worktree_store::WorktreeStore}; @@ -682,8 +682,9 @@ impl Inventory { TaskSettingsLocation::Worktree(location) => { let new_templates = new_templates.collect::>(); if new_templates.is_empty() { - if let Some(worktree_tasks) = - parsed_templates.worktree.get_mut(&WorktreeId(location.worktree.worktree_id as usize)) + if let Some(worktree_tasks) = parsed_templates + .worktree + .get_mut(&WorktreeId(location.worktree.worktree_id as usize)) { worktree_tasks.remove(location.path); } @@ -848,8 +849,8 @@ fn task_variables_preference(task: &ResolvedTask) -> Reverse { mod test_inventory { use gpui::{AppContext as _, Entity, Task, TestAppContext}; use itertools::Itertools; + use settings::WorktreeId; use task::TaskContext; - use worktree::WorktreeId; use crate::Inventory; @@ -1397,8 +1398,8 @@ mod tests { init_test(cx); let inventory = cx.update(|cx| Inventory::new(cx)); let common_name = "common_task_name"; - let worktree_1 = WorktreeId::from_usize(1); - let worktree_2 = WorktreeId::from_usize(2); + let worktree_1 = WorktreeId::from_usize(1).with_project_id(0); + let worktree_2 = WorktreeId::from_usize(2).with_project_id(0); cx.run_until_parked(); let worktree_independent_tasks = vec![ @@ -1427,7 +1428,7 @@ mod tests { let worktree_1_tasks = [ ( TaskSourceKind::Worktree { - id: worktree_1, + id: worktree_1.worktree_id, directory_in_worktree: rel_path(".zed").into(), id_base: "local worktree tasks from directory \".zed\"".into(), }, @@ -1435,7 +1436,7 @@ mod tests { ), ( TaskSourceKind::Worktree { - id: worktree_1, + id: worktree_1.worktree_id, directory_in_worktree: rel_path(".zed").into(), id_base: "local worktree tasks from directory \".zed\"".into(), }, @@ -1445,7 +1446,7 @@ mod tests { let worktree_2_tasks = [ ( TaskSourceKind::Worktree { - id: worktree_2, + id: worktree_2.worktree_id, directory_in_worktree: rel_path(".zed").into(), id_base: "local worktree tasks from directory \".zed\"".into(), }, @@ -1453,7 +1454,7 @@ mod tests { ), ( TaskSourceKind::Worktree { - id: worktree_2, + id: worktree_2.worktree_id, directory_in_worktree: rel_path(".zed").into(), id_base: "local worktree tasks from directory \".zed\"".into(), }, @@ -1502,7 +1503,7 @@ mod tests { "Without a worktree, only worktree-independent tasks should be listed" ); assert_eq!( - list_tasks_sorted_by_last_used(&inventory, Some(worktree_1), cx).await, + list_tasks_sorted_by_last_used(&inventory, Some(worktree_1.worktree_id), cx).await, worktree_1_tasks .iter() .chain(worktree_independent_tasks.iter()) @@ -1511,7 +1512,7 @@ mod tests { .collect::>(), ); assert_eq!( - list_tasks_sorted_by_last_used(&inventory, Some(worktree_2), cx).await, + list_tasks_sorted_by_last_used(&inventory, Some(worktree_2.worktree_id), cx).await, worktree_2_tasks .iter() .chain(worktree_independent_tasks.iter()) @@ -1526,7 +1527,7 @@ mod tests { "Without a worktree, only worktree-independent tasks should be listed" ); assert_eq!( - list_tasks(&inventory, Some(worktree_1), cx).await, + list_tasks(&inventory, Some(worktree_1.worktree_id), cx).await, worktree_1_tasks .iter() .chain(worktree_independent_tasks.iter()) @@ -1534,7 +1535,7 @@ mod tests { .collect::>(), ); assert_eq!( - list_tasks(&inventory, Some(worktree_2), cx).await, + list_tasks(&inventory, Some(worktree_2.worktree_id), cx).await, worktree_2_tasks .iter() .chain(worktree_independent_tasks.iter()) diff --git a/crates/project/src/toolchain_store.rs b/crates/project/src/toolchain_store.rs index 186c92e1ea..0ef7e02377 100644 --- a/crates/project/src/toolchain_store.rs +++ b/crates/project/src/toolchain_store.rs @@ -19,10 +19,9 @@ use rpc::{ resolve_toolchain_response::Response as ResolveResponsePayload, }, }; -use settings::ProjectWorktree; +use settings::{ProjectWorktree, WorktreeId}; use task::Shell; use util::{ResultExt as _, rel_path::RelPath}; -use worktree::WorktreeId; use crate::{ ProjectEnvironment, ProjectPath, @@ -399,7 +398,7 @@ pub struct LocalToolchainStore { languages: Arc, worktree_store: Entity, project_environment: Entity, - active_toolchains: BTreeMap<(ProjectWorktree, LanguageName), BTreeMap, Toolchain>>, + active_toolchains: BTreeMap<(WorktreeId, LanguageName), BTreeMap, Toolchain>>, manifest_tree: Entity, fs: Arc, } @@ -408,7 +407,7 @@ pub struct LocalToolchainStore { impl language::LocalLanguageToolchainStore for LocalStore { fn active_toolchain( self: Arc, - worktree_id: ProjectWorktree, + worktree_id: WorktreeId, path: &Arc, language_name: LanguageName, cx: &mut AsyncApp, @@ -425,14 +424,14 @@ impl language::LocalLanguageToolchainStore for LocalStore { impl language::LanguageToolchainStore for RemoteStore { async fn active_toolchain( self: Arc, - worktree_id: ProjectWorktree, + worktree_id: WorktreeId, path: Arc, language_name: LanguageName, cx: &mut AsyncApp, ) -> Option { self.0 .update(cx, |this, cx| { - this.active_toolchain(ProjectPath { worktree_id, path }, language_name, cx) + this.active_toolchain(ProjectPath { worktree_id: worktree_id.worktree_id, path }, language_name, cx) }) .ok()? .await @@ -443,7 +442,7 @@ pub struct EmptyToolchainStore; impl language::LocalLanguageToolchainStore for EmptyToolchainStore { fn active_toolchain( self: Arc, - _: ProjectWorktree, + _: WorktreeId, _: &Arc, _: LanguageName, _: &mut AsyncApp, diff --git a/crates/project/src/worktree_store.rs b/crates/project/src/worktree_store.rs index c0d288931f..4357db5593 100644 --- a/crates/project/src/worktree_store.rs +++ b/crates/project/src/worktree_store.rs @@ -17,6 +17,7 @@ use rpc::{ AnyProtoClient, ErrorExt, TypedEnvelope, proto::{self, REMOTE_SERVER_PROJECT_ID}, }; +use settings::WorktreeId; use smol::{ channel::{Receiver, Sender}, stream::StreamExt, @@ -29,7 +30,7 @@ use util::{ }; use worktree::{ CreatedEntry, Entry, ProjectEntryId, UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, - WorktreeId, WorktreeSettings, + WorktreeSettings, }; use crate::{ProjectPath, search::SearchQuery}; @@ -52,6 +53,7 @@ enum WorktreeStoreState { } pub struct WorktreeStore { + project_id: u64, next_entry_id: Arc, downstream_client: Option<(AnyProtoClient, u64)>, retain_worktrees: bool, @@ -86,8 +88,9 @@ impl WorktreeStore { client.add_entity_request_handler(Self::handle_expand_all_for_project_entry); } - pub fn local(retain_worktrees: bool, fs: Arc) -> Self { + pub fn local(project_id: u64, retain_worktrees: bool, fs: Arc) -> Self { Self { + project_id, next_entry_id: Default::default(), loading_worktrees: Default::default(), downstream_client: None, @@ -101,10 +104,12 @@ impl WorktreeStore { pub fn remote( retain_worktrees: bool, upstream_client: AnyProtoClient, + local_project_id: u64, upstream_project_id: u64, path_style: PathStyle, ) -> Self { Self { + project_id: local_project_id, next_entry_id: Default::default(), loading_worktrees: Default::default(), downstream_client: None, @@ -197,7 +202,7 @@ impl WorktreeStore { if let Some((tree, relative_path)) = self.find_worktree(abs_path, cx) { Task::ready(Ok((tree, relative_path))) } else { - let worktree = self.create_worktree(abs_path, visible, cx); + let worktree = self.create_worktree(abs_path, visible, cx); cx.background_spawn(async move { Ok((worktree.await?, RelPath::empty().into())) }) } } @@ -463,7 +468,6 @@ impl WorktreeStore { pub fn create_worktree( &mut self, abs_path: impl AsRef, - project_id_for_settings: u64, visible: bool, cx: &mut Context, ) -> Task>> { @@ -479,12 +483,20 @@ impl WorktreeStore { Task::ready(Err(Arc::new(anyhow!("cannot create worktrees via collab")))) } else { let abs_path = RemotePathBuf::new(abs_path.to_string(), *path_style); - self.create_remote_worktree(upstream_client.clone(), project_id_for_settings, abs_path, visible, cx) + self.create_remote_worktree( + upstream_client.clone(), + abs_path, + visible, + cx, + ) } } - WorktreeStoreState::Local { fs } => { - self.create_local_worktree(fs.clone(), project_id_for_settings, abs_path.clone(), visible, cx) - } + WorktreeStoreState::Local { fs } => self.create_local_worktree( + fs.clone(), + abs_path.clone(), + visible, + cx, + ), }; self.loading_worktrees @@ -528,7 +540,7 @@ impl WorktreeStore { let path = RemotePathBuf::new(abs_path, path_style); let response = client .request(proto::AddWorktree { - project_id: REMOTE_SERVER_PROJECT_ID, + project_id: self.project_id, path: path.to_proto(), visible, }) @@ -548,7 +560,7 @@ impl WorktreeStore { let worktree = cx.update(|cx| { Worktree::remote( - REMOTE_SERVER_PROJECT_ID, + self.project_id, ReplicaId::REMOTE_SERVER, proto::WorktreeMetadata { id: response.worktree_id, diff --git a/crates/remote_server/src/headless_project.rs b/crates/remote_server/src/headless_project.rs index f5cce907f9..46cc065461 100644 --- a/crates/remote_server/src/headless_project.rs +++ b/crates/remote_server/src/headless_project.rs @@ -92,7 +92,7 @@ impl HeadlessProject { languages::init(languages.clone(), fs.clone(), node_runtime.clone(), cx); let worktree_store = cx.new(|cx| { - let mut store = WorktreeStore::local(true, fs.clone()); + let mut store = WorktreeStore::local(REMOTE_SERVER_PROJECT_ID, true, fs.clone()); store.shared(REMOTE_SERVER_PROJECT_ID, session.clone(), cx); store }); diff --git a/crates/settings/src/settings.rs b/crates/settings/src/settings.rs index 61c4328af0..fade8477de 100644 --- a/crates/settings/src/settings.rs +++ b/crates/settings/src/settings.rs @@ -20,7 +20,7 @@ pub mod private { use gpui::{App, Global}; use rust_embed::RustEmbed; -use std::{borrow::Cow, str}; +use std::{borrow::Cow, fmt, str}; use util::asset_str; pub use base_keymap_setting::*; @@ -46,10 +46,50 @@ pub struct ActiveSettingsProfileName(pub String); impl Global for ActiveSettingsProfileName {} +/// Worktree ID within a project. Prefer [`ProjectWorktree`] when something globally unique is needed. +/// +/// These are usually globally unique, but not always (particularly with remote projects). +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord, serde::Serialize)] +pub struct WorktreeId(pub usize); + +impl From for usize { + fn from(value: WorktreeId) -> Self { + value.0 + } +} + +impl WorktreeId { + pub fn from_usize(handle_id: usize) -> Self { + Self(handle_id) + } + + pub fn from_proto(id: u64) -> Self { + Self(id as usize) + } + + pub fn to_proto(self) -> u64 { + self.0 as u64 + } + + pub fn to_usize(self) -> usize { + self.0 + } + pub fn with_project_id(self, project_id: u64) -> ProjectWorktree { + ProjectWorktree { + project_id, + worktree_id: self, + } + } +} + +/// `worktree_id` and the `project_id` it belongs to. +/// +/// `worktree_id` is usually globally unique, but sometimes only unique within a +/// project (e.g., when remoting). #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord, serde::Serialize)] pub struct ProjectWorktree { pub project_id: u64, - pub worktree_id: u64, + pub worktree_id: WorktreeId, } impl ProjectWorktree { @@ -57,11 +97,17 @@ impl ProjectWorktree { pub fn from_u64(n: u64) -> Self { Self { project_id: 0, - worktree_id: n, + worktree_id: WorktreeId(n as usize), } } } +impl fmt::Display for WorktreeId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + std::fmt::Display::fmt(&self.0, f) + } +} + #[derive(RustEmbed)] #[folder = "../../assets"] #[include = "settings/*"] diff --git a/crates/settings/src/settings_store.rs b/crates/settings/src/settings_store.rs index 8874c8a077..4b49ed005d 100644 --- a/crates/settings/src/settings_store.rs +++ b/crates/settings/src/settings_store.rs @@ -32,7 +32,8 @@ pub type EditorconfigProperties = ec4rs::Properties; use crate::{ ActiveSettingsProfileName, FontFamilyName, IconThemeName, LanguageSettingsContent, - LanguageToSettingsMap, ThemeName, VsCodeSettings, ProjectWorktree, fallible_options, + LanguageToSettingsMap, ProjectWorktree, ThemeName, VsCodeSettings, + fallible_options, merge_from::MergeFrom, settings_content::{ ExtensionsSettingsContent, ProjectSettingsContent, SettingsContent, UserSettingsContent, @@ -150,7 +151,8 @@ pub struct SettingsStore { merged_settings: Rc, local_settings: BTreeMap<(ProjectWorktree, Arc), SettingsContent>, - raw_editorconfig_settings: BTreeMap<(ProjectWorktree, Arc), (String, Option)>, + raw_editorconfig_settings: + BTreeMap<(ProjectWorktree, Arc), (String, Option)>, _setting_file_updates: Task<()>, setting_file_updates_tx: @@ -246,7 +248,12 @@ pub trait AnySettingValue: 'static + Send + Sync { fn value_for_path(&self, path: Option) -> &dyn Any; fn all_local_values(&self) -> Vec<(ProjectWorktree, Arc, &dyn Any)>; fn set_global_value(&mut self, value: Box); - fn set_local_value(&mut self, root_id: ProjectWorktree, path: Arc, value: Box); + fn set_local_value( + &mut self, + root_id: ProjectWorktree, + path: Arc, + value: Box, + ); } /// Parameters that are used when generating some JSON schemas at runtime. @@ -980,13 +987,8 @@ impl SettingsStore { root_id: ProjectWorktree, ) -> impl '_ + Iterator, &ProjectSettingsContent)> { self.local_settings - .range( - (root_id, RelPath::empty().into()) - ..( - ProjectWorktree{ project_id: root_id.project_id, worktree_id: root_id.worktree_id + 1}, - RelPath::empty().into(), - ), - ) + .range((root_id, RelPath::empty().into())..) + .take_while(move |((project_worktree, _), _)| *project_worktree == root_id) .map(|((_, path), content)| (path.clone(), &content.project)) } @@ -995,13 +997,8 @@ impl SettingsStore { root_id: ProjectWorktree, ) -> impl '_ + Iterator, String, Option)> { self.raw_editorconfig_settings - .range( - (root_id, RelPath::empty().into()) - ..( - ProjectWorktree{ project_id: root_id.project_id, worktree_id: root_id.worktree_id + 1}, - RelPath::empty().into(), - ), - ) + .range((root_id, RelPath::empty().into())..) + .take_while(move |((project_worktree, _), _)| *project_worktree == root_id) .map(|((_, path), (content, parsed_content))| { (path.clone(), content.clone(), parsed_content.clone()) }) @@ -1310,7 +1307,11 @@ impl AnySettingValue for SettingValue { } fn value_for_path(&self, path: Option) -> &dyn Any { - if let Some(SettingsLocation { worktree: worktree_id, path }) = path { + if let Some(SettingsLocation { + worktree: worktree_id, + path, + }) = path + { for (settings_root_id, settings_path, value) in self.local_values.iter().rev() { if worktree_id == *settings_root_id && path.starts_with(settings_path) { return value; @@ -1327,7 +1328,12 @@ impl AnySettingValue for SettingValue { self.global_value = Some(*value.downcast().unwrap()); } - fn set_local_value(&mut self, root_id: ProjectWorktree, path: Arc, value: Box) { + fn set_local_value( + &mut self, + root_id: ProjectWorktree, + path: Arc, + value: Box, + ) { let value = *value.downcast().unwrap(); match self .local_values @@ -1344,7 +1350,8 @@ mod tests { use std::num::NonZeroU32; use crate::{ - ClosePosition, ItemSettingsContent, VsCodeSettingsSource, default_settings, settings_content::LanguageSettingsContent, test_settings + ClosePosition, ItemSettingsContent, VsCodeSettingsSource, WorktreeId, default_settings, + settings_content::LanguageSettingsContent, test_settings, }; use super::*; @@ -1449,7 +1456,10 @@ mod tests { ClosePosition::Left ); - let worktree = ProjectWorktree { project_id: 1, worktree_id: 1 }; + let worktree = ProjectWorktree { + project_id: 1, + worktree_id: WorktreeId(1), + }; store .set_local_settings( @@ -2132,7 +2142,6 @@ mod tests { let mut store = SettingsStore::new(cx, &test_settings()); store.register_setting::(); - let wt0_root = (ProjectWorktree::from_u64(0), RelPath::empty().into_arc()); let wt0_child1 = (ProjectWorktree::from_u64(0), rel_path("child1").into_arc()); let wt0_child2 = (ProjectWorktree::from_u64(0), rel_path("child2").into_arc()); diff --git a/crates/worktree/src/worktree.rs b/crates/worktree/src/worktree.rs index c9985ac6fb..37ce9804a6 100644 --- a/crates/worktree/src/worktree.rs +++ b/crates/worktree/src/worktree.rs @@ -38,7 +38,7 @@ use rpc::{ AnyProtoClient, proto::{self, split_worktree_update}, }; -use settings::{ProjectWorktree, Settings, SettingsLocation, SettingsStore}; +use settings::{ProjectWorktree, Settings, SettingsLocation, SettingsStore, WorktreeId}; use smallvec::{SmallVec, smallvec}; use smol::channel::{self, Sender}; use std::{ @@ -71,45 +71,6 @@ pub use worktree_settings::WorktreeSettings; pub const FS_WATCH_LATENCY: Duration = Duration::from_millis(100); -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord, serde::Serialize)] -pub struct WorktreeId(pub usize); - -impl From for usize { - fn from(value: WorktreeId) -> Self { - value.0 - } -} - -impl WorktreeId { - pub fn from_usize(handle_id: usize) -> Self { - Self(handle_id) - } - - pub fn from_proto(id: u64) -> Self { - Self(id as usize) - } - - pub fn to_proto(self) -> u64 { - self.0 as u64 - } - - pub fn to_usize(self) -> usize { - self.0 - } -} - -impl From for WorktreeId { - fn from(value: ProjectWorktree) -> Self { - Self(value.worktree_id as usize) - } -} - -impl fmt::Display for WorktreeId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - std::fmt::Display::fmt(&self.0, f) - } -} - /// A set of local or remote files that are being opened as part of a project. /// Responsible for tracking related FS (for local)/collab (for remote) events and corresponding updates. /// Stores git repositories data and the diagnostics for the file(s). @@ -535,7 +496,7 @@ impl Worktree { let worktree_id = snapshot.id(); let settings_location = Some(SettingsLocation { worktree: settings::ProjectWorktree { - worktree_id: worktree_id.to_proto(), + worktree_id, project_id: project_id_for_settings, }, path: RelPath::empty(), @@ -658,7 +619,7 @@ impl Worktree { SettingsLocation { worktree: ProjectWorktree { project_id: self.project_id_for_settings, - worktree_id: self.id.to_proto(), + worktree_id: self.id, }, path: RelPath::empty(), } @@ -2110,7 +2071,7 @@ impl Snapshot { pub fn project_worktree(&self) -> ProjectWorktree { ProjectWorktree { - worktree_id: self.id.0 as u64, + worktree_id: self.id, project_id: self.project_id_for_settings, } }