From dfcc143ead1a544a4bae09a158024f83f868450f Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 11 Mar 2024 11:35:27 -0700 Subject: [PATCH] Rename 'project_core' crate to 'worktree', make it just about worktrees (#9189) This is just a refactor. I noticed that we now have a `project_core` crate, which mainly contains the `Worktree` type and its private helpers, plus the project's settings. In this PR, I've renamed that crate to `worktree` and did some minor simplification to its module structure. I also extracted a new `WorktreeSettings` settings type from the `ProjectSettings`, so that the worktree settings could live in the worktree crate. This way, the crate is now exclusively about worktree logic. Release Notes: - N/A --- Cargo.lock | 71 ++++++++------- Cargo.toml | 4 +- crates/collab/src/tests/following_tests.rs | 6 +- crates/editor/src/editor.rs | 2 +- crates/extension/Cargo.toml | 1 + crates/extension/src/build_extension.rs | 14 +-- crates/file_finder/src/file_finder_tests.rs | 2 +- crates/project/Cargo.toml | 7 +- crates/project/src/project.rs | 14 ++- .../src/project_settings.rs | 19 ---- crates/project/src/project_tests.rs | 1 + crates/project/src/task_inventory.rs | 4 +- crates/project_core/src/lib.rs | 81 ----------------- crates/project_panel/src/project_panel.rs | 18 ++-- .../src/semantic_index_tests.rs | 4 +- crates/{project_core => worktree}/Cargo.toml | 7 +- crates/{project_core => worktree}/LICENSE-GPL | 0 .../{project_core => worktree}/src/ignore.rs | 0 .../src/worktree.rs | 91 +++++++++++++++++-- crates/worktree/src/worktree_settings.rs | 40 ++++++++ .../src/worktree_tests.rs | 15 ++- crates/zed/src/zed.rs | 4 +- 22 files changed, 215 insertions(+), 190 deletions(-) rename crates/{project_core => project}/src/project_settings.rs (78%) delete mode 100644 crates/project_core/src/lib.rs rename crates/{project_core => worktree}/Cargo.toml (91%) rename crates/{project_core => worktree}/LICENSE-GPL (100%) rename crates/{project_core => worktree}/src/ignore.rs (100%) rename crates/{project_core => worktree}/src/worktree.rs (98%) create mode 100644 crates/worktree/src/worktree_settings.rs rename crates/{project_core => worktree}/src/worktree_tests.rs (99%) diff --git a/Cargo.lock b/Cargo.lock index cd9230a9c7..c515fff45c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7225,11 +7225,11 @@ dependencies = [ "postage", "prettier", "pretty_assertions", - "project_core", "rand 0.8.5", "regex", "release_channel", "rpc", + "schemars", "serde", "serde_json", "settings", @@ -7242,40 +7242,7 @@ dependencies = [ "unindent", "util", "which 6.0.0", -] - -[[package]] -name = "project_core" -version = "0.1.0" -dependencies = [ - "anyhow", - "client", - "clock", - "collections", - "fs", - "futures 0.3.28", - "fuzzy", - "git", - "git2", - "gpui", - "ignore", - "itertools 0.11.0", - "language", - "log", - "lsp", - "parking_lot 0.11.2", - "postage", - "pretty_assertions", - "rand 0.8.5", - "rpc", - "schemars", - "serde", - "serde_json", - "settings", - "smol", - "sum_tree", - "text", - "util", + "worktree", ] [[package]] @@ -12497,6 +12464,40 @@ dependencies = [ "uuid", ] +[[package]] +name = "worktree" +version = "0.1.0" +dependencies = [ + "anyhow", + "client", + "clock", + "collections", + "fs", + "futures 0.3.28", + "fuzzy", + "git", + "git2", + "gpui", + "ignore", + "itertools 0.11.0", + "language", + "log", + "lsp", + "parking_lot 0.11.2", + "postage", + "pretty_assertions", + "rand 0.8.5", + "rpc", + "schemars", + "serde", + "serde_json", + "settings", + "smol", + "sum_tree", + "text", + "util", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index ae8d2c5247..daba782b13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,7 +54,6 @@ members = [ "crates/picker", "crates/prettier", "crates/project", - "crates/project_core", "crates/project_panel", "crates/project_symbols", "crates/quick_action_bar", @@ -90,6 +89,7 @@ members = [ "crates/vim", "crates/welcome", "crates/workspace", + "crates/worktree", "crates/zed", "crates/zed_actions", @@ -159,7 +159,7 @@ plugin = { path = "crates/plugin" } plugin_macros = { path = "crates/plugin_macros" } prettier = { path = "crates/prettier" } project = { path = "crates/project" } -project_core = { path = "crates/project_core" } +worktree = { path = "crates/worktree" } project_panel = { path = "crates/project_panel" } project_symbols = { path = "crates/project_symbols" } quick_action_bar = { path = "crates/quick_action_bar" } diff --git a/crates/collab/src/tests/following_tests.rs b/crates/collab/src/tests/following_tests.rs index 0dff43e41b..db63ddf202 100644 --- a/crates/collab/src/tests/following_tests.rs +++ b/crates/collab/src/tests/following_tests.rs @@ -12,7 +12,7 @@ use gpui::{ }; use language::Capability; use live_kit_client::MacOSDisplay; -use project::project_settings::ProjectSettings; +use project::WorktreeSettings; use rpc::proto::PeerId; use serde_json::json; use settings::SettingsStore; @@ -1646,8 +1646,8 @@ async fn test_following_into_excluded_file( for cx in [&mut cx_a, &mut cx_b] { cx.update(|cx| { cx.update_global::(|store, cx| { - store.update_user_settings::(cx, |project_settings| { - project_settings.file_scan_exclusions = Some(vec!["**/.git".to_string()]); + store.update_user_settings::(cx, |settings| { + settings.file_scan_exclusions = Some(vec!["**/.git".to_string()]); }); }); }); diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index e747d0d286..bd4fccf4a9 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -3245,7 +3245,7 @@ impl Editor { .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty()) .filter_map(|(buffer_handle, excerpt_visible_range, excerpt_id)| { let buffer = buffer_handle.read(cx); - let buffer_file = project::worktree::File::from_dyn(buffer.file())?; + let buffer_file = project::File::from_dyn(buffer.file())?; let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?; let worktree_entry = buffer_worktree .read(cx) diff --git a/crates/extension/Cargo.toml b/crates/extension/Cargo.toml index ce5ea85480..51df62068e 100644 --- a/crates/extension/Cargo.toml +++ b/crates/extension/Cargo.toml @@ -10,6 +10,7 @@ workspace = true [lib] path = "src/extension_store.rs" +doctest = false [[bin]] name = "extension_json_schemas" diff --git a/crates/extension/src/build_extension.rs b/crates/extension/src/build_extension.rs index 8d19544571..0e1408d886 100644 --- a/crates/extension/src/build_extension.rs +++ b/crates/extension/src/build_extension.rs @@ -260,13 +260,6 @@ impl ExtensionBuilder { .args(["fetch", "--depth", "1", "origin", &rev]) .output() .context("failed to execute `git fetch`")?; - if !fetch_output.status.success() { - bail!( - "failed to fetch revision {} in directory '{}'", - rev, - directory.display() - ); - } let checkout_output = Command::new("git") .arg("--git-dir") @@ -276,6 +269,13 @@ impl ExtensionBuilder { .output() .context("failed to execute `git checkout`")?; if !checkout_output.status.success() { + if !fetch_output.status.success() { + bail!( + "failed to fetch revision {} in directory '{}'", + rev, + directory.display() + ); + } bail!( "failed to checkout revision {} in directory '{}'", rev, diff --git a/crates/file_finder/src/file_finder_tests.rs b/crates/file_finder/src/file_finder_tests.rs index 8342677d38..179cd2ca6a 100644 --- a/crates/file_finder/src/file_finder_tests.rs +++ b/crates/file_finder/src/file_finder_tests.rs @@ -4,7 +4,7 @@ use super::*; use editor::Editor; use gpui::{Entity, TestAppContext, VisualTestContext}; use menu::{Confirm, SelectNext}; -use project::worktree::FS_WATCH_LATENCY; +use project::FS_WATCH_LATENCY; use serde_json::json; use workspace::{AppState, Workspace}; diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index 875ebb2de4..ae0f78a686 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -19,7 +19,7 @@ test-support = [ "settings/test-support", "text/test-support", "prettier/test-support", - "project_core/test-support", + "worktree/test-support", "gpui/test-support", ] @@ -44,10 +44,11 @@ node_runtime.workspace = true parking_lot.workspace = true postage.workspace = true prettier.workspace = true -project_core.workspace = true +worktree.workspace = true rand.workspace = true regex.workspace = true rpc.workspace = true +schemars.workspace = true task.workspace = true serde.workspace = true serde_json.workspace = true @@ -72,7 +73,7 @@ release_channel.workspace = true lsp = { workspace = true, features = ["test-support"] } prettier = { workspace = true, features = ["test-support"] } pretty_assertions.workspace = true -project_core = { workspace = true, features = ["test-support"] } +worktree = { workspace = true, features = ["test-support"] } rpc = { workspace = true, features = ["test-support"] } settings = { workspace = true, features = ["test-support"] } unindent.workspace = true diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 733590709a..b3b13bd0ba 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -2,6 +2,7 @@ pub mod debounced_delay; pub mod lsp_command; pub mod lsp_ext_command; mod prettier_support; +pub mod project_settings; pub mod search; mod task_inventory; pub mod terminals; @@ -56,9 +57,9 @@ use node_runtime::NodeRuntime; use parking_lot::{Mutex, RwLock}; use postage::watch; use prettier_support::{DefaultPrettier, PrettierInstance}; -use project_core::project_settings::{LspSettings, ProjectSettings}; -pub use project_core::{DiagnosticSummary, ProjectEntryId}; +use project_settings::{LspSettings, ProjectSettings}; use rand::prelude::*; +use worktree::LocalSnapshot; use rpc::{ErrorCode, ErrorExt as _}; use search::SearchQuery; @@ -96,16 +97,20 @@ use util::{ paths::{LOCAL_SETTINGS_RELATIVE_PATH, LOCAL_TASKS_RELATIVE_PATH}, post_inc, ResultExt, TryFutureExt as _, }; +use worktree::{Snapshot, Traversal}; pub use fs::*; pub use language::Location; #[cfg(any(test, feature = "test-support"))] pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX; -pub use project_core::project_settings; -pub use project_core::worktree::{self, *}; #[cfg(feature = "test-support")] pub use task_inventory::test_inventory::*; pub use task_inventory::{Inventory, TaskSourceKind}; +pub use worktree::{ + DiagnosticSummary, Entry, EntryKind, File, LocalWorktree, PathChange, ProjectEntryId, + RepositoryEntry, UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, + WorktreeSettings, FS_WATCH_LATENCY, +}; const MAX_SERVER_REINSTALL_ATTEMPT_COUNT: u64 = 4; const SERVER_REINSTALL_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1); @@ -492,6 +497,7 @@ impl SearchMatchCandidate { impl Project { pub fn init_settings(cx: &mut AppContext) { + WorktreeSettings::register(cx); ProjectSettings::register(cx); } diff --git a/crates/project_core/src/project_settings.rs b/crates/project/src/project_settings.rs similarity index 78% rename from crates/project_core/src/project_settings.rs rename to crates/project/src/project_settings.rs index 835ca61e7d..2d659725a7 100644 --- a/crates/project_core/src/project_settings.rs +++ b/crates/project/src/project_settings.rs @@ -20,25 +20,6 @@ pub struct ProjectSettings { /// Configuration for Git-related features #[serde(default)] pub git: GitSettings, - - /// Completely ignore files matching globs from `file_scan_exclusions` - /// - /// Default: [ - /// "**/.git", - /// "**/.svn", - /// "**/.hg", - /// "**/CVS", - /// "**/.DS_Store", - /// "**/Thumbs.db", - /// "**/.classpath", - /// "**/.settings" - /// ] - #[serde(default)] - pub file_scan_exclusions: Option>, - - /// Treat the files matching these globs as `.env` files. - /// Default: [ "**/.env*" ] - pub private_files: Option>, } #[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index c513b9a2c4..1a6bf5d64f 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -14,6 +14,7 @@ use serde_json::json; use std::{os, task::Poll}; use unindent::Unindent as _; use util::{assert_set_eq, paths::PathMatcher, test::temp_tree}; +use worktree::WorktreeModelHandle as _; #[gpui::test] async fn test_block_via_channel(cx: &mut gpui::TestAppContext) { diff --git a/crates/project/src/task_inventory.rs b/crates/project/src/task_inventory.rs index b51cdf2ba4..991d47554a 100644 --- a/crates/project/src/task_inventory.rs +++ b/crates/project/src/task_inventory.rs @@ -9,9 +9,9 @@ use std::{ use collections::{HashMap, VecDeque}; use gpui::{AppContext, Context, Model, ModelContext, Subscription}; use itertools::Itertools; -use project_core::worktree::WorktreeId; use task::{Task, TaskContext, TaskId, TaskSource}; use util::{post_inc, NumericPrefixWithSuffix}; +use worktree::WorktreeId; /// Inventory tracks available tasks for a given project. pub struct Inventory { @@ -230,8 +230,8 @@ pub mod test_inventory { use std::{path::Path, sync::Arc}; use gpui::{AppContext, Context as _, Model, ModelContext, TestAppContext}; - use project_core::worktree::WorktreeId; use task::{Task, TaskContext, TaskId, TaskSource}; + use worktree::WorktreeId; use crate::Inventory; diff --git a/crates/project_core/src/lib.rs b/crates/project_core/src/lib.rs deleted file mode 100644 index ffba767a2e..0000000000 --- a/crates/project_core/src/lib.rs +++ /dev/null @@ -1,81 +0,0 @@ -use std::path::Path; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering::SeqCst; - -use language::DiagnosticEntry; -use lsp::{DiagnosticSeverity, LanguageServerId}; -use rpc::proto; -use serde::Serialize; - -mod ignore; -pub mod project_settings; -pub mod worktree; -#[cfg(test)] -mod worktree_tests; - -#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct ProjectEntryId(usize); - -impl ProjectEntryId { - pub const MAX: Self = Self(usize::MAX); - - pub fn new(counter: &AtomicUsize) -> Self { - Self(counter.fetch_add(1, SeqCst)) - } - - 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 - } -} - -#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)] -pub struct DiagnosticSummary { - pub error_count: usize, - pub warning_count: usize, -} - -impl DiagnosticSummary { - fn new<'a, T: 'a>(diagnostics: impl IntoIterator>) -> Self { - let mut this = Self { - error_count: 0, - warning_count: 0, - }; - - for entry in diagnostics { - if entry.diagnostic.is_primary { - match entry.diagnostic.severity { - DiagnosticSeverity::ERROR => this.error_count += 1, - DiagnosticSeverity::WARNING => this.warning_count += 1, - _ => {} - } - } - } - - this - } - - pub fn is_empty(&self) -> bool { - self.error_count == 0 && self.warning_count == 0 - } - - pub fn to_proto( - &self, - language_server_id: LanguageServerId, - path: &Path, - ) -> proto::DiagnosticSummary { - proto::DiagnosticSummary { - path: path.to_string_lossy().to_string(), - language_server_id: language_server_id.0 as u64, - error_count: self.error_count as u32, - warning_count: self.warning_count as u32, - } - } -} diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 3b2bd7a9f9..76b51a8ef1 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1717,7 +1717,7 @@ mod tests { use collections::HashSet; use gpui::{TestAppContext, View, VisualTestContext, WindowHandle}; use pretty_assertions::assert_eq; - use project::{project_settings::ProjectSettings, FakeFs}; + use project::{FakeFs, WorktreeSettings}; use serde_json::json; use settings::SettingsStore; use std::path::{Path, PathBuf}; @@ -1819,8 +1819,8 @@ mod tests { init_test(cx); cx.update(|cx| { cx.update_global::(|store, cx| { - store.update_user_settings::(cx, |project_settings| { - project_settings.file_scan_exclusions = + store.update_user_settings::(cx, |worktree_settings| { + worktree_settings.file_scan_exclusions = Some(vec!["**/.git".to_string(), "**/4/**".to_string()]); }); }); @@ -3026,8 +3026,8 @@ mod tests { init_test_with_editor(cx); cx.update(|cx| { cx.update_global::(|store, cx| { - store.update_user_settings::(cx, |project_settings| { - project_settings.file_scan_exclusions = Some(Vec::new()); + store.update_user_settings::(cx, |worktree_settings| { + worktree_settings.file_scan_exclusions = Some(Vec::new()); }); store.update_user_settings::(cx, |project_panel_settings| { project_panel_settings.auto_reveal_entries = Some(false) @@ -3264,8 +3264,8 @@ mod tests { init_test_with_editor(cx); cx.update(|cx| { cx.update_global::(|store, cx| { - store.update_user_settings::(cx, |project_settings| { - project_settings.file_scan_exclusions = Some(Vec::new()); + store.update_user_settings::(cx, |worktree_settings| { + worktree_settings.file_scan_exclusions = Some(Vec::new()); }); store.update_user_settings::(cx, |project_panel_settings| { project_panel_settings.auto_reveal_entries = Some(false) @@ -3582,8 +3582,8 @@ mod tests { Project::init_settings(cx); cx.update_global::(|store, cx| { - store.update_user_settings::(cx, |project_settings| { - project_settings.file_scan_exclusions = Some(Vec::new()); + store.update_user_settings::(cx, |worktree_settings| { + worktree_settings.file_scan_exclusions = Some(Vec::new()); }); }); }); diff --git a/crates/semantic_index/src/semantic_index_tests.rs b/crates/semantic_index/src/semantic_index_tests.rs index f660aa8fb3..48ceabdb63 100644 --- a/crates/semantic_index/src/semantic_index_tests.rs +++ b/crates/semantic_index/src/semantic_index_tests.rs @@ -10,7 +10,7 @@ use gpui::{Task, TestAppContext}; use language::{Language, LanguageConfig, LanguageMatcher, LanguageRegistry, ToOffset}; use parking_lot::Mutex; use pretty_assertions::assert_eq; -use project::{project_settings::ProjectSettings, FakeFs, Fs, Project}; +use project::{FakeFs, Fs, Project}; use rand::{rngs::StdRng, Rng}; use serde_json::json; use settings::{Settings, SettingsStore}; @@ -1720,6 +1720,6 @@ fn init_test(cx: &mut TestAppContext) { let settings_store = SettingsStore::test(cx); cx.set_global(settings_store); SemanticIndexSettings::register(cx); - ProjectSettings::register(cx); + Project::init_settings(cx); }); } diff --git a/crates/project_core/Cargo.toml b/crates/worktree/Cargo.toml similarity index 91% rename from crates/project_core/Cargo.toml rename to crates/worktree/Cargo.toml index b82e9a26eb..ce1c27e03a 100644 --- a/crates/project_core/Cargo.toml +++ b/crates/worktree/Cargo.toml @@ -1,14 +1,17 @@ [package] -name = "project_core" +name = "worktree" version = "0.1.0" edition = "2021" publish = false license = "GPL-3.0-or-later" +[lib] +path = "src/worktree.rs" +doctest = false + [lints] workspace = true -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] test-support = [ "client/test-support", diff --git a/crates/project_core/LICENSE-GPL b/crates/worktree/LICENSE-GPL similarity index 100% rename from crates/project_core/LICENSE-GPL rename to crates/worktree/LICENSE-GPL diff --git a/crates/project_core/src/ignore.rs b/crates/worktree/src/ignore.rs similarity index 100% rename from crates/project_core/src/ignore.rs rename to crates/worktree/src/ignore.rs diff --git a/crates/project_core/src/worktree.rs b/crates/worktree/src/worktree.rs similarity index 98% rename from crates/project_core/src/worktree.rs rename to crates/worktree/src/worktree.rs index 8c64ab2579..4302754dca 100644 --- a/crates/project_core/src/worktree.rs +++ b/crates/worktree/src/worktree.rs @@ -1,6 +1,8 @@ -use crate::{ - ignore::IgnoreStack, project_settings::ProjectSettings, DiagnosticSummary, ProjectEntryId, -}; +mod ignore; +mod worktree_settings; +#[cfg(test)] +mod worktree_tests; + use ::ignore::gitignore::{Gitignore, GitignoreBuilder}; use anyhow::{anyhow, Context as _, Result}; use client::{proto, Client}; @@ -26,6 +28,7 @@ use gpui::{ AppContext, AsyncAppContext, BackgroundExecutor, Context, EventEmitter, Model, ModelContext, Task, }; +use ignore::IgnoreStack; use itertools::Itertools; use language::{ proto::{ @@ -35,13 +38,14 @@ use language::{ Buffer, Capability, DiagnosticEntry, File as _, LineEnding, PointUtf16, Rope, RopeFingerprint, Unclipped, }; -use lsp::LanguageServerId; +use lsp::{DiagnosticSeverity, LanguageServerId}; use parking_lot::Mutex; use postage::{ barrier, prelude::{Sink as _, Stream as _}, watch, }; +use serde::Serialize; use settings::{Settings, SettingsStore}; use smol::channel::{self, Sender}; use std::{ @@ -68,10 +72,12 @@ use util::{ ResultExt, }; +pub use worktree_settings::WorktreeSettings; + #[cfg(feature = "test-support")] pub const FS_WATCH_LATENCY: Duration = Duration::from_millis(100); #[cfg(not(feature = "test-support"))] -const FS_WATCH_LATENCY: Duration = Duration::from_millis(100); +pub const FS_WATCH_LATENCY: Duration = Duration::from_millis(100); #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)] pub struct WorktreeId(usize); @@ -340,13 +346,13 @@ impl Worktree { cx.observe_global::(move |this, cx| { if let Self::Local(this) = this { let new_file_scan_exclusions = path_matchers( - ProjectSettings::get_global(cx) + WorktreeSettings::get_global(cx) .file_scan_exclusions .as_deref(), "file_scan_exclusions", ); let new_private_files = path_matchers( - ProjectSettings::get(Some((cx.handle().entity_id().as_u64() as usize, &Path::new(""))), cx).private_files.as_deref(), + WorktreeSettings::get(Some((cx.handle().entity_id().as_u64() as usize, &Path::new(""))), cx).private_files.as_deref(), "private_files", ); @@ -396,13 +402,13 @@ impl Worktree { let mut snapshot = LocalSnapshot { file_scan_exclusions: path_matchers( - ProjectSettings::get_global(cx) + WorktreeSettings::get_global(cx) .file_scan_exclusions .as_deref(), "file_scan_exclusions", ), private_files: path_matchers( - ProjectSettings::get(Some((cx.handle().entity_id().as_u64() as usize, &Path::new(""))), cx).private_files.as_deref(), + WorktreeSettings::get(Some((cx.handle().entity_id().as_u64() as usize, &Path::new(""))), cx).private_files.as_deref(), "private_files", ), ignores_by_parent_abs_path: Default::default(), @@ -4737,3 +4743,70 @@ fn git_status_to_proto(status: GitFileStatus) -> i32 { GitFileStatus::Conflict => proto::GitStatus::Conflict as i32, } } + +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct ProjectEntryId(usize); + +impl ProjectEntryId { + pub const MAX: Self = Self(usize::MAX); + + pub fn new(counter: &AtomicUsize) -> Self { + Self(counter.fetch_add(1, SeqCst)) + } + + 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 + } +} + +#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)] +pub struct DiagnosticSummary { + pub error_count: usize, + pub warning_count: usize, +} + +impl DiagnosticSummary { + fn new<'a, T: 'a>(diagnostics: impl IntoIterator>) -> Self { + let mut this = Self { + error_count: 0, + warning_count: 0, + }; + + for entry in diagnostics { + if entry.diagnostic.is_primary { + match entry.diagnostic.severity { + DiagnosticSeverity::ERROR => this.error_count += 1, + DiagnosticSeverity::WARNING => this.warning_count += 1, + _ => {} + } + } + } + + this + } + + pub fn is_empty(&self) -> bool { + self.error_count == 0 && self.warning_count == 0 + } + + pub fn to_proto( + &self, + language_server_id: LanguageServerId, + path: &Path, + ) -> proto::DiagnosticSummary { + proto::DiagnosticSummary { + path: path.to_string_lossy().to_string(), + language_server_id: language_server_id.0 as u64, + error_count: self.error_count as u32, + warning_count: self.warning_count as u32, + } + } +} diff --git a/crates/worktree/src/worktree_settings.rs b/crates/worktree/src/worktree_settings.rs new file mode 100644 index 0000000000..432e274cf2 --- /dev/null +++ b/crates/worktree/src/worktree_settings.rs @@ -0,0 +1,40 @@ +use gpui::AppContext; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use settings::Settings; + +#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)] +pub struct WorktreeSettings { + /// Completely ignore files matching globs from `file_scan_exclusions` + /// + /// Default: [ + /// "**/.git", + /// "**/.svn", + /// "**/.hg", + /// "**/CVS", + /// "**/.DS_Store", + /// "**/Thumbs.db", + /// "**/.classpath", + /// "**/.settings" + /// ] + #[serde(default)] + pub file_scan_exclusions: Option>, + + /// Treat the files matching these globs as `.env` files. + /// Default: [ "**/.env*" ] + pub private_files: Option>, +} + +impl Settings for WorktreeSettings { + const KEY: Option<&'static str> = None; + + type FileContent = Self; + + fn load( + default_value: &Self::FileContent, + user_values: &[&Self::FileContent], + _: &mut AppContext, + ) -> anyhow::Result { + Self::load_via_json_merge(default_value, user_values) + } +} diff --git a/crates/project_core/src/worktree_tests.rs b/crates/worktree/src/worktree_tests.rs similarity index 99% rename from crates/project_core/src/worktree_tests.rs rename to crates/worktree/src/worktree_tests.rs index 71ba4a525e..52b1d09296 100644 --- a/crates/project_core/src/worktree_tests.rs +++ b/crates/worktree/src/worktree_tests.rs @@ -1,7 +1,6 @@ use crate::{ - project_settings::ProjectSettings, - worktree::{Entry, EntryKind, PathChange, Worktree}, - worktree::{Event, Snapshot, WorktreeModelHandle}, + worktree_settings::WorktreeSettings, Entry, EntryKind, Event, PathChange, Snapshot, Worktree, + WorktreeModelHandle, }; use anyhow::Result; use client::Client; @@ -804,7 +803,7 @@ async fn test_rescan_with_gitignore(cx: &mut TestAppContext) { init_test(cx); cx.update(|cx| { cx.update_global::(|store, cx| { - store.update_user_settings::(cx, |project_settings| { + store.update_user_settings::(cx, |project_settings| { project_settings.file_scan_exclusions = Some(Vec::new()); }); }); @@ -996,7 +995,7 @@ async fn test_file_scan_exclusions(cx: &mut TestAppContext) { })); cx.update(|cx| { cx.update_global::(|store, cx| { - store.update_user_settings::(cx, |project_settings| { + store.update_user_settings::(cx, |project_settings| { project_settings.file_scan_exclusions = Some(vec!["**/foo/**".to_string(), "**/.DS_Store".to_string()]); }); @@ -1033,7 +1032,7 @@ async fn test_file_scan_exclusions(cx: &mut TestAppContext) { cx.update(|cx| { cx.update_global::(|store, cx| { - store.update_user_settings::(cx, |project_settings| { + store.update_user_settings::(cx, |project_settings| { project_settings.file_scan_exclusions = Some(vec!["**/node_modules/**".to_string()]); }); @@ -1097,7 +1096,7 @@ async fn test_fs_events_in_exclusions(cx: &mut TestAppContext) { })); cx.update(|cx| { cx.update_global::(|store, cx| { - store.update_user_settings::(cx, |project_settings| { + store.update_user_settings::(cx, |project_settings| { project_settings.file_scan_exclusions = Some(vec![ "**/.git".to_string(), "node_modules/".to_string(), @@ -2541,6 +2540,6 @@ fn init_test(cx: &mut gpui::TestAppContext) { cx.update(|cx| { let settings_store = SettingsStore::test(cx); cx.set_global(settings_store); - ProjectSettings::register(cx); + WorktreeSettings::register(cx); }); } diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 04481dd0be..ea3f0b1974 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -866,7 +866,7 @@ mod tests { VisualTestContext, WindowHandle, }; use language::{LanguageMatcher, LanguageRegistry}; - use project::{project_settings::ProjectSettings, Project, ProjectPath}; + use project::{Project, ProjectPath, WorktreeSettings}; use serde_json::json; use settings::{handle_settings_file_changes, watch_config_file, SettingsStore}; use std::path::{Path, PathBuf}; @@ -1480,7 +1480,7 @@ mod tests { let app_state = init_test(cx); cx.update(|cx| { cx.update_global::(|store, cx| { - store.update_user_settings::(cx, |project_settings| { + store.update_user_settings::(cx, |project_settings| { project_settings.file_scan_exclusions = Some(vec!["excluded_dir".to_string(), "**/.git".to_string()]); });