global gitignore handling in the background scanner
This commit is contained in:
parent
8b0203e177
commit
3119d0d06e
5 changed files with 167 additions and 61 deletions
|
@ -131,7 +131,7 @@ pub trait Fs: Send + Sync {
|
||||||
Arc<dyn Watcher>,
|
Arc<dyn Watcher>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn home_dir(&self) -> Option<PathBuf>;
|
// fn home_dir(&self) -> Option<PathBuf>;
|
||||||
fn open_repo(&self, abs_dot_git: &Path) -> Option<Arc<dyn GitRepository>>;
|
fn open_repo(&self, abs_dot_git: &Path) -> Option<Arc<dyn GitRepository>>;
|
||||||
fn git_init(&self, abs_work_directory: &Path, fallback_branch_name: String) -> Result<()>;
|
fn git_init(&self, abs_work_directory: &Path, fallback_branch_name: String) -> Result<()>;
|
||||||
fn global_git_ignore_path(&self, abs_work_directory: &Path) -> Option<PathBuf>;
|
fn global_git_ignore_path(&self, abs_work_directory: &Path) -> Option<PathBuf>;
|
||||||
|
@ -876,9 +876,9 @@ impl Fs for RealFs {
|
||||||
case_sensitive
|
case_sensitive
|
||||||
}
|
}
|
||||||
|
|
||||||
fn home_dir(&self) -> Option<PathBuf> {
|
// fn home_dir(&self) -> Option<PathBuf> {
|
||||||
Some(paths::home_dir().clone())
|
// Some(paths::home_dir().clone())
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
|
#[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
|
||||||
|
@ -912,7 +912,7 @@ struct FakeFsState {
|
||||||
metadata_call_count: usize,
|
metadata_call_count: usize,
|
||||||
read_dir_call_count: usize,
|
read_dir_call_count: usize,
|
||||||
moves: std::collections::HashMap<u64, PathBuf>,
|
moves: std::collections::HashMap<u64, PathBuf>,
|
||||||
home_dir: Option<PathBuf>,
|
// home_dir: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
|
@ -1098,7 +1098,7 @@ impl FakeFs {
|
||||||
read_dir_call_count: 0,
|
read_dir_call_count: 0,
|
||||||
metadata_call_count: 0,
|
metadata_call_count: 0,
|
||||||
moves: Default::default(),
|
moves: Default::default(),
|
||||||
home_dir: None,
|
// home_dir: None,
|
||||||
})),
|
})),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1744,10 +1744,6 @@ impl FakeFs {
|
||||||
fn simulate_random_delay(&self) -> impl futures::Future<Output = ()> {
|
fn simulate_random_delay(&self) -> impl futures::Future<Output = ()> {
|
||||||
self.executor.simulate_random_delay()
|
self.executor.simulate_random_delay()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_home_dir(&self, home_dir: PathBuf) {
|
|
||||||
self.state.lock().home_dir = Some(home_dir);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
|
@ -2350,9 +2346,9 @@ impl Fs for FakeFs {
|
||||||
self.this.upgrade().unwrap()
|
self.this.upgrade().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn home_dir(&self) -> Option<PathBuf> {
|
// fn home_dir(&self) -> Option<PathBuf> {
|
||||||
self.state.lock().home_dir.clone()
|
// self.state.lock().home_dir.clone()
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chunks(rope: &Rope, line_ending: LineEnding) -> impl Iterator<Item = &str> {
|
fn chunks(rope: &Rope, line_ending: LineEnding) -> impl Iterator<Item = &str> {
|
||||||
|
|
|
@ -7578,9 +7578,9 @@ async fn test_home_dir_as_git_repository(cx: &mut gpui::TestAppContext) {
|
||||||
init_test(cx);
|
init_test(cx);
|
||||||
let fs = FakeFs::new(cx.background_executor.clone());
|
let fs = FakeFs::new(cx.background_executor.clone());
|
||||||
fs.insert_tree(
|
fs.insert_tree(
|
||||||
path!("/root"),
|
path!("/home"),
|
||||||
json!({
|
json!({
|
||||||
"home": {
|
"zed": {
|
||||||
".git": {},
|
".git": {},
|
||||||
"project": {
|
"project": {
|
||||||
"a.txt": "A"
|
"a.txt": "A"
|
||||||
|
@ -7589,9 +7589,8 @@ async fn test_home_dir_as_git_repository(cx: &mut gpui::TestAppContext) {
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
fs.set_home_dir(Path::new(path!("/root/home")).to_owned());
|
|
||||||
|
|
||||||
let project = Project::test(fs.clone(), [path!("/root/home/project").as_ref()], cx).await;
|
let project = Project::test(fs.clone(), [path!("/home/zed/project").as_ref()], cx).await;
|
||||||
let tree = project.read_with(cx, |project, cx| project.worktrees(cx).next().unwrap());
|
let tree = project.read_with(cx, |project, cx| project.worktrees(cx).next().unwrap());
|
||||||
let tree_id = tree.read_with(cx, |tree, _| tree.id());
|
let tree_id = tree.read_with(cx, |tree, _| tree.id());
|
||||||
|
|
||||||
|
@ -7608,7 +7607,7 @@ async fn test_home_dir_as_git_repository(cx: &mut gpui::TestAppContext) {
|
||||||
assert!(containing.is_none());
|
assert!(containing.is_none());
|
||||||
});
|
});
|
||||||
|
|
||||||
let project = Project::test(fs.clone(), [path!("/root/home").as_ref()], cx).await;
|
let project = Project::test(fs.clone(), [path!("/home/zed").as_ref()], cx).await;
|
||||||
let tree = project.read_with(cx, |project, cx| project.worktrees(cx).next().unwrap());
|
let tree = project.read_with(cx, |project, cx| project.worktrees(cx).next().unwrap());
|
||||||
let tree_id = tree.read_with(cx, |tree, _| tree.id());
|
let tree_id = tree.read_with(cx, |tree, _| tree.id());
|
||||||
project
|
project
|
||||||
|
@ -7628,7 +7627,7 @@ async fn test_home_dir_as_git_repository(cx: &mut gpui::TestAppContext) {
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.work_directory_abs_path
|
.work_directory_abs_path
|
||||||
.as_ref(),
|
.as_ref(),
|
||||||
Path::new(path!("/root/home"))
|
Path::new(path!("/home/zed"))
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,13 @@ use crate::NumericPrefixWithSuffix;
|
||||||
/// Returns the path to the user's home directory.
|
/// Returns the path to the user's home directory.
|
||||||
pub fn home_dir() -> &'static PathBuf {
|
pub fn home_dir() -> &'static PathBuf {
|
||||||
static HOME_DIR: OnceLock<PathBuf> = OnceLock::new();
|
static HOME_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||||
HOME_DIR.get_or_init(|| dirs::home_dir().expect("failed to determine home directory"))
|
HOME_DIR.get_or_init(|| {
|
||||||
|
if cfg!(test) {
|
||||||
|
PathBuf::from("/home/zed")
|
||||||
|
} else {
|
||||||
|
dirs::home_dir().expect("failed to determine home directory")
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PathExt {
|
pub trait PathExt {
|
||||||
|
|
|
@ -4,6 +4,9 @@ use std::{ffi::OsStr, path::Path, sync::Arc};
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum IgnoreStack {
|
pub enum IgnoreStack {
|
||||||
None,
|
None,
|
||||||
|
Global {
|
||||||
|
ignore: Arc<Gitignore>,
|
||||||
|
},
|
||||||
Some {
|
Some {
|
||||||
abs_base_path: Arc<Path>,
|
abs_base_path: Arc<Path>,
|
||||||
ignore: Arc<Gitignore>,
|
ignore: Arc<Gitignore>,
|
||||||
|
@ -21,6 +24,10 @@ impl IgnoreStack {
|
||||||
Arc::new(Self::All)
|
Arc::new(Self::All)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn global(ignore: Arc<Gitignore>) -> Arc<Self> {
|
||||||
|
Arc::new(Self::Global { ignore })
|
||||||
|
}
|
||||||
|
|
||||||
pub fn append(self: Arc<Self>, abs_base_path: Arc<Path>, ignore: Arc<Gitignore>) -> Arc<Self> {
|
pub fn append(self: Arc<Self>, abs_base_path: Arc<Path>, ignore: Arc<Gitignore>) -> Arc<Self> {
|
||||||
match self.as_ref() {
|
match self.as_ref() {
|
||||||
IgnoreStack::All => self,
|
IgnoreStack::All => self,
|
||||||
|
@ -40,6 +47,11 @@ impl IgnoreStack {
|
||||||
match self {
|
match self {
|
||||||
Self::None => false,
|
Self::None => false,
|
||||||
Self::All => true,
|
Self::All => true,
|
||||||
|
Self::Global { ignore } => match ignore.matched(abs_path, is_dir) {
|
||||||
|
ignore::Match::None => false,
|
||||||
|
ignore::Match::Ignore(_) => true,
|
||||||
|
ignore::Match::Whitelist(_) => false,
|
||||||
|
},
|
||||||
Self::Some {
|
Self::Some {
|
||||||
abs_base_path,
|
abs_base_path,
|
||||||
ignore,
|
ignore,
|
||||||
|
|
|
@ -3,7 +3,7 @@ mod worktree_settings;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod worktree_tests;
|
mod worktree_tests;
|
||||||
|
|
||||||
use ::ignore::gitignore::{Gitignore, GitignoreBuilder};
|
use ::ignore::gitignore::{Gitignore, GitignoreBuilder, gitconfig_excludes_path};
|
||||||
use anyhow::{Context as _, Result, anyhow};
|
use anyhow::{Context as _, Result, anyhow};
|
||||||
use clock::ReplicaId;
|
use clock::ReplicaId;
|
||||||
use collections::{HashMap, HashSet, VecDeque};
|
use collections::{HashMap, HashSet, VecDeque};
|
||||||
|
@ -65,7 +65,7 @@ use std::{
|
||||||
use sum_tree::{Bias, Edit, KeyedItem, SeekTarget, SumTree, Summary, TreeMap, TreeSet, Unit};
|
use sum_tree::{Bias, Edit, KeyedItem, SeekTarget, SumTree, Summary, TreeMap, TreeSet, Unit};
|
||||||
use text::{LineEnding, Rope};
|
use text::{LineEnding, Rope};
|
||||||
use util::{
|
use util::{
|
||||||
ResultExt,
|
ResultExt, path,
|
||||||
paths::{PathMatcher, SanitizedPath, home_dir},
|
paths::{PathMatcher, SanitizedPath, home_dir},
|
||||||
};
|
};
|
||||||
pub use worktree_settings::WorktreeSettings;
|
pub use worktree_settings::WorktreeSettings;
|
||||||
|
@ -356,6 +356,7 @@ impl From<ProjectEntryId> for WorkDirectoryEntry {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LocalSnapshot {
|
pub struct LocalSnapshot {
|
||||||
snapshot: Snapshot,
|
snapshot: Snapshot,
|
||||||
|
global_gitignore: Option<Arc<Gitignore>>,
|
||||||
/// All of the gitignore files in the worktree, indexed by their relative path.
|
/// All of the gitignore files in the worktree, indexed by their relative path.
|
||||||
/// The boolean indicates whether the gitignore needs to be updated.
|
/// The boolean indicates whether the gitignore needs to be updated.
|
||||||
ignores_by_parent_abs_path: HashMap<Arc<Path>, (Arc<Gitignore>, bool)>,
|
ignores_by_parent_abs_path: HashMap<Arc<Path>, (Arc<Gitignore>, bool)>,
|
||||||
|
@ -510,6 +511,7 @@ impl Worktree {
|
||||||
cx.new(move |cx: &mut Context<Worktree>| {
|
cx.new(move |cx: &mut Context<Worktree>| {
|
||||||
let mut snapshot = LocalSnapshot {
|
let mut snapshot = LocalSnapshot {
|
||||||
ignores_by_parent_abs_path: Default::default(),
|
ignores_by_parent_abs_path: Default::default(),
|
||||||
|
global_gitignore: Default::default(),
|
||||||
git_repositories: Default::default(),
|
git_repositories: Default::default(),
|
||||||
snapshot: Snapshot::new(
|
snapshot: Snapshot::new(
|
||||||
cx.entity_id().as_u64(),
|
cx.entity_id().as_u64(),
|
||||||
|
@ -2803,11 +2805,20 @@ impl LocalSnapshot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ancestor.join(*DOT_GIT).exists() {
|
if ancestor.join(*DOT_GIT).exists() {
|
||||||
|
// FIXME HERE
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut ignore_stack = IgnoreStack::none();
|
// FIXME the plan for global
|
||||||
|
// - the abs_base_path for the ignore is ""
|
||||||
|
// - match relative to dot git parent using existing stripping logic
|
||||||
|
// - global variant??
|
||||||
|
let mut ignore_stack = if let Some(global_gitignore) = self.global_gitignore.clone() {
|
||||||
|
IgnoreStack::global(global_gitignore)
|
||||||
|
} else {
|
||||||
|
IgnoreStack::none()
|
||||||
|
};
|
||||||
for (parent_abs_path, ignore) in new_ignores.into_iter().rev() {
|
for (parent_abs_path, ignore) in new_ignores.into_iter().rev() {
|
||||||
if ignore_stack.is_abs_path_ignored(parent_abs_path, true) {
|
if ignore_stack.is_abs_path_ignored(parent_abs_path, true) {
|
||||||
ignore_stack = IgnoreStack::all();
|
ignore_stack = IgnoreStack::all();
|
||||||
|
@ -3870,6 +3881,26 @@ impl BackgroundScanner {
|
||||||
|
|
||||||
log::trace!("containing git repository: {containing_git_repository:?}");
|
log::trace!("containing git repository: {containing_git_repository:?}");
|
||||||
|
|
||||||
|
let global_gitignore_path = global_gitignore_path();
|
||||||
|
self.state.lock().snapshot.global_gitignore =
|
||||||
|
if let Some(global_gitignore_path) = global_gitignore_path.as_ref() {
|
||||||
|
build_gitignore(global_gitignore_path, self.fs.as_ref())
|
||||||
|
.await
|
||||||
|
.log_err()
|
||||||
|
.map(Arc::new)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let mut global_gitignore_events = if let Some(global_gitignore_path) = global_gitignore_path
|
||||||
|
{
|
||||||
|
self.fs
|
||||||
|
.watch(&global_gitignore_path, FS_WATCH_LATENCY)
|
||||||
|
.await
|
||||||
|
.0
|
||||||
|
} else {
|
||||||
|
Box::pin(futures::stream::empty())
|
||||||
|
};
|
||||||
|
|
||||||
let (scan_job_tx, scan_job_rx) = channel::unbounded();
|
let (scan_job_tx, scan_job_rx) = channel::unbounded();
|
||||||
{
|
{
|
||||||
let mut state = self.state.lock();
|
let mut state = self.state.lock();
|
||||||
|
@ -3952,6 +3983,15 @@ impl BackgroundScanner {
|
||||||
}
|
}
|
||||||
self.process_events(paths.into_iter().map(Into::into).collect()).await;
|
self.process_events(paths.into_iter().map(Into::into).collect()).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
paths = global_gitignore_events.next().fuse() => {
|
||||||
|
match paths.as_deref() {
|
||||||
|
Some([event, ..]) => {
|
||||||
|
self.update_global_gitignore(&event.path).await;
|
||||||
|
}
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4151,6 +4191,30 @@ impl BackgroundScanner {
|
||||||
self.send_status_update(false, SmallVec::new());
|
self.send_status_update(false, SmallVec::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn update_global_gitignore(&self, abs_path: &Path) {
|
||||||
|
let ignore = build_gitignore(abs_path, self.fs.as_ref())
|
||||||
|
.await
|
||||||
|
.log_err()
|
||||||
|
.map(Arc::new);
|
||||||
|
let (prev_snapshot, ignore_stack, abs_path) = {
|
||||||
|
let mut state = self.state.lock();
|
||||||
|
state.snapshot.global_gitignore = ignore;
|
||||||
|
// FIXME is_dir (do we care?)
|
||||||
|
let abs_path = state.snapshot.abs_path().clone();
|
||||||
|
let ignore_stack = state.snapshot.ignore_stack_for_abs_path(&abs_path, true);
|
||||||
|
(state.snapshot.clone(), ignore_stack, abs_path)
|
||||||
|
};
|
||||||
|
let (scan_job_tx, scan_job_rx) = channel::unbounded();
|
||||||
|
self.update_ignore_statuses_for_paths(
|
||||||
|
scan_job_tx,
|
||||||
|
prev_snapshot,
|
||||||
|
vec![(abs_path, ignore_stack)].into_iter(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
self.scan_dirs(false, scan_job_rx).await;
|
||||||
|
self.send_status_update(false, SmallVec::new());
|
||||||
|
}
|
||||||
|
|
||||||
async fn forcibly_load_paths(&self, paths: &[Arc<Path>]) -> bool {
|
async fn forcibly_load_paths(&self, paths: &[Arc<Path>]) -> bool {
|
||||||
let (scan_job_tx, scan_job_rx) = channel::unbounded();
|
let (scan_job_tx, scan_job_rx) = channel::unbounded();
|
||||||
{
|
{
|
||||||
|
@ -4622,43 +4686,15 @@ impl BackgroundScanner {
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update_ignore_statuses(&self, scan_job_tx: Sender<ScanJob>) {
|
async fn update_ignore_statuses_for_paths(
|
||||||
let mut ignores_to_update = Vec::new();
|
&self,
|
||||||
|
scan_job_tx: Sender<ScanJob>,
|
||||||
|
prev_snapshot: LocalSnapshot,
|
||||||
|
mut ignores_to_update: impl Iterator<Item = (Arc<Path>, Arc<IgnoreStack>)>,
|
||||||
|
) {
|
||||||
let (ignore_queue_tx, ignore_queue_rx) = channel::unbounded();
|
let (ignore_queue_tx, ignore_queue_rx) = channel::unbounded();
|
||||||
let prev_snapshot;
|
|
||||||
{
|
{
|
||||||
let snapshot = &mut self.state.lock().snapshot;
|
while let Some((parent_abs_path, ignore_stack)) = ignores_to_update.next() {
|
||||||
let abs_path = snapshot.abs_path.clone();
|
|
||||||
snapshot
|
|
||||||
.ignores_by_parent_abs_path
|
|
||||||
.retain(|parent_abs_path, (_, needs_update)| {
|
|
||||||
if let Ok(parent_path) = parent_abs_path.strip_prefix(abs_path.as_path()) {
|
|
||||||
if *needs_update {
|
|
||||||
*needs_update = false;
|
|
||||||
if snapshot.snapshot.entry_for_path(parent_path).is_some() {
|
|
||||||
ignores_to_update.push(parent_abs_path.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let ignore_path = parent_path.join(*GITIGNORE);
|
|
||||||
if snapshot.snapshot.entry_for_path(ignore_path).is_none() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
});
|
|
||||||
|
|
||||||
ignores_to_update.sort_unstable();
|
|
||||||
let mut ignores_to_update = ignores_to_update.into_iter().peekable();
|
|
||||||
while let Some(parent_abs_path) = ignores_to_update.next() {
|
|
||||||
while ignores_to_update
|
|
||||||
.peek()
|
|
||||||
.map_or(false, |p| p.starts_with(&parent_abs_path))
|
|
||||||
{
|
|
||||||
ignores_to_update.next().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
let ignore_stack = snapshot.ignore_stack_for_abs_path(&parent_abs_path, true);
|
|
||||||
ignore_queue_tx
|
ignore_queue_tx
|
||||||
.send_blocking(UpdateIgnoreStatusJob {
|
.send_blocking(UpdateIgnoreStatusJob {
|
||||||
abs_path: parent_abs_path,
|
abs_path: parent_abs_path,
|
||||||
|
@ -4668,8 +4704,6 @@ impl BackgroundScanner {
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_snapshot = snapshot.clone();
|
|
||||||
}
|
}
|
||||||
drop(ignore_queue_tx);
|
drop(ignore_queue_tx);
|
||||||
|
|
||||||
|
@ -4701,6 +4735,54 @@ impl BackgroundScanner {
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn update_ignore_statuses(&self, scan_job_tx: Sender<ScanJob>) {
|
||||||
|
let mut ignores_to_update = Vec::new();
|
||||||
|
let prev_snapshot = {
|
||||||
|
let snapshot = &mut self.state.lock().snapshot;
|
||||||
|
let abs_path = snapshot.abs_path.clone();
|
||||||
|
snapshot
|
||||||
|
.ignores_by_parent_abs_path
|
||||||
|
.retain(|parent_abs_path, (_, needs_update)| {
|
||||||
|
if let Ok(parent_path) = parent_abs_path.strip_prefix(abs_path.as_path()) {
|
||||||
|
if *needs_update {
|
||||||
|
*needs_update = false;
|
||||||
|
if snapshot.snapshot.entry_for_path(parent_path).is_some() {
|
||||||
|
ignores_to_update.push(parent_abs_path.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ignore_path = parent_path.join(*GITIGNORE);
|
||||||
|
if snapshot.snapshot.entry_for_path(ignore_path).is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
});
|
||||||
|
|
||||||
|
snapshot.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
ignores_to_update.sort_unstable();
|
||||||
|
let mut ignores_to_update = ignores_to_update.into_iter().peekable();
|
||||||
|
let ignores_to_update = std::iter::from_fn({
|
||||||
|
let prev_snapshot = prev_snapshot.clone();
|
||||||
|
move || {
|
||||||
|
let parent_abs_path = ignores_to_update.next()?;
|
||||||
|
while ignores_to_update
|
||||||
|
.peek()
|
||||||
|
.map_or(false, |p| p.starts_with(&parent_abs_path))
|
||||||
|
{
|
||||||
|
ignores_to_update.next().unwrap();
|
||||||
|
}
|
||||||
|
let ignore_stack = prev_snapshot.ignore_stack_for_abs_path(&parent_abs_path, true);
|
||||||
|
Some((parent_abs_path, ignore_stack))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.update_ignore_statuses_for_paths(scan_job_tx, prev_snapshot, ignores_to_update)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
async fn update_ignore_status(&self, job: UpdateIgnoreStatusJob, snapshot: &LocalSnapshot) {
|
async fn update_ignore_status(&self, job: UpdateIgnoreStatusJob, snapshot: &LocalSnapshot) {
|
||||||
log::trace!("update ignore status {:?}", job.abs_path);
|
log::trace!("update ignore status {:?}", job.abs_path);
|
||||||
|
|
||||||
|
@ -4765,6 +4847,9 @@ impl BackgroundScanner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !entries_by_path_edits.is_empty() {
|
||||||
|
dbg!(&entries_by_path_edits);
|
||||||
|
}
|
||||||
state
|
state
|
||||||
.snapshot
|
.snapshot
|
||||||
.entries_by_path
|
.entries_by_path
|
||||||
|
@ -4876,7 +4961,7 @@ async fn discover_ancestor_git_repo(
|
||||||
let mut ignores = HashMap::default();
|
let mut ignores = HashMap::default();
|
||||||
for (index, ancestor) in root_abs_path.as_path().ancestors().enumerate() {
|
for (index, ancestor) in root_abs_path.as_path().ancestors().enumerate() {
|
||||||
if index != 0 {
|
if index != 0 {
|
||||||
if Some(ancestor) == fs.home_dir().as_deref() {
|
if ancestor == paths::home_dir() {
|
||||||
// Unless $HOME is itself the worktree root, don't consider it as a
|
// Unless $HOME is itself the worktree root, don't consider it as a
|
||||||
// containing git repository---expensive and likely unwanted.
|
// containing git repository---expensive and likely unwanted.
|
||||||
break;
|
break;
|
||||||
|
@ -5597,3 +5682,11 @@ fn discover_git_paths(dot_git_abs_path: &Arc<Path>, fs: &dyn Fs) -> (Arc<Path>,
|
||||||
|
|
||||||
(repository_dir_abs_path, common_dir_abs_path)
|
(repository_dir_abs_path, common_dir_abs_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn global_gitignore_path() -> Option<Arc<Path>> {
|
||||||
|
if cfg!(test) {
|
||||||
|
Some(Path::new(path!("/home/zed/.config/git/ignore")).into())
|
||||||
|
} else {
|
||||||
|
gitconfig_excludes_path().map(Into::into)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue