settings: Load `.zed/settings.json` even if .gitignored (#13370)

Thorsten Ball and Bennet created

This fixes #4432 by ensuring that we scan & watch the `.zed` folder,
just like we watch the `.git`, for changes.

Release Notes:

- Settings are now loaded from local `.zed/settings.json` files even if
they are `.gitignore`d.
([#4432](https://github.com/zed-industries/zed/issues/4432)).

Co-authored-by: Bennet <bennet@zed.dev>

Change summary

Cargo.lock                      | 1 +
crates/paths/src/paths.rs       | 6 ++++++
crates/worktree/Cargo.toml      | 1 +
crates/worktree/src/worktree.rs | 2 ++
4 files changed, 10 insertions(+)

Detailed changes

Cargo.lock 🔗

@@ -13082,6 +13082,7 @@ dependencies = [
  "language",
  "log",
  "parking_lot",
+ "paths",
  "postage",
  "pretty_assertions",
  "rand 0.8.5",

crates/paths/src/paths.rs 🔗

@@ -224,6 +224,12 @@ pub fn default_prettier_dir() -> &'static PathBuf {
     DEFAULT_PRETTIER_DIR.get_or_init(|| support_dir().join("prettier"))
 }
 
+/// Returns the relative path to a `.zed` folder within a project.
+pub fn local_settings_folder_relative_path() -> &'static Path {
+    static LOCAL_SETTINGS_FOLDER_RELATIVE_PATH: OnceLock<&Path> = OnceLock::new();
+    LOCAL_SETTINGS_FOLDER_RELATIVE_PATH.get_or_init(|| Path::new(".zed"))
+}
+
 /// Returns the relative path to a `settings.json` file within a project.
 pub fn local_settings_file_relative_path() -> &'static Path {
     static LOCAL_SETTINGS_FILE_RELATIVE_PATH: OnceLock<&Path> = OnceLock::new();

crates/worktree/Cargo.toml 🔗

@@ -34,6 +34,7 @@ ignore.workspace = true
 language.workspace = true
 log.workspace = true
 parking_lot.workspace = true
+paths.workspace = true
 postage.workspace = true
 rpc.workspace = true
 schemars.workspace = true

crates/worktree/src/worktree.rs 🔗

@@ -31,6 +31,7 @@ use gpui::{
 };
 use ignore::IgnoreStack;
 use parking_lot::Mutex;
+use paths::local_settings_folder_relative_path;
 use postage::{
     barrier,
     prelude::{Sink as _, Stream as _},
@@ -2589,6 +2590,7 @@ impl BackgroundScannerState {
     fn should_scan_directory(&self, entry: &Entry) -> bool {
         (!entry.is_external && !entry.is_ignored)
             || entry.path.file_name() == Some(*DOT_GIT)
+            || entry.path.file_name() == Some(local_settings_folder_relative_path().as_os_str())
             || self.scanned_dirs.contains(&entry.id) // If we've ever scanned it, keep scanning
             || self
                 .paths_to_scan